Members no longer demoted after PayPal subscription suspended

If a member’s credit card has expired and they do not update it in PayPal, after three attempts to take the money, the PayPal subscription is suspended, s2Member is sent a recurring_payment_suspended_due_to_max_failed_payment IPN, and the member should be automatically downgraded.

However this is no longer happening, apparently because s2Member cannot identify the member which the payment failure IPN relates to. I believe this may be due to some recent PayPal changes with subscription IDs.

Below is an anonymised example of a final payment failure message from gateway-core-ipn.log

LOG ENTRY: Sun Jan 13th, 2019 @ precisely 3:08 pm UTC
PHP v5.6.39-0 :: WordPress v5.0.3 :: s2Member v170722 :: s2Member Pro v170722
Memory 31.76 MB :: Real Memory 32.52 MB :: Peak Memory 32.11 MB :: Real Peak Memory 32.52 MB
www.xxxxx.com/?s2member_paypal_notify=1
User-Agent: PayPal IPN ( https://www.paypal.com/ipn )
Array
(
    [payment_cycle] => Yearly
    [txn_type] => recurring_payment_suspended_due_to_max_failed_payment
    [last_name] => xxxxx
    [next_payment_date] => N/A
    [residence_country] => GB
    [initial_payment_amount] => 0.00
	[rp_invoice_id] => xxxxxxxxxxxxx~xxx.xxx.xxx.xxx
    [currency_code] => GBP
    [time_created] => 12:51:57 Jan 01, 2017 PST
    [verify_sign] => x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    [period_type] => Regular
    [payer_status] => verified
    [tax] => 0.00
    [payer_email] => xxxxxxxxxxxxxxx@xxxxxxxxxxxxxx.com
    [first_name] => xxxxx
    [receiver_email] => member@xxxxx.com
    [payer_id] => xxxxxxxxxxxxx
    [product_type] => 1
    [shipping] => 0.00
    [amount_per_cycle] => 80.00
    [profile_status] => Suspended
    [custom] => www.xxxxx.com
    [charset] => windows-1252
    [notify_version] => 3.9
    [amount] => 80.00
    [outstanding_balance] => 80.00
    [recurring_payment_id] => I-xxxxxxxxxxxx
    [product_name] => Member - RENEW
    [ipn_track_id] => xxnnnxnxnxnnn
    [s2member_log] => Array
        (
            [0] => IPN received on: Sun Jan 13, 2019 3:08:17 pm UTC
            [1] => s2Member POST vars verified through a POST back to PayPal.
            [2] => s2Member originating domain (`$_SERVER["HTTP_HOST"]`) validated.
            [3] => s2Member `txn_type` identified as ( `subscr_eot|recurring_payment_expired|recurring_payment_suspended_due_to_max_failed_payment` ) - or - `recurring_payment_profile_cancel` w/ `initial_payment_status` ( `failed` ).
            [4] => Sleeping for 15 seconds. Waiting for a possible ( `subscr_signup|subscr_modify|recurring_payment_profile_created` ).
            [5] => Awake. It's Sun Jan 13, 2019 3:08:32 pm UTC. s2Member `txn_type` identified as ( `subscr_eot|recurring_payment_expired|recurring_payment_suspended_due_to_max_failed_payment` ) - or - `recurring_payment_profile_cancel` w/ `initial_payment_status` ( `failed` ).
            [6] => Unable to (demote|delete) Member. Could not get the existing User ID from the DB. It's possible that it was ALREADY processed through another IPN, removed manually by a Site Administrator, or by s2Member's Auto-EOT Sys.
        )

    [subscr_gateway] => paypal
    [subscr_id] => I-xxxxxxxxxxxx
    [period1] => 0 D
    [period3] => 1 D
    [item_number] => 1
    [item_name] => Member - RENEW
    [subscr_baid] => I-xxxxxxxxxxxx
    [subscr_cid] => I-xxxxxxxxxxxx
    [ip] => 
    [currency] => 
    [currency_symbol] => $
)
1 Like

Following up on this - the root cause appears to be that s2Member is not using the [old_subscr_id] field that comes through with the first skipped payment IPN.

This was a relatively recent change by PayPal and has caught a lot of people out.

s2Member should update the Paid Subscr. ID field to the current [subscr_id] when it gets an IPN containing an [old_subscr_id], but it doesn’t. Old numbers are prefixed S-, new ones are prefixed I-.

@clavaque are you able to look into this? Below I’ve included an example IPN containing the [old_subscr_id] field. You will also note from my first message that PayPal do not include this [old_subscr_id] field on the final recurring_payment_suspended_due_to_max_failed_payment IPN. The net result is that if the [subscr_id] is not updated after the first skipped payment IPN, the final failed IPN will not demote the user, because s2Member can’t find them.

LOG ENTRY: Sun Jan 13th, 2019 @ precisely 3:16 pm UTC
PHP v5.6.39-0 :: WordPress v5.0.3 :: s2Member v170722 :: s2Member Pro v170722
Memory 31.44 MB :: Real Memory 32.52 MB :: Peak Memory 31.98 MB :: Real Peak Memory 32.52 MB
www.xxxxx.com/?s2member_paypal_notify=1
User-Agent: PayPal IPN ( https://www.paypal.com/ipn )
Array
(
    [txn_type] => subscr_failed
    [subscr_id] => I-xxxxxxxxxxxx
    [last_name] => xxxxx
    [option_selection1] => nnn
    [option_selection2] => xxx.xxx.xxx.xxx
    [residence_country] => GB
    [payment_gross] => 
    [mc_currency] => GBP
    [item_name] => Member - RENEW
    [business] => member@xxxxx.com
    [verify_sign] => x.xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    [payer_status] => verified
    [payer_email] => xxxxxxxxxxxxxxx@xxxxxxxxxxxxxx.com
    [first_name] => xxxxx
    [receiver_email] => member@xxxxx.com
    [option_name1] => Referencing Customer ID
    [payer_id] => nxxxxxxxxnnxx
    [invoice] => nxnxxnnnnnxn~xxx.xxx.xxx.xxx
    [option_name2] => Customer IP Address
    [retry_at] => 02:00:00 Jan 18, 2019 PST
    [item_number] => 3
    [mc_gross] => 80.00
    [custom] => www.xxxxx.com
    [old_subscr_id] => S-xxxxxxxxxxxxxxxxx
    [charset] => windows-1252
    [notify_version] => 3.9
    [ipn_track_id] => nnxnnnxnnnxnx
    [option_selection] => nnn
    [option_name] => Referencing Customer ID
    [s2member_log] => Array
        (
            [0] => IPN received on: Sun Jan 13, 2019 3:16:17 pm UTC
            [1] => s2Member POST vars verified through a POST back to PayPal.
            [2] => s2Member originating domain (`$_SERVER["HTTP_HOST"]`) validated.
            [3] => s2Member `txn_type` identified as ( `subscr_failed|recurring_payment_failed|recurring_payment_skipped` ).
            [4] => This `txn_type` does not require any action on the part of s2Member.
            [5] => s2Member does NOT respond to individual failed payments, only multiple consecutive failed payments.
            [6] => When multiple consecutive payments fail, a special IPN response will be triggered.
        )

    [subscr_gateway] => paypal
    [subscr_baid] => I-xxxxxxxxxxxx
    [subscr_cid] => I-xxxxxxxxxxxx
)
1 Like

Hi Richard!

Sorry I didn’t get to your post yersterday, I was travelling all day.

Thank you for the bringing my attention to this! I will take care of it as soon as possible. :slight_smile:

Hi Cristián,

That’s great news, thank you.

1 Like

Is anyone filing for compensation from PayPal for this unannounced change?!! we have had members stop paying and then NOT drop off our database and so still receive benefits… that we pay for…

Guys, I finally could get back to this. Have you kept having issues with the new subscr_id prefix PayPal changed to?

Here’s a hack I’d like you to try on your sites, to see if it’d take care of the issue. Krum and I have tried it ourselves, but don’t have installations with old subscriptions where we’d get notifications with the old ID’s. So if you could test it, that’d be wonderful.

Please create this file /wp-content/mu-plugins/s2-pp-subscr-id-fix.php and in it paste:

<?php
add_action('ws_plugin__s2member_before_paypal_notify', function ($vars = array()) {
   if (!empty($_REQUEST['old_subscr_id']) AND !empty($_REQUEST['subscr_id']))
      $_REQUEST['subscr_id'] = $_POST['subscr_id'] = $_REQUEST['old_subscr_id'];
});

Make sure there are no spaces or lines before the <?php, it has to be the very first thing in the file.

Please keep logging enabled. See if you can still reproduce the problem with the notifications not updating the user.

I look forward to your updates. Thanks!

Hi Cristián,

Many thanks for the fix, unfortunately I won’t be able to help test it, as we weren’t able to wait this long.

Once we realised the root cause, back in January, we requested from PayPal Technical Support a mapping file of old subscriber IDs to new subscriber IDs. That took them about 24 hous to produce and we used that to update our database, so the problem no longer affects us.

But this does worry me that if anything else broke with s2Member that we couldn’t fix ourselves somehow, we would either be waiting a very long time for an official fix because you are so stretched, or we would be forced to pay external consultants to implement hacky workarounds which may then end up being broken by future updates.

s2Member is a great piece of software but it badly needs the paid professional support option to be restored! I’m sure you agree, and I can tell that you take your job very seriously and would love to have more resources to be able to give better and faster help.

Thank you for putting this fix together anyway, it will definitely be of help to others.

1 Like

I’m glad you sorted it out by updating the database from the old to the new subscr IDs. Yes, that’s one way about it, but I can’t have site owners do that, although it’s PayPal’s whim that caused it. The dynamic approach I’m trying above would be good enough. Now I just need to confirm it.

I’m very sorry about the delay to post it, it’s been much longer than I wanted. The past months have been rough for, yes, for a number of reasons, but it’s much easier ahead. I’m also in the process of recruiting developers, and although it’s taking a while to find them, the whole back and forth, and none making the cut yet, I know I’ll find one or two good ones very soon.

I do plan to start charging a recurring payment for the new releases, maybe yearly, but haven’t felt it’s the right time yet.

1 Like

Oh no I agree you couldn’t ask people to do the database update themselves, the risk would be huge. (Although btw that is PayPal’s official recommendation…!) The only reason I did it that way is that I’m confident with SQL but not PHP. I could see it would be a straightforward fix in PHP if I was more familiar with the language, the solution you’ve posted looks good.

Glad to hear things are looking up. I don’t think everyone needs pro support, I guess it is down to the size of the site and the impact it has if things stop working. We would pay if there was an option because we need reliability, and because we want s2Member to be a viable commercial product.

1 Like