BUG: Wrong EOT for paypall fallback missing ipn_signup_vars cancellation

If a user has no IPN_signup_vars and cancels his subscription via the paypal button (not link) then the date s2member enters for EOT is 1 day into the future, instead of the end of the paid term. So I’m pretty sure this does not happen if it’s just the link and the user goes into his paypal profile to cancel. At least I haven’t had any complaints in this regard yet.

I don’t think this happens if the user cancels via following the link to paypal. In that case the date I think is correct.

I think this only applies to paypal - not sure about stripe. I don’t know what happens once the subscription actually fully runs out as the fallback option is less than one year old and with Stripe there is no date entered at all on cancellation with fallback ipn vars.

Actually the best behaviour would be to delete the subscription ID on cancellation and put in the EOT - otherwise it’s also impossible to show a field to the user so he can see how long his account is still active.

I think there really needs to be some check up of what actually happens concerning EOT when users without signup_vars cancel and harmonise it over all ways of cancellation. Right now it’s clearly somewhat broken.

I’m pretty sure this bug did not happen when cancelling a subscription on paypal website. This way the button instead of link/anchor mode is really broken for me as I have so many users with missing ipn_signup_vars.

I just went through a lot of older cancellations where I guess the user could have missing signup_vars and the date was always correct.

Thanks for the detailed report.

I found an issue in the PayPal Checkout output="button" cancellation flow. When the local API cancellation succeeded, s2Member was simulating a PayPal cancellation notification and the normal cancellation handler could end up calculating EOT from incomplete data when ipn_signup_vars were missing. In that case, the old fallback could result in an incorrect short EOT, such as about 1 day.

I have a dev build that changes the PayPal Checkout button cancellation flow so it first asks PayPal for the subscription details and uses PayPal’s next_billing_time as the local EOT source. If that safe EOT value cannot be found, s2Member does not cancel through the API and instead would fall back to sending the user to PayPal to manage/cancel the subscription there.

It also keeps the local cancellation tied to the logged-in user who clicked the button, instead of relying only on a subscription-ID lookup in the internal proxy notification.

s2member-dev-v260517.0405.zip (1.4 MB)

Could you test this dev build with a user that has a valid PayPal Checkout subscription but no ipn_signup_vars ?

Before testing, please clear any existing bad EOT value on the test user, otherwise s2Member may preserve the already-set EOT.

:slight_smile:

2 Likes

Brilliant idea! :bulb:

Answering here for both topics - as they are somewhat related. Thanks for looking into it.
Actually I would rather have it cancel both users - I’m gonna test it out. Usual reason for both users is - the user claims he cannot login - I search through emails/user search and cannot find the actual user he created (sometimes searching for subscription-id doesn’t yield the result you want - don’t ask me why - wordpress user search is really bad). - so I go on and create a second user and input subscription-id by hand.

There is however one rather big problem with this - the standard paypal checkout is really confusing once a user logs in - and users get confused about what it does - so I feel I have to give an explanation with screenshots beforehand - else I get too many people who don’t manage to cancel ending up in paypal complaints (many of my users are a bit elder). However I really don’t want to give that explanation beforehand if not needed.

Meaning if I would need some sort of s2if / s2get_!ipn_vars shortcode that makes it possible to only show this explanation to users without signup_vars

It’s a bit tough debugging this because it’s a bit random when users have or have not signup_vars (it happened for 2 longer periods for signups but I’m not sure from when to when this actually was), besides the case of manually creating users out of signup problems (another possibility user has problems receiving the email with signup link, maybe in spam, maybe blocked - I cannot bother too much sending question back and forward and faster just to create the user for him with a temporary password from wordpress backend).
So I guess I will have to go into the database for some user asking me to end his account, delete the ipn_signup_vars, backup wordpress databse, set a password for his account I know, use it to login and to cancel, then restore the wordpress database to make sure he gets his password back, and manually demote his account afterwards to actually simulate it. Before I just copied over the data into a test account so I can save the wordpress database reset (this was how I noticed the bug)

Yeah, I know what you mean.

The dev build should remove the need to show the PayPal instructions just because signup vars are missing. Missing signup vars alone should no longer force the PayPal-management fallback for PPCO button cancellation.

The fallback to PayPal management is now only for cases where s2Member cannot safely get the subscription details / next billing time from PayPal, or where the API cancellation itself fails.

About multiple users having the same subscription ID: I’m not changing that behavior in this dev build. That’s ambiguous/corrupted local data, and I don’t want to add a broader “demote every matching user” behavior until I’ve thought through the possible side effects. For this fix, the button-triggered cancellation stays tied to the logged-in user who clicked it.

But if you still want to show different instructions based on missing signup vars, with Advanced/PHP conditionals enabled, you can already do roughly:

[s2If php="!is_array(get_user_option('s2member_ipn_signup_vars', get_current_user_id()))"]
    PayPal cancellation explanation here.
[/s2If]

Please test the dev build with a user that has a valid PayPal Checkout subscription but is missing ipn_signup_vars, using the same steps you used to reproduce the original problem.

Before testing, please clear any existing bad EOT value on that test user, otherwise s2Member may preserve the already-set EOT.

:slight_smile:

Thanks, yeah now it seems to work with this version. I deleted some more fields in the database which many users are missing and it works.

However I would have one really big request - after confirming the s2member cancellation button - the page should auto reload.

Why? If you want to show the user the new status of his subscription - a reload is needed to fetch it.
The small “subscription cancelled” is hard to read - and actually also hard to modify in layout as it’s a special field. Yeah I know the button gets greyed out - but that may still confuse some users. I like to use s2if to show the user his EOT time then after cancelling.

I think for pro-form cancellations this is not needed as much - but would also be useful.

The only thing that still happens - s2member sends 3 of the following emails instead of a single one - I don’t mind but maybe useful for you.

(s2Member / API Notification Email) - Cancellation
emails.

email1:
(s2Member / API Notification Email) - Cancellation

subscr_id: I-E9BL9PR9HAWR
subscr_baid: I-E9BL9PR9HAWR
subscr_cid: I-E9BL9PR9HAWR
item_number: 1
item_name: PayPal Checkout Subscription
user_first_name: firstname
user_last_name: lastname
user_full_name: fullname
user_email: removed
user_login: removed
user_ip: removed
user_id: 28270
cv0: openmtbmap.org

email2:
(s2Member / API Notification Email) - Cancellation

subscr_id: I-E9BL9PR9HAWR
subscr_baid: I-E9BL9PR9HAWR
subscr_cid: I-E9BL9PR9HAWR
item_number: 1
item_name: FALLBACK IPN SIGNUP VARS
user_first_name: firstname
user_last_name: lastname
user_full_name: fullname
user_email: removed
user_login: removed
user_ip: removed
user_id: 28270
cv0: openmtbmap.org

email3.
(s2Member / API Notification Email) - Cancellation

subscr_id: I-E9BL9PR9HAWR
subscr_baid: I-E9BL9PR9HAWR
subscr_cid: I-E9BL9PR9HAWR
item_number: 1
item_name: First year access for €20, then €15 each year
(recurring_charge, for OpenMTBMap access)
user_first_name: firstname
user_last_name: lastname
user_full_name: fullname
user_email: removed
user_login: removed
user_ip: removed
user_id: 28270
cv0: openmtbmap.org