Stripe EOT does not demote

What would prevent Stripe from demoting a user when EOT is reached? This seems to be happening consistently where EOT does not bring demotion of the user account.

My shortcode looks like this:
[s2Member-Pro-Stripe-Form level=“1” ccaps=“hips_focus_general_level_august_16th” desc=“Hips Focus General Level August 16th Video - $14.00 for 48 hour access” cc=“USD” custom=“rivervalleyyoga.com” ta=“0” tp=“0” tt=“D” ra=“14.00” rp=“2” rt=“D” rr=“BN” coupon="" accept_coupons=“0” default_country_code=“US” captcha=“0” success="/video-classes/thank-you/" /]

I guess that s2Member is ignoring Stripe’s IPN with the information the user cancelled their recurring subscription.

I found out that it’s not acting up on the information after checking the logs, but I didn’t get a reply either: Stripe's IPN for Cancellation During Trial being Ignored

Hi Gerry.

Does the user profile get an EOT time set after buying the access? After that time is reached, what happens to that time in his profile, is it still there or not anymore?

Create a test user account, add an EOT time in the past, does it get the EOT behavior soon after?

What is your EOT configuration? WP admin > s2Member > Stripe Options > Auto EOT Behavior

Let me know how it goes. :slight_smile:
With logging enabled, what does your auto-eot-system.log file say? WP Admin > s2Member > Log Files

1 Like

I don’t have the log files turned on, but I do have the Stripe EOT behavior set to demote upon the end of term and clear our CCAPS. Yes, s2M does set the EOT after purchase. I’m getting mixed success with the EOT and CCAPS sometimes being cleared and demotion happening, and sometimes not. Perhaps the issue is with the WP-cron? These are also return purchases, not recurring subscriptions.

Thanks for the details, Gerry.

Okay, maybe the cron is just a bit behind… Could you try the hack suggested here? https://f.wpsharks.com/t/8362/2

Create this folder/file with that code in it: /wp-content/mu-plugins/s2-hacks.php

See also: https://s2member.com/kb-article/hacking-s2member-plugin-w-hooksfilters-for-wordpress/

I hope that helps. :slight_smile:

1 Like

A post was split to a new topic: Stripe level subscription downgrade

Hi Cristián, Thank you for pointing me in this direction. I have added the s2-hacks.php file with the code in the suggested location. After doing so, I loaded the URL s2member_auto_eot_system_via_cron=1 and the one account that should have expired but was not, did expire and was demoted… So, I’m not sure if adding the code or running the URL did force the cron to run. There is another account that should expire later today, so I guess I’ll see if it doe it automatically as expected. My question now is simply: does this hack now in place resolve the issue going forward without me having to take any further action? Thank you again!

I was disappointed to find that the user who should have been demoted overnight did not get demoted, so I must have missed something in what I’m supposed to do. I did add the s2-hacks.php file but I don’t understand if that is the whole solution.

Again today, I loaded the URL: /?s2member_auto_eot_system_via_cron=1 and THAT is what made the demotion happen.

Why is this not happening on its own? Where can I look to see if WP_CRON is running and get a log of what it’s doing?

Thanks for your help!

I have my crontab set up to curl that url every few minutes on my server. Maybe you need to do the same.

Hi Sim, thanks for the reply… but this site is in a shared hosting environment on GoDaddy.com… is there a WP plugin that will help me curl that URL perhaps? I guess I’m disappointed that s2M doesn’t actually do this… it’s an advertised functionality that EOT demotes the user.

It sounds like it’s working then. The issue seems to be that wp-cron had not fired until you loaded that URL. This is not under s2’s control, it’s a limitation in WP’s implementation.

wp-cron is not a real “cron” job, it doesn’t fire at the set time. When WP is loaded, wp-cron will check scheduled events and see which are behind the current time. https://developer.wordpress.org/plugins/cron/

If WP doesn’t get loaded, wp-cron doesn’t run. If nobody visits the site, or maybe if a cache is served instead of loading WP, wp-cron will be behind.

But if that user that should have been demoted, logs in, then the cron would have demoted him then, and the effect would still have been the intended one, I think.

A real cron job loading that URL, as Sim mentioned, would help keep things up-to-date, but it’s true that not every host makes it possible.

You could also try a cron-jobs online service, e.g. https://cron-job.org/en/

:slight_smile:

1 Like

I had the problem happen today, when I cancelled a subscription for a customer that was delinquent, but s2member ignored the webhook:

LOG ENTRY: Sat Jan 16th, 2021 @ precisely 1:08 pm UTC
PHP v7.4.13 :: WordPress v5.6 :: s2Member v201225 :: s2Member Pro v201225
Memory 6.09 MB :: Real Memory 2.00 MB :: Peak Memory 6.14 MB :: Real Peak Memory 2.00 MB
redactedurl?s2member_pro_stripe_notify=1
User-Agent: Stripe/1.0 (+https://stripe.com/docs/webhooks)
Array
(
    [event] => Stripe\Event Object
        (
            [id] => Redacted
            [object] => event
            [api_version] => 2020-08-27
            [created] => 1610802532
            [data] => Stripe\StripeObject Object
                (
                    [object] => Stripe\Subscription Object
                        (
                            [id] => Redacted
                            [object] => subscription
                            [application_fee_percent] => 
                            [billing_cycle_anchor] => 1608072674
                            [billing_thresholds] => 
                            [cancel_at] => 
                            [cancel_at_period_end] => 
                            [canceled_at] => 1610802532
                            [collection_method] => charge_automatically
                            [created] => 1605480674
                            [current_period_end] => 1613256674
                            [current_period_start] => 1610664674
                            [customer] => Redacted
                            [days_until_due] => 
                            [default_payment_method] => 
                            [default_source] => 
                            [default_tax_rates] => Array
                                (
                                )

                            [discount] => 
                            [ended_at] => 1610802532
                            [items] => Stripe\Collection Object
                                (
                                    [object] => list
                                    [data] => Array
                                        (
                                            [0] => Stripe\SubscriptionItem Object
                                                (
                                                    [id] => Redacted
                                                    [object] => subscription_item
                                                    [billing_thresholds] => 
                                                    [created] => 1605480675
                                                    [metadata] => Stripe\StripeObject Object
                                                        (
                                                        )

                                                    [plan] => Stripe\Plan Object
                                                        (
                                                            [id] => Redacted
                                                            [object] => plan
                                                            [active] => 1
                                                            [aggregate_usage] => 
                                                            [amount] => 600
                                                            [amount_decimal] => 600
                                                            [billing_scheme] => per_unit
                                                            [created] => 1605157061
                                                            [currency] => usd
                                                            [interval] => day
                                                            [interval_count] => 30
                                                            [livemode] => 1
                                                            [metadata] => Stripe\StripeObject Object
                                                                (
                                                                    [recurring] => true
                                                                    [recurring_times] => -1
                                                                )

                                                            [nickname] => 
                                                            [product] => Redacted
                                                            [tiers_mode] => 
                                                            [transform_usage] => 
                                                            [trial_period_days] => 30
                                                            [usage_type] => licensed
                                                        )

                                                    [price] => Stripe\StripeObject Object
                                                        (
                                                            [id] => Redacted
                                                            [object] => price
                                                            [active] => 1
                                                            [billing_scheme] => per_unit
                                                            [created] => 1605157061
                                                            [currency] => usd
                                                            [livemode] => 1
                                                            [lookup_key] => 
                                                            [metadata] => Stripe\StripeObject Object
                                                                (
                                                                    [recurring] => true
                                                                    [recurring_times] => -1
                                                                )

                                                            [nickname] => 
                                                            [product] => Redacted
                                                            [recurring] => Stripe\StripeObject Object
                                                                (
                                                                    [aggregate_usage] => 
                                                                    [interval] => day
                                                                    [interval_count] => 30
                                                                    [trial_period_days] => 30
                                                                    [usage_type] => licensed
                                                                )

                                                            [tiers_mode] => 
                                                            [transform_quantity] => 
                                                            [type] => recurring
                                                            [unit_amount] => 600
                                                            [unit_amount_decimal] => 600
                                                        )

                                                    [quantity] => 1
                                                    [subscription] => Redacted
                                                    [tax_rates] => Array
                                                        (
                                                        )

                                                )

                                        )

                                    [has_more] => 
                                    [total_count] => 1
                                    [url] => /v1/subscription_items?subscription=Redacted
                                )

                            [latest_invoice] => Redacted
                            [livemode] => 1
                            [metadata] => Stripe\StripeObject Object
                                (
                                    [tax_info] => {"trial_tax":"0.00","trial_tax_per":"0%","tax":"0.00","tax_per":"0%"}
                                )

                            [next_pending_invoice_item_invoice] => 
                            [pause_collection] => 
                            [pending_invoice_item_interval] => 
                            [pending_setup_intent] => 
                            [pending_update] => 
                            [plan] => Stripe\Plan Object
                                (
                                    [id] => Redacted
                                    [object] => plan
                                    [active] => 1
                                    [aggregate_usage] => 
                                    [amount] => 600
                                    [amount_decimal] => 600
                                    [billing_scheme] => per_unit
                                    [created] => 1605157061
                                    [currency] => usd
                                    [interval] => day
                                    [interval_count] => 30
                                    [livemode] => 1
                                    [metadata] => Stripe\StripeObject Object
                                        (
                                            [recurring] => true
                                            [recurring_times] => -1
                                        )

                                    [nickname] => 
                                    [product] => Redacted
                                    [tiers_mode] => 
                                    [transform_usage] => 
                                    [trial_period_days] => 30
                                    [usage_type] => licensed
                                )

                            [quantity] => 1
                            [schedule] => 
                            [start_date] => 1605480674
                            [status] => canceled
                            [transfer_data] => 
                            [trial_end] => 1608072674
                            [trial_start] => 1605480674
                        )

                )

            [livemode] => 1
            [pending_webhooks] => 1
            [request] => Stripe\StripeObject Object
                (
                    [id] => Redacted
                    [idempotency_key] => 
                )

            [type] => customer.subscription.deleted
        )

    [s2member_log] => Array
        (
            [0] => Ignoring this Webhook/IPN. The event does NOT require any action on the part of s2Member.
        )

)

As you can see in the example, the webhook was ignored by the plugin. It does not hapen on all cases, I cancelled 3 delinquent subscriptions, two were demoted, one (the one above) wasn’t. I hope it helps diagnosing what could be wrong…

s2 recodnized the event and tried to handle it, but if it was ignored it could be because s2 didn’t get the other things it needed…

case 'customer.subscription.deleted': // Customer subscription deletion.
  if(!empty($event->data->object)
  && ($stripe_subscription = $event->data->object) instanceof \Stripe\Subscription
  && ($ipn_signup_vars = c_ws_plugin__s2member_utils_users::get_user_ipn_signup_vars(0, $stripe_subscription->id))
)
{
  $processing = TRUE;

Could you check if those conditions would have been true in that particular case you mention? And if not, why weren’t they true, and should they have been? I would like to see if there’s a way to improve that logic…

Thanks!

1 Like

Hum… I don’t know how to confirm if any of those were missing. I demoted the user manually after I found what happened, so I’d have to wait for the next time it happens. Would I be able to find the information you need somewhere in the logs?

Are you using a different field than the sub id we can edit on wordpress’s user profile, meaning is get_user_ipn_signup_vars = Paid Subscr. ID (from the user profile)?

I ask that because when there’s a problem processing a new subscription I upgrade the user manually and I fill up the fields manually.

Cancelled another subscription today (overdue payment, as usual), s2Member ignored webhook.

                        [id] => sub_Redacted
                        [object] => subscription
                        [application_fee_percent] => 
                        [billing_cycle_anchor] => 1608665503
                        [billing_thresholds] => 
                        [cancel_at] => 
                        [cancel_at_period_end] =>
                        [canceled_at] => 1611346510
                        ... same stuff as usual ...
                        [quantity] => 1
                        [schedule] => 
                        [start_date] => 1606073503
                        [status] => canceled
                        [transfer_data] => 
                        [trial_end] => 1608665503
                        [trial_start] => 1606073503

I have a feeling that the problem may happen because Stripe doesn’t send a “cancel_at” number when the cancellation is immediate on Stripe. The plugin needs to set an immediate EOT when it happens, if it’s not doing that, because that’s Stripe behavior when we cancel a subscription for immediate effects.

When a subscription cancellation is scheduled for the future (when the subscriber is not overdue and just wants to stop it, for example) Stripe fills up those two variables and s2Member schedules the EOT accordingly, but that’s not the case when we cancel a subscription because payment is overdue.

Next time I face the same situation I’ll try to schedule the cancellation for sometime shortly in the future (if the system allows me to) and post here my results. It might take a while, since I don’t have too many subscribers using Stripe to pay :innocent:

1 Like

I see…

What does the s2Member log say for that webhook? Could you show it to me as you did the previous one?

Also, in that user’s wordpress profile, does he have a Paid Subscr ID or CID that match with his Stripe subscription ID or client ID?

Thanks :slight_smile:

1 Like

Oh, I didn’t repeat it because it said the same thing as the previous one :innocent:

Yes, the user had a subscriber ID that matched and it was also an automatically assigned one and not a manual one (those happen more often with PayPal, when the user subscribes and pays, but doesn’t open my page for any reason, then I add the information manually)

I see…

Going back to the conditionals I quoted in my other reply, if the subscription ID matched, then either the method that finds the user from it is not working, which I doubt, or the instanceof condition is false for some reason…

I’ll test a bit on my side, but you can test yourself too, since you’re having the problem there. One simple test would be to comment out the line with the instanceof condition. Seems pretty safe, since it’s highly unlikely that it gets to that point if it isn’t, it already matched the event type.

I look forward to your updates from this. Hopefully we can narrow it down to the culprit soon.

:slight_smile:

1 Like

I only saw your message now, sorry. I’ll find that line and comment it out to see what happens and let you know when I have to cancel another subscription with immediate effects. Now I understood what you meant, I understood the opposite when I read the message where you posted that line of code, sorry.

Not sure what happens but today I did an “immediate demotion” by cancelling a subscription on Stripe right away and the impact was instantaneous on s2member (as expected).

I didn’t try the change you suggested yet (thankfully). I have a feeling stripe is fiddling around with their system (you saw my other topic on the other issue around them creating “free trial” subscriptions against my will yesterday).

I’ll continue testing and keep you up to date. Sorry for my slowness.

1 Like