Last active
September 23, 2022 04:07
-
-
Save Tam/31aaa14b7ff274940efe40f701774c54 to your computer and use it in GitHub Desktop.
Add subscription pause support to Commerce Stripe
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace modules; | |
use Craft; | |
use craft\commerce\elements\Subscription; | |
use DateTime; | |
use Twig\Error\LoaderError; | |
use Twig\Error\SyntaxError; | |
use yii\base\Module; | |
/** | |
* Class PauseSubscription | |
* | |
* @author Ether Creative | |
* @package modules | |
*/ | |
class PauseSubscription extends Module | |
{ | |
public function init () | |
{ | |
parent::init(); | |
Craft::$app->getView()->hook( | |
'cp.commerce.subscriptions.edit.content', | |
[$this, 'hookCpCommerceSubscriptionsContentEdit'] | |
); | |
} | |
/** | |
* @param array $context | |
* | |
* @return string | |
* @throws LoaderError | |
* @throws SyntaxError | |
*/ | |
public function hookCpCommerceSubscriptionsContentEdit (array &$context) | |
{ | |
$view = Craft::$app->getView(); | |
$css = <<<CSS | |
.b-badge { | |
padding: 2px 6px; | |
font-size: 11px; | |
text-transform: uppercase; | |
line-height: 16px; | |
border-radius: 8px; | |
background-color: #596673; | |
color: #fff; | |
} | |
CSS; | |
$view->registerCss($css); | |
/** @var Subscription $subscription */ | |
$subscription = $context['subscription']; | |
if ($subscription->isCanceled || $subscription->isExpired) | |
return ''; | |
$paused = $subscription->getSubscriptionData()['pause_collection']; | |
$context['isPaused'] = !empty($paused); | |
$context['pausedUntil'] = null; | |
if ($context['isPaused'] && !empty($paused['resumes_at'])) | |
$context['pausedUntil'] = (new DateTime())->setTimestamp($paused['resumes_at']); | |
$markup = <<<TWIG | |
<div class="pane"> | |
<h2>Pause Subscription <span class="b-badge">Custom</span></h2> | |
<form method="POST"> | |
<input type="hidden" name="action" value="pause-subscription/subscriptions/{{ isPaused ? 'resume' : 'pause' }}"> | |
<input type="hidden" name="subscriptionUid" value="{{ subscription.uid|hash }}"> | |
{{ redirectInput(continueEditingUrl) }} | |
{{ csrfInput() }} | |
<div class="field"> | |
<div class="btngrp"> | |
<input type="submit" class="btn submit" value="{{ isPaused ? 'Resume' : 'Pause' }}"> | |
{% if isPaused %} | |
{% if pausedUntil %} | |
<strong> Paused until: {{ pausedUntil|date }}</strong> | |
{% else %} | |
<strong> Paused indefinitely</strong> | |
{% endif %} | |
{% else %} | |
for | |
<input class="text" type="text" name="for" placeholder="1 month" /> | |
{% endif %} | |
</div> | |
</div> | |
</form> | |
</div> | |
TWIG; | |
return $view->renderString($markup, $context); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace modules\controllers; | |
use Craft; | |
use craft\commerce\elements\Subscription; | |
use craft\commerce\Plugin as Commerce; | |
use craft\commerce\stripe\gateways\PaymentIntents; | |
use craft\commerce\stripe\Plugin as StripePlugin; | |
use craft\web\Controller; | |
use DateTime; | |
use Exception; | |
use Stripe\Stripe; | |
use yii\base\InvalidConfigException; | |
/** | |
* Class SubscriptionController | |
* | |
* @author Ether Creative | |
* @package modules\controllers | |
*/ | |
class SubscriptionsController extends Controller | |
{ | |
public function __construct ($id, $module, $config = []) | |
{ | |
parent::__construct($id, $module, $config); | |
Stripe::setApiKey(Craft::parseEnv(Commerce::getInstance()->getGateways()->getGatewayByHandle('CHANGE_ME')->apiKey)); | |
Stripe::setAppInfo(StripePlugin::getInstance()->name, StripePlugin::getInstance()->version, StripePlugin::getInstance()->documentationUrl); | |
Stripe::setApiVersion(PaymentIntents::STRIPE_API_VERSION); | |
} | |
public function actionPause () | |
{ | |
$request = Craft::$app->getRequest(); | |
$session = Craft::$app->getSession(); | |
$uid = $request->getValidatedBodyParam('subscriptionUid'); | |
$for = $request->getBodyParam('for'); | |
$sub = Subscription::find()->anyStatus()->uid($uid)->one(); | |
$data = $sub->getSubscriptionData(); | |
$resumesAt = null; | |
if (!empty($for)) | |
{ | |
$d = new DateTime(); | |
try { | |
$d = $d->modify($for); | |
} catch (Exception $e) { | |
$d = false; | |
Craft::error($e, 'B:SubscriptionPause'); | |
} | |
if ($d === false) | |
{ | |
$session->setError('Pause duration is invalid (see logs)!'); | |
return $this->redirectToPostedUrl(); | |
} | |
if ($d <= new DateTime()) | |
{ | |
$session->setError('Pause duration must result in the future!'); | |
return $this->redirectToPostedUrl(); | |
} | |
$resumesAt = $d->getTimestamp(); | |
} | |
\Stripe\Subscription::update($data['id'], [ | |
'pause_collection' => [ | |
'behavior' => 'void', | |
'resumes_at' => $resumesAt, | |
], | |
]); | |
self::_refresh($sub); | |
return $this->redirectToPostedUrl(); | |
} | |
public function actionResume () | |
{ | |
$uid = Craft::$app->getRequest()->getValidatedBodyParam('subscriptionUid'); | |
$sub = Subscription::find()->anyStatus()->uid($uid)->one(); | |
$data = $sub->getSubscriptionData(); | |
\Stripe\Subscription::update($data['id'], [ | |
'pause_collection' => '', | |
]); | |
self::_refresh($sub); | |
return $this->redirectToPostedUrl(); | |
} | |
/** | |
* Refresh the subscription data | |
* (Bit of a hack, kinda shitty that we can't do it directly. You can remove | |
* this if you're only viewing the subscription in the CP) | |
* | |
* @param Subscription $subscription | |
* | |
* @throws InvalidConfigException | |
*/ | |
private static function _refresh (Subscription $subscription) | |
{ | |
$subscription->getGateway()->getHasBillingIssues($subscription); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment