strangerstudios / pmpro-cancel-on-next-payment-date

Change membership cancellation in Paid Memberships Pro to set expiration for next payment date instead of cancelling immediately.
https://www.paidmembershipspro.com/add-ons/cancel-on-next-payment-date
8 stars 8 forks source link

Users have their membership extended when the initial payment fails in a PayPal subscription. #18

Closed ideadude closed 3 years ago

ideadude commented 3 years ago

Describe the bug Sometimes when using PayPal for recurring subscriptions, the subscription is set up, but the initial payment fails later. In these cases, PMPro and CONPD will process the cancellation and update the user's membership to expire on the "next payment date".

Instead, this membership should be cancelled immediately.

ideadude commented 3 years ago

This is what the IPN log looks like when this happens.

Logged On: 04/11/2021 12:14:54
Array
(
[payment_cycle] => Yearly
[txn_type] => recurring_payment_profile_cancel
[last_name] => LastName
[initial_payment_status] => Failed
[next_payment_date] => N/A
[residence_country] => DE
[initial_payment_amount] => 297.00
[currency_code] => USD
[time_created] => 09:17:43 Apr 11, 2021 PDT
[verify_sign] => xxxx
[period_type] => Regular
[payer_status] => verified
[tax] => 0.00
[payer_email] => payer@domain.com
[first_name] => FirstName
[receiver_email] => receiver@domain.com
[payer_id] => PAYERID
[product_type] => 1
[shipping] => 0.00
[amount_per_cycle] => 297.00
[profile_status] => Cancelled
[charset] => windows-1252
[notify_version] => 3.9
[amount] => 297.00
[outstanding_balance] => 0.00
[recurring_payment_id] => I-12345
[product_name] => Plus at Paid Memberships Pro
[ipn_track_id] => 12345
)

FP!
VERIFIED
Cancelled membership for user with id = 123. Subscription transaction id = I-12345.
ideadude commented 3 years ago

Here is where we detect the failed initial payment in the IPN handler and try to cancel.

https://github.com/strangerstudios/paid-memberships-pro/blob/dev/services/ipnhandler.php#L267-L275

ideadude commented 3 years ago

Since we're passing "error" as the $old_level_status (excuse the poorly named variable), we can detect that in our callback and in that case return false so that the membership is cancelled immediately.

Here: https://github.com/strangerstudios/pmpro-cancel-on-next-payment-date/blob/skip-cancel/pmpro-cancel-on-next-payment-date.php#L27

If $old_level_status is 'error', we are almost certainly cancelling.

We should probably refactor this function to also make the logic more clear. Return if $level != 0, etc.

The bonus of checking for 'error' status is that if a gateway cancels with status 'error', our code will support that. See related: https://github.com/strangerstudios/pmpro-cancel-on-next-payment-date/issues/9

sc0ttkclark commented 3 years ago

@ideadude There's some very similar code in https://github.com/strangerstudios/pmpro-auto-renewal-checkbox/blob/dev/pmpro-auto-renewal-checkbox.php#L327 which has the same issue, it mostly resembles the previous version from this branch that was changed away from the pmpro_before_change_membership_level and pmpro_after_change_membership_level actions.

sc0ttkclark commented 3 years ago

https://github.com/strangerstudios/pmpro-cancel-on-next-payment-date/pull/19 addresses the necessary work to resolve the error status handling.

https://github.com/strangerstudios/pmpro-cancel-on-next-payment-date/pull/20 includes code clean up and some refactoring to improve readability / wpdb prepare usage / etc