I had to update the stripe connection which meant rewriting how subscription processing is managed including cancellations.

So for the customer mcampbell_at_tnwebtech_dot_com (830.828) this is what I have as the status:
original subscription 24th
last renewed feb 24th
cancelled mar 6th
stripe charged them mar 6th AND marked it cancelled april 6th
it should have marked the 24th subscription to cancel on mar 24th

Clearly a bug in the new cancellation processor.

Task: https://github.com/Store-Locator-Plus/myslp_aws_ecs_kit/issues/94


Dev Notes

Customer: mc…tnwebtech… (830.828)

customer: mcampbell@tnwebtech.com

Current status according to Stripe: they have set their account to cancel on April 5th
Current subscription: *z8ku is deleted on Stripe now meaning it will not auto-renew

Please ensure that is what they want.

From the Stripe history:
The original subscription *9h4z
Started Oct 24 2023
Cancelled via SLP Dashboard on Mar 6th 2026 at 1:05AM (server time)
Was set to stop providing SLP maps on Mar 24th 2026
They then renewed (created the new subscription) Mar 6th at 1:08AM (server time)
This is set to expire on April 5th 2026

Yes, we have an issue with RENEW
If the prior subscription is still active (*9h4z in this case) it should set the new subscription (renewal) to start when that ends (Mar 24th 2026 06:21AM server time)
The bug is that is started immediately , thus the new 6th to 5th dates
That is OK for renewals that happen AFTER the maps are disabled (most users) but in this unique situation it needs to be addressed.

Stripe


Current Subscription *z8ku

Started and cancelled March 6th 2026

Mar 6, 2026, 1:08:53 AM EDT POST/v1/subscriptions

{
  "id": "sub_1T7rZBBvHKfBw2LGODU6z8ku",
  "object": "subscription",
...
  "cancel_at": null,
  "cancel_at_period_end": false,
  "canceled_at": null,
  "cancellation_details": {
    "comment": null,
    "feedback": null,
    "reason": null,
   },
  "collection_method": "charge_automatically",
  "created": 1772777333,
  "currency": "usd",
  "current_period_end": 1775455733, // April 5 2026 06:22:13
  "current_period_start": 1772777333,
  "customer": "cus_OsOnxeaYjgqPNu",
...
  "items": {
    "object": "list",
    "data": [
      {
        "id": "si_U63gr60piiTUmH",
        "object": "subscription_item",
        "billing_thresholds": null,
        "created": 1772777334,
        "current_period_end": 1775455733,
        "current_period_start": 1772777333,
        "discounts": [],
        "metadata": {},
        "plan": {
          "id": "Professional",
          "object": "plan",
          "active": true,
          "aggregate_usage": null,
          "amount": 3500,
          "amount_decimal": "3500",
          "billing_scheme": "per_unit",
          "created": 1500935159,
          "currency": "usd",
          "interval": "month",
          "interval_count": 1,
          "livemode": true,
          "metadata": {},
          "meter": null,
          "nickname": null,
          "product": "prod_BU6KhAFcwnXTef",
          "tiers_mode": null,
          "transform_usage": null,
          "trial_period_days": null,
          "usage_type": "licensed"
        },
        "price": {
          "id": "Professional",
          "object": "price",
          "active": true,
          "billing_scheme": "per_unit",
          "created": 1500935159,
          "currency": "usd",
          "custom_unit_amount": null,
          "livemode": true,
          "lookup_key": null,
          "metadata": {},
          "nickname": null,
          "product": "prod_BU6KhAFcwnXTef",
          "recurring": {
            "aggregate_usage": null,
            "interval": "month",
            "interval_count": 1,
            "meter": null,
            "trial_period_days": null,
            "usage_type": "licensed"
          },
          "tax_behavior": "unspecified",
          "tiers_mode": null,
          "transform_quantity": null,
          "type": "recurring",
          "unit_amount": 3500,
          "unit_amount_decimal": "3500"
        },
        "quantity": 1,
        "subscription": "sub_1T7rZBBvHKfBw2LGODU6z8ku",
        "tax_rates": []
      }
    ],
...
  },
...
  "trial_settings": {
    "end_behavior": {
      "missing_payment_method": "create_invoice"
    }
  },
  "trial_start": null
}

Mar 6, 2026, 1:09:11 AM EDT POST /v1/subscriptions/sub_1T7rZBBvHKfBw2LGODU6z8ku

{
  "id": "sub_1T7rZBBvHKfBw2LGODU6z8ku",
  "object": "subscription",
...
  "cancel_at": 1775455733,
  "cancel_at_period_end": true,
  "canceled_at": 1772777351,
  "cancellation_details": {
    "comment": null,
    "feedback": null,
    "reason": "cancellation_requested"
  },
  "collection_method": "charge_automatically",
  "created": 1772777333,
  "currency": "usd",
  "current_period_end": 1775455733,
  "current_period_start": 1772777333,
  "customer": "cus_OsOnxeaYjgqPNu",
...
}

Mar 6, 2026, 1:09:12 AM EDT DELETE/v1/subscriptions/sub_1T7rZBBvHKfBw2LGODU6z8ku


Original Subscription: *h4z

Started: 2023-10-24
Ended: 2026-03-06 01:05AM

Mar 6, 2026, 1:05:04 AM EDT POST/v1/subscriptions/sub_1O4dzSBvHKfBw2LGsKZp9h4z

{
  "id": "sub_1O4dzSBvHKfBw2LGsKZp9h4z",
  "object": "subscription",
  "application": null,
  "application_fee_percent": null,
  "automatic_tax": {
    "disabled_reason": null,
    "enabled": false,
    "liability": null
  },
  "billing_cycle_anchor": 1698128482,
  "billing_cycle_anchor_config": null,
  "billing_mode": {
    "flexible": null,
    "type": "classic"
  },
  "billing_thresholds": null,
  "cancel_at": 1774333282, // Mar 24 2026 06:21:22 AM (correct)
  "cancel_at_period_end": true,
  "canceled_at": 1772777104, // Mar 6 2026 01:05:04 AM
  "cancellation_details": {
    "comment": null,
    "feedback": null,
    "reason": "cancellation_requested"
  },
  "collection_method": "charge_automatically",
  "created": 1698128482,
  "currency": "usd",
  "current_period_end": 1774333282, // Mar 24 2026 06:21:22 AM (correct)
  "current_period_start": 1771914082, // February 23 2026 11:21:22 PM
  "customer": "cus_OsOnxeaYjgqPNu",
  "customer_account": null,
  "days_until_due": null,
  "default_payment_method": null,
  "default_source": null,
  "default_tax_rates": [],
  "description": null,
  "discount": null,
  "discounts": [],
  "ended_at": null,
  "invoice_settings": {
    "account_tax_ids": null,
    "issuer": {
      "type": "self"
    }
  },
  "items": {
    "object": "list",
    "data": [
      {
        "id": "si_OsOnhVkp9iBCCb",
        "object": "subscription_item",
        "billing_thresholds": null,
        "created": 1698128483,
        "current_period_end": 1774333282,
        "current_period_start": 1771914082,
        "discounts": [],
        "metadata": {},
        "plan": {
          "id": "Professional",
          "object": "plan",
          "active": true,
          "aggregate_usage": null,
          "amount": 3500,
          "amount_decimal": "3500",
          "billing_scheme": "per_unit",
          "created": 1500935159,
          "currency": "usd",
          "interval": "month",
          "interval_count": 1,
          "livemode": true,
          "metadata": {},
          "meter": null,
          "nickname": null,
          "product": "prod_BU6KhAFcwnXTef",
          "tiers_mode": null,
          "transform_usage": null,
          "trial_period_days": null,
          "usage_type": "licensed"
        },
        "price": {
          "id": "Professional",
          "object": "price",
          "active": true,
          "billing_scheme": "per_unit",
          "created": 1500935159,
          "currency": "usd",
          "custom_unit_amount": null,
          "livemode": true,
          "lookup_key": null,
          "metadata": {},
          "nickname": null,
          "product": "prod_BU6KhAFcwnXTef",
          "recurring": {
            "aggregate_usage": null,
            "interval": "month",
            "interval_count": 1,
            "meter": null,
            "trial_period_days": null,
            "usage_type": "licensed"
          },
          "tax_behavior": "unspecified",
          "tiers_mode": null,
          "transform_quantity": null,
          "type": "recurring",
          "unit_amount": 3500,
          "unit_amount_decimal": "3500"
        },
        "quantity": 1,
        "subscription": "sub_1O4dzSBvHKfBw2LGsKZp9h4z",
        "tax_rates": []
      }
    ],
    "has_more": false,
    "total_count": 1,
    "url": "/v1/subscription_items?subscription=sub_1O4dzSBvHKfBw2LGsKZp9h4z"
  },
  "latest_invoice": "in_1T4EzzBvHKfBw2LGXjuYItOu",
  "livemode": true,
  "metadata": {},
  "next_pending_invoice_item_invoice": null,
  "on_behalf_of": null,
  "pause_collection": null,
  "payment_settings": {
    "payment_method_options": null,
    "payment_method_types": null,
    "save_default_payment_method": null
  },
  "pending_invoice_item_interval": null,
  "pending_setup_intent": null,
  "pending_update": null,
  "plan": {
    "id": "Professional",
    "object": "plan",
    "active": true,
    "aggregate_usage": null,
    "amount": 3500,
    "amount_decimal": "3500",
    "billing_scheme": "per_unit",
    "created": 1500935159,
    "currency": "usd",
    "interval": "month",
    "interval_count": 1,
    "livemode": true,
    "metadata": {},
    "meter": null,
    "nickname": null,
    "product": "prod_BU6KhAFcwnXTef",
    "tiers_mode": null,
    "transform_usage": null,
    "trial_period_days": null,
    "usage_type": "licensed"
  },
  "quantity": 1,
  "schedule": null,
  "start_date": 1698128482,
  "status": "active",
  "test_clock": null,
  "transfer_data": null,
  "trial_end": null,
  "trial_settings": {
    "end_behavior": {
      "missing_payment_method": "create_invoice"
    }
  },
  "trial_start": null
}

Mar 6, 2026, 1:05:05 AM EDT DELETE/v1/subscriptions/sub_1O4dzSBvHKfBw2LGsKZp9h4z


SLP SaaS

Currently on Professional Plan
Expires 2026-05-21 06:08:53
Cancelled 2026-03-06 06:09:11

Current Stripe subscription: sub_1T7rZBBvHKfBw2LGODU6z8ku


Stripe Notes

Billing mode

Currently using Classic billing mode.

Flexible Recommended: Provides accurate and predictable billing behavior and new capabilities. To access these improvements, which are only available in flexible billing mode, you must create new subscriptions with flexible billing mode or migrate your existing subscriptions.

*Classic: Uses the existing Stripe subscription behavior. This setting is maintained for backward compatibility with older integrations.

AI Resolution Assistance

Prompt

@Amelia -
In the MySLP Payments module (WordPress/wp-content/plugins/myslp-payments) there is an issue related to renewing cancelled subscriptions.

__
Make a note of this as general knowledge about the Store Locator Plus Saas Application:
- local (https://local.storelocatorplus.com) and staging (https://staging.storelocatorplus.com) servers may be using outdated data sets
- local and staging servers employ the Stripe TEST environment and related keys 
- the production server uses live keys
- NEVER run tests against live Stripe customer data using live keys even on the staging or local servers

__

The following scenario is a real-world situation which played out on the production version of the SaaS application.   

We have an issue with RENEW subscription.
- If the prior subscription is still active (sub_1O4dzSBvHKfBw2LGsKZp9h4z in this case) it should set the new subscription (sub_1T7rZBBvHKfBw2LGODU6z8ku) to start when the still-active subscription ends (Mar 24th 2026 06:21AM server time).
- The bug is that the new subscription started immediately setting a March 6th start date when an April 5th end date.
- The new subscription should have started on March 24th 2026 at 6:21AM.
- If the  prior subscription is past the end (cancel_at) date, only then should the renewal start immediately.  That was not the case in this situation.


Meta data about the customer and their interaction with the application:

customer: mcampbell@tnwebtech.com

Current status according to Stripe: they have set their account to cancel on April 5th
Current subscription: *z8ku is deleted on Stripe now meaning it will not auto-renew

Please ensure that is what they want.

From the Stripe history:
The original subscription *9h4z
Started Oct 24 2023
Cancelled via SLP Dashboard on Mar 6th 2026 at 1:05AM (server time)
Was set to stop providing SLP maps on Mar 24th 2026
They then renewed (created the new subscription) Mar 6th at 1:08AM (server time)
This is set to expire on April 5th 2026

AI Fix

in \stripe\MySLP_Stripe_Payments::renew_subscription add the trial_end argument.


		// If the old subscription still has remaining paid time, defer the new
		// subscription so it starts when the old period ends.
		$prior_period_end = $this->subscription->current_period_end ?? null;
		if ( $prior_period_end && $prior_period_end > time() ) {
			$args['trial_end'] = $prior_period_end;
		}

		try {
			$this->subscription    = Subscription::create( $args );

E2E Testing

Write a new E2E Test Specification "subscription_renewals".

The first test in the specification needs to test "Can renew a subscription before it has expired".
This is a corner case with some specific requirements.
- Login as a user with a current active subscription
- Go to My Profile and look for the current subscription ID, remember this value
- Go to My Profile and cancel the subscription
-- The current Stripe subscription ID should be posted and marked in Stripe as canceled
-- The current subscription should have a cancellation date at the end of the current period
- Go to My Profile and renew the subscription
-- This should create a new Stripe subscription ID
-- The new Stripe subscription ID should start when the current period ends
-- The new Stripe subscription should NOT start at the date/time of the renewal
-- The new Stripe subscription should be set to renew in a month (current period ends a month later)



Leave a Reply