From d3250f2c5936ba7de128ef7a5592ae3c0757c74f Mon Sep 17 00:00:00 2001
From: Matthew Somerville
Date: Tue, 11 Jun 2024 17:20:25 +0100
Subject: [PATCH] Improve plan downgrade behaviour.
Use the new Subscription Schedules so that downgrade will only apply
from the next billing period.
---
classes/Subscription.php | 93 ++++++++++++++-----
.../html/api/subscription_detail.php | 4 +
2 files changed, 72 insertions(+), 25 deletions(-)
diff --git a/classes/Subscription.php b/classes/Subscription.php
index 8d428163da..e18b6c020b 100644
--- a/classes/Subscription.php
+++ b/classes/Subscription.php
@@ -12,6 +12,7 @@ class Subscription {
public $has_payment_data = false;
private static $plans = ['twfy-1k', 'twfy-5k', 'twfy-10k', 'twfy-0k'];
+ private static $prices = [2000, 5000, 10000, 30000];
public function __construct($arg) {
# User ID
@@ -62,6 +63,7 @@ public function __construct($arg) {
'customer.default_source',
'customer.invoice_settings.default_payment_method',
'latest_invoice.payment_intent',
+ 'schedule.phases.items.plan',
],
]);
} catch (\Stripe\Exception\InvalidRequestException $e) {
@@ -98,33 +100,74 @@ private function update_subscription($form_data) {
$this->update_payment_method($form_data['payment_method']);
}
- # Update Stripe subscription
- $args = [
- 'payment_behavior' => 'allow_incomplete',
- 'plan' => $form_data['plan'],
- 'metadata' => $form_data['metadata'],
- 'cancel_at_period_end' => false, # Needed in Stripe 2018-02-28
- ];
- if ($form_data['coupon']) {
- $args['coupon'] = $form_data['coupon'];
- } elseif ($this->stripe->discount) {
- $args['coupon'] = '';
+ foreach ($this::$plans as $i => $plan) {
+ if ($plan == $form_data['plan']) {
+ $new_price = $this::$prices[$i];
+ if ($form_data['coupon'] == 'charitable100') {
+ $new_price = 0;
+ } elseif ($form_data['coupon'] == 'charitable50') {
+ $new_price /= 2;
+ }
+ }
+ if ($plan == $this->stripe->plan->id) {
+ $old_price = $this::$prices[$i];
+ if ($this->stripe->discount && ($coupon = $this->stripe->discount->coupon)) {
+ if ($coupon->percent_off == 100) {
+ $old_price = 0;
+ } elseif ($coupon->percent_off == 50) {
+ $old_price /= 2;
+ }
+ }
+ }
}
- \Stripe\Subscription::update($this->stripe->id, $args);
- # Attempt immediate payment on the upgrade
- try {
- $invoice = \Stripe\Invoice::create([
- 'customer' => $this->stripe->customer,
- 'subscription' => $this->stripe,
- 'tax_rates': [STRIPE_TAX_RATE],
- ]);
- $invoice->finalizeInvoice();
- $invoice->pay();
- } catch (\Stripe\Exception\InvalidRequestException $e) {
- # No invoice created if nothing to pay
- } catch (\Stripe\Exception\CardException $e) {
- # A source may still require 3DS... Stripe will have sent an email :-/
+ if ($old_price >= $new_price) {
+ if ($this->stripe->schedule) {
+ \Stripe\SubscriptionSchedule::release($this->stripe->schedule);
+ }
+ $schedule = \Stripe\SubscriptionSchedule::create(['from_subscription' => $this->stripe->id]);
+ $phases = [
+ {
+ 'items' => [['price' => $schedule->phases[0]->items[0]->price]],
+ 'start_date' => $schedule->phases[0]->start_date,
+ 'end_date' => $schedule->phases[0]->end_date,
+ 'proration_behavior' => 'none',
+ 'default_tax_rates' => [STRIPE_TAX_RATE],
+ },
+ {
+ 'items' => [['price' => $form_data['plan']]],
+ 'iterations' => 1,
+ 'metadata' => $form_data['metadata'],
+ 'proration_behavior' => 'none',
+ 'default_tax_rates' => [STRIPE_TAX_RATE],
+ },
+ ];
+ if ($schedule->phases[0]->discounts && $schedule->phases[0]->discounts[0]->coupon) {
+ $phases[0]['discounts'] = [['coupon' => $schedule->phases[0]->discounts[0]->coupon]];
+ }
+ if ($form_data['coupon']) {
+ $phases[1]['coupon'] = $form_data['coupon'];
+ }
+ \Stripe\SubscriptionSchedule::update($schedule->id, ['phases' => $phases]);
+ }
+
+ if ($old_price < $new_price) {
+ $args = [
+ 'payment_behavior' => 'allow_incomplete',
+ 'plan' => $form_data['plan'],
+ 'metadata' => $form_data['metadata'],
+ 'cancel_at_period_end' => false, # Needed in Stripe 2018-02-28
+ 'proration_behavior': 'always_invoice',
+ ];
+ if ($form_data['coupon']) {
+ $args['coupon'] = $form_data['coupon'];
+ } elseif ($this->stripe->discount) {
+ $args['coupon'] = '';
+ }
+ if ($this->stripe->schedule) {
+ stripe.SubscriptionSchedule.release(self.object.schedule)
+ }
+ \Stripe\Subscription::update($this->stripe->id, $args);
}
}
diff --git a/www/includes/easyparliament/templates/html/api/subscription_detail.php b/www/includes/easyparliament/templates/html/api/subscription_detail.php
index bdbe9e22be..a0f0faf22f 100644
--- a/www/includes/easyparliament/templates/html/api/subscription_detail.php
+++ b/www/includes/easyparliament/templates/html/api/subscription_detail.php
@@ -40,6 +40,10 @@
+ stripe->schedule->phases[1] && $subscription->stripe->schedule->phases[1]->items[0]->plan->nickname != $subscription->stripe->plan->nickname ?>
+ You are switching to stripe->schedule->phases[1]->items[0]->plan->nickname ?> at the end of your current period.
+
+
stripe->discount && $subscription->stripe->discount->end) { ?>
Your discount will expire on = $subscription->stripe->discount->end ?>.