I wanted to have a way to let my users know that they have had a FAILED payment on their recurring paypal subscription. This was my solution. This addon does NOT change the functionality of how amember currently handles a failed payment. All it does is: Add a blurb in the Admin->User->Payments & Subscriptions (similar to the CANCELLED tag) Add a blurb in the member's area under payment history for the payment that actually failed. Along with the member's area blurb (#2 above) will be a link called "Resolve Failed Payment", which will point to an html document that you define in the code below. For me, I just make one document called FailedPayment.html and explain the situation and what the user must do to resolve it (typically either wait or cancel/fix/resubscribe.) Anyway, this is very unobtrusive code and really only provides a line of additional customer support more than actual script functionality. However, I think anyone that uses recurring paypal_r will find it useful. Amadeus --------------------------------- In /plugins/payment/paypal_r/paypal_r.inc.php: REPLACE: Code: case 'subscr_eot': case 'subscr_failed': $payment_id = $this->find_last_payment_id($vars['subscr_id'], $vars['invoice']); if (!$payment_id) $this->postback_error(_PLUG_PAY_PAYPALR_ERROR11); $p = $db->get_payment($payment_id); $new_expire = date('Y-m-d', time() - 3600 * 24 ); //yesterday date if ($p['expire_date'] && ($new_expire < $p['expire_date'])) $p['expire_date'] = $new_expire; $p['data'][] = $vars; $db->update_payment($payment_id, $p); break; With: Code: case 'subscr_failed': $failed = 1; case 'subscr_eot': $payment_id = $this->find_last_payment_id($vars['subscr_id'], $vars['invoice']); if (!$payment_id) $this->postback_error(_PLUG_PAY_PAYPALR_ERROR11); $p = $db->get_payment($payment_id); $new_expire = date('Y-m-d', time() - 3600 * 24 ); //yesterday date if ($p['expire_date'] && ($new_expire < $p['expire_date'])) $p['expire_date'] = $new_expire; $p['data'][] = $vars; if ($failed) { $p['data']['FAILED'] = 1; $p['data']['FAILED_AT'] = strftime($config['time_format'], time()); $p['data']['failed_url'] = "http://www.yourdomain.com/FailedPayment.html"; } $db->update_payment($payment_id, $p); break; NOTE: Replace ""http://www.yourdomain.com/FailedPayment.html" (in the code above) with the URL to the document you wish people to be directed to in order to resolve failed payments. In /templates/admin/user_payment.html: AFTER: Code: {if $p.data.CANCELLED} <table style='font-size: 8pt;' bgcolor=#e0e0e0> <tr><th align=right><b>CANCELLED</b> </th><td> {$p.data.CANCELLED_AT|escape}</td></tr> </table> <br /><br /> {/if} ADD: Code: {if $p.data.FAILED} <table style='font-size: 8pt;' bgcolor=#e0e0e0> <tr><th align=right><b>FAILED</b> </th><td> {$p.data.FAILED_AT|escape}</td></tr> </table> <br /><br /> {/if} In /templates/admin/payments.html: AFTER: Code: {if $p.data.CANCELLED}<br /><font color=red>CANCELLED</font>{/if} ADD: Code: {if $p.data.FAILED}<br /><font color=red>FAILED PAYMENT</font>{/if} In /templates/admin/user_payments.html: AFTER: Code: {if $p.data.CANCELLED}<br /><font color=red>CANCELLED</font>{/if} ADD: Code: {if $p.data.FAILED}<br /><font color=red>FAILED PAYMENT</font>{/if} In /templates/member.html AFTER: Code: {if $p.data.CANCELLED}<br /><div class="small" style="font-color: red; font-weight: bold;">#_TPL_MEMBER_CANCELLED#</div> {elseif $p.cancel_url}<br /><a href="{$p.cancel_url}" target=top onclick="return confirm('#_TPL_MEMBER_CANCEL_SUBSCR#')">#_TPL_MEMBER_CANCEL#</a> {/if} ADD: Code: {if $p.data.FAILED}<br /><div class="small" style="font-color: red; font-weight: bold;"><font color=red>PAYMENT FAILED</font></div> <br /><a href="{$p.data.failed_url}" target=top">Resolve Failed Payment</a> {/if}
Hmmm...I hope that it is ok to post code here on the forums. I thought I saw someone else posting another addon; however, I got to thinking after I posted it that perhaps it might not be allowed. I think the templates are fair game; however, perhaps the one php snippet might not be acceptable. Administrators feel free to delete if this is out-of-line with my apologies. I only thought I'd give a little something back after asking so many questions the past few days ..heh.
Awesome! Thanks for the contribution. And I don't think Alex will mind some random code being posted up here, as the aMember itself is so big that it really doesn't make a difference if you "share" some of the code here for free...
Here is a little more tweaking for those that are interested: In the code above that I had you add in paypal_r.inc.php, replace this line: Code: $p['data']['failed_url'] = "http://www.yourdomain.com/FailedPayment.html"; With this line: Code: $p['data']['failed_url'] = "http://www.yourdomain.com/FailedPayment.php?cancel_url=https://www.paypal.com/cgi-bin/webscr?cmd=_subscr-find&alias=USER%40DOMAIN.COM"; (USER%40DOMAIN.COM is the email address that people are paying to on paypal. ..an example might be uberness%40amember.com) Once you've done that ..then you can put something like this in your FailedPayment.php file... Code: <p> 1. First, you must cancel your current subscription. <a href= <?php if (isset($_GET['cancel_url'])) $cancel_url = $_GET['cancel_url']; else $cancel_url = "http://www.paypal.com"; print "\"$cancel_url\""; ?> target="_blank">Click here</a> to visit paypal and cancel you current subscription. After you have cancelled that subscription, you can close the additional browser window and come back to this page in order to continue on to step 2.</p> After that, I tell the user to FIX the problem that causes the failure, then I give them a link to the member page to create a new subscription. I'm thinking it's really the only sane way to deal with a failed recurring payment on paypal without forcing the user to wait 3 days for the automatic rebill.
This is awesome, any chance it can be rolled into the main amember distribution? There are a bunch of changes to the files, and I'd rather not have to deal with checking the changes each upgrade.
Am revisiting this as I use Paypal a lot. This is good code, I'm really interested in having it integrated in amember. How should I go about requesting this?
I just wanted to be clear that I relinquish all copyrights on my code in this thread (in hopes that Alex will add it, or something similar, to the standard aMember distribution.)