Page 1 of 1

Authorize.net Automatic EOT behavior

PostPosted: July 19th, 2011, 5:43 pm
by nciske
I'm trying to determine how to get s2member to allow a user to cancel recurring billing but still have their account active for the paid for period. Some of the documentation seems to say this is the default, but it's not happening on my site.

Right now, when a user cancels, their account is downgraded to level 0 ... but they may have several months left on their paid subscription.

Some snippets from the settings screens:

Authorize.Net® EOT Behavior ( required, please choose )
EOT = End Of Term. By default, s2Member will demote a paid Member to a Free Subscriber whenever their Subscription term has ended ( i.e. expired ) or is cancelled.

Authorize.Net® Billing Cancellation Form
Cancellation Process* Very simple. A Member clicks a link to a Post/Page that contains a Cancellation Form you've generated. The Member clicks the Submit button to confirm the cancellation. s2Member is notified silently behind-the-scene, and will immediately cancel all future billing. s2Member will later terminate their account access, at the correct point in time. This works in conjunction with the s2Member Auto-EOT System. For further details, see: s2Member -> Authorize.Net® Options -> EOT Behavior.

These two don't seem to agree as to how cancellations are handled... my customers are getting downgraded when they cancel, instead of an EOT being set for the end of their subscription.

So how does a member cancel recurring billing without canceling their account outright?

Re: Authorize.net Automatic EOT behavior

PostPosted: July 20th, 2011, 2:16 pm
by Cristián Lávaque
If the person is paying monthly, say every 1st, and they cancel the 15th of a paid month, then the EOT time should be set for the 30th. Could you give an example of what's happening to your user?

Could you show me your shortcode for the form they're subscribing with?

Also, please post the log entries related to this. You need to have logging enabled when these things happen for them to be logged WP Admin -> s2Member -> Auth.Net Options -> Account Details -> Enable Logging Routines. The logs can be found via FTP here /wp-content/plugins/s2member-logs/.

Re: Authorize.net Automatic EOT behavior

PostPosted: July 20th, 2011, 3:34 pm
by nciske
The sites uses 3 month and 12 month subscriptions.

This user signed up originally on March 29th 2011. The subscription auto-renewed on June 28th 2011.

On July 14th, the user canceled their account and was demoted to Level 0:
Demoted by s2Member: Thu Jul 14, 2011 10:56 pm UTC


Shortcode on the signup form:
Code: Select all
[s2Member-Pro-AuthNet-Form level="1" ccaps="+ab,cd" desc="$XX USD / Quarterly ( auto-renewing charge, for ongoing access )" cc="USD" custom="sitename.com" ta="0" tp="0" tt="D" ra="'XX'" rp="3" rt="M" rr="1" accept="visa,mastercard,discover" coupon="" accept_coupons="1" default_country_code="US" captcha="0" /]


Shortcode on the cancel billing page:
Code: Select all
[s2Member-Pro-AuthNet-Form cancel="1" desc="" captcha="0" /]


I am seeing this error in the authnet-ipn.log for each transaction:

Code: Select all
array (
  's2member_log' =>
  array (
    0 => 'Unable to verify POST vars. This is most likely related to an invalid Authorize.Net® configuration. Please check: s2Member -> Authorize.Net® Options.',
    1 => 'If you\'re absolutely SURE that your Authorize.Net® configuration is valid, you may want to run some tests on your server, just to be sure $_POST variables are populated, and that your server is able to connect to Authorize.Net® over an HTTPS connection.',
    2 => 's2Member uses the WP_Http class for remote connections; which will try to use cURL first, and then fall back on the FOPEN method when cURL is not available. On a Windows® server, you may have to disable your cURL extension. Instead, set allow_url_fopen = yes in your php.ini file. The cURL extension (usually) does NOT support SSL connections on a Windows® server.',


All the entries for that subscription in authnet-arb-ipn.log say:

Code: Select all
array (
  'response_reason_code' => 'I00001',
  'response_code' => 'I00001',
  'response_reason_text' => 'Successful.',
  'response_text' => 'Successful.',
  'subscription_status' => 'active',
  'arb_ipn_signup_vars' =>

...

's2member_log' =>
  array (
    0 => 'Ignoring this ARB/Status (active). It does NOT require any action on the part of s2Member.',
  ),
)


The last 2 entries in authnet-api.log say:

Code: Select all
libraryinsider.com/library-locator/cancel-recurring-billing/
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;)
-------- Input vars: ( Thu Jul 14, 2011 10:53:48 pm UTC ) --------
array (
  'x_method' => 'status',
  'x_subscription_id' => '9...2',
  'x_login' => 'xxxxxxx',
  'x_tran_key' => 'xxxxxxx',
  'x_invoice_num' => false,
  'x_description' => '',
)
-------- Output string/vars: ( Thu Jul 14, 2011 10:53:48 pm UTC ) --------
<?xml version="1.0" encoding="utf-8"?><ARBGetSubscriptionStatusResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages><Status>active</Status></ARBGetSubscriptionStatusResponse>
array (
  'response_reason_code' => 'I00001',
  'response_code' => 'I00001',
  'response_reason_text' => 'Successful.',
  'response_text' => 'Successful.',
  'subscription_status' => 'active',
)


libraryinsider.com/library-locator/cancel-recurring-billing/
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1;)
-------- Input vars: ( Thu Jul 14, 2011 10:53:50 pm UTC ) --------
array (
  'x_method' => 'cancel',
  'x_subscription_id' => '9...2',
  'x_login' => 'xxxxxx',
  'x_tran_key' => 'xxxxxx',
  'x_invoice_num' => false,
  'x_description' => '',
)
-------- Output string/vars: ( Thu Jul 14, 2011 10:53:50 pm UTC ) --------
<?xml version="1.0" encoding="utf-8"?><ARBCancelSubscriptionResponse xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="AnetApi/xml/v1/schema/AnetApiSchema.xsd"><messages><resultCode>Ok</resultCode><message><code>I00001</code><text>Successful.</text></message></messages></ARBCancelSubscriptionResponse>
array (
  'response_reason_code' => 'I00001',
  'response_code' => 'I00001',
  'response_reason_text' => 'Successful.',
  'response_text' => 'Successful.',
)

Re: Authorize.net Automatic EOT behavior

PostPosted: July 21st, 2011, 12:00 am
by Cristián Lávaque
Thanks a lot.

Do you think you could post the log entries for this user in full and not just parts? x'ing out any private info, of course. I'll email Jason to take a look at it.

Re: Authorize.net Automatic EOT behavior

PostPosted: July 21st, 2011, 12:55 am
by nciske
Here's both entries for the user from authnet-ipn.log:

Code: Select all
sitename.com/?s2member_pro_authnet_notify=1
User-Agent:
array (
  's2member_log' =>
  array (
    0 => 'Unable to verify POST vars. This is most likely related to an invalid Authorize.Net® configuration. Please check: s2Member -> Authorize.Net® Options.',
    1 => 'If you\'re absolutely SURE that your Authorize.Net® configuration is valid, you may want to run some tests on your server, just to be sure $_POST variables are populated, and that your server is able to connect to Authorize.Net® over an HTTPS connection.',
    2 => 's2Member uses the WP_Http class for remote connections; which will try to use cURL first, and then fall back on the FOPEN method when cURL is not available. On a Windows® server, you may have to disable your cURL extension. Instead, set allow_url_fopen = yes in your php.ini file. The cURL extension (usually) does NOT support SSL connections on a Windows® server.',
    3 => 'array (
  \'s2member_pro_authnet_notify\' => \'1\',
  \'x_response_code\' => \'1\',
  \'x_response_reason_code\' => \'1\',
  \'x_response_reason_text\' => \'This transaction has been approved.\',
  \'x_avs_code\' => \'Y\',
  \'x_auth_code\' => \'0...R\',
  \'x_trans_id\' => \'3...2\',
  \'x_method\' => \'CC\',
  \'x_card_type\' => \'Discover\',
  \'x_account_number\' => \'X...6\',
  \'x_first_name\' => \'Name\',
  \'x_last_name\' => \'Last\',
  \'x_company\' => \'\',
  \'x_address\' => \'123 Example Lane\',
  \'x_city\' => \'City\',
  \'x_state\' => \'ST\',
  \'x_zip\' => \'12345\',
  \'x_country\' => \'US\',
  \'x_phone\' => \'\',
  \'x_fax\' => \'\',
  \'x_email\' => \'email@gmail.com\',
  \'x_invoice_num\' => \'s2-1...8\',
  \'x_description\' => \'2  States / $XX USD / Quarterly ( recurring charge, for ongoing access ) ((1...8:0 D:3 M~sitename.com~1:+ma,sc))\',
  \'x_type\' => \'auth_capture\',
  \'x_cust_id\' => \'\',
  \'x_ship_to_first_name\' => \'\',
  \'x_ship_to_last_name\' => \'\',
  \'x_ship_to_company\' => \'\',
  \'x_ship_to_address\' => \'\',
  \'x_ship_to_city\' => \'\',
  \'x_ship_to_state\' => \'\',
  \'x_ship_to_zip\' => \'\',
  \'x_ship_to_country\' => \'\',
  \'x_amount\' => \'XX.00\',
  \'x_tax\' => \'0.00\',
  \'x_duty\' => \'0.00\',
  \'x_freight\' => \'0.00\',
  \'x_tax_exempt\' => \'FALSE\',
  \'x_po_num\' => \'\',
  \'x_MD5_Hash\' => \'F...8\',
  \'x_cvv2_resp_code\' => \'\',
  \'x_cavv_response\' => \'\',
  \'x_test_request\' => \'false\',
  \'x_subscription_id\' => \'9...2\',
  \'x_subscription_paynum\' => \'1\',
  \'_REPEATED\' => \'0\',
)',
  ),
)

-------

sitename.com/?s2member_pro_authnet_notify=1
User-Agent:
array (
  's2member_log' =>
  array (
    0 => 'Unable to verify POST vars. This is most likely related to an invalid Authorize.Net® configuration. Please check: s2Member -> Authorize.Net® Options.',
    1 => 'If you\'re absolutely SURE that your Authorize.Net® configuration is valid, you may want to run some tests on your server, just to be sure $_POST variables are populated, and that your server is able to connect to Authorize.Net® over an HTTPS connection.',
    2 => 's2Member uses the WP_Http class for remote connections; which will try to use cURL first, and then fall back on the FOPEN method when cURL is not available. On a Windows® server, you may have to disable your cURL extension. Instead, set allow_url_fopen = yes in your php.ini file. The cURL extension (usually) does NOT support SSL connections on a Windows® server.',
    3 => 'array (
  \'s2member_pro_authnet_notify\' => \'1\',
  \'x_response_code\' => \'1\',
  \'x_response_reason_code\' => \'1\',
  \'x_response_reason_text\' => \'This transaction has been approved.\',
  \'x_avs_code\' => \'Y\',
  \'x_auth_code\' => \'0...R\',
  \'x_trans_id\' => \'3...2\',
  \'x_method\' => \'CC\',
  \'x_card_type\' => \'Discover\',
  \'x_account_number\' => \'X...6\',
  \'x_first_name\' => \'First\',
  \'x_last_name\' => \'Last\',
  \'x_company\' => \'\',
  \'x_address\' => \'123 Example Lane\',
  \'x_city\' => \'City\',
  \'x_state\' => \'ST\',
  \'x_zip\' => \'12345\',
  \'x_country\' => \'US\',
  \'x_phone\' => \'\',
  \'x_fax\' => \'\',
  \'x_email\' => \'email@gmail.com\',
  \'x_invoice_num\' => \'s2-1...8\',
  \'x_description\' => \'2  States / $XX USD / Quarterly ( recurring charge, for ongoing access ) ((1...8:0 D:3 M~sitename.com~1:+ma,sc))\',
  \'x_type\' => \'auth_capture\',
  \'x_cust_id\' => \'\',
  \'x_ship_to_first_name\' => \'\',
  \'x_ship_to_last_name\' => \'\',
  \'x_ship_to_company\' => \'\',
  \'x_ship_to_address\' => \'\',
  \'x_ship_to_city\' => \'\',
  \'x_ship_to_state\' => \'\',
  \'x_ship_to_zip\' => \'\',
  \'x_ship_to_country\' => \'\',
  \'x_amount\' => \'XX.00\',
  \'x_tax\' => \'0.00\',
  \'x_duty\' => \'0.00\',
  \'x_freight\' => \'0.00\',
  \'x_tax_exempt\' => \'FALSE\',
  \'x_po_num\' => \'\',
  \'x_MD5_Hash\' => \'F...8\',
  \'x_cvv2_resp_code\' => \'\',
  \'x_cavv_response\' => \'\',
  \'x_test_request\' => \'false\',
  \'x_subscription_id\' => \'9...2\',
  \'x_subscription_paynum\' => \'1\',
  \'_REPEATED\' => \'0\',
)',
  ),
)


In authnet-arb-ipn.log all the other entries are the same as this one (one per day the wp-cron ran):

Code: Select all
sitename.com/wp-cron.php?doing_wp_cron
User-Agent: WordPress/3.1; http://sitename.com
array (
  'response_reason_code' => 'I00001',
  'response_code' => 'I00001',
  'response_reason_text' => 'Successful.',
  'response_text' => 'Successful.',
  'subscription_status' => 'active',
  'arb_ipn_signup_vars' =>
  array (
    'txn_type' => 'subscr_signup',
    'subscr_id' => '9291082',
    'custom' => 'libraryinsider.com',
    'txn_id' => '3...1',
    'period1' => '0 D',
    'period3' => '3 M',
    'mc_amount1' => '0.00',
    'mc_amount3' => 'X0.00',
    'mc_gross' => 'X0.00',
    'mc_currency' => 'USD',
    'tax' => '0.00',
    'recurring' => 'X0.00',
    'payer_email' => 'email@gmail.com',
    'first_name' => 'First',
    'last_name' => 'Last',
    'item_name' => '2  States / $X0 USD / Quarterly ( recurring charge, for ongoing access )',
    'item_number' => '1:+ma,sc',
    '_REPEATED' => '0',
    'proxy_verified' => 'authnet',
    'subscr_gateway' => 'authnet',
    'eotper' => '',
    'ccaps' => '+ma,sc',
    'level' => '1',
    'initial_term' => '0 D',
    'initial' => 'X0.00',
    'regular' => 'X0.00',
    'regular_term' => '3 M',
  ),
  's2member_log' =>
  array (
    0 => 'Ignoring this ARB/Status (active). It does NOT require any action on the part of s2Member.',
  ),
)


If there's specific info you still need, I'm happy to provide it.

Re: Authorize.net Automatic EOT behavior

PostPosted: July 21st, 2011, 1:18 am
by Cristián Lávaque
Cool. Thanks. I'll wait for Jason now.

Re: Authorize.net Automatic EOT behavior

PostPosted: July 22nd, 2011, 6:38 pm
by Jason Caldwell
Thanks for the heads up on this thread.

From what I've seen so far, I suspect that s2Member is failing to record Payment Times for your Members, and thus, is terminating their accounts immediately, because it's failing to collect the information it needs to make an intelligent decision about the EOT Time.

Let's start please, by addressing the errors in your authnet-ipn.log file.
"Unable to verify POST vars.", indicates that s2Member is failing to communicate with Authorize.Net's Silent Post ( aka: IPN communication ). Have you double/triple checked your API details for Authorize.Net? I suspect that your MD5 Hash is the problem. I would try to reset this inside your Authorize.Net account, and then update the value inside your Dashboard as well, under: s2Member -> AuthNet Options -> Account Details.

Next, I need to see all of the related entries inside your paypal-ipn.log file as well. Ultimately, all transactions are processed internally by s2Member's core PayPal processors, even if you're running Authorize.Net. So in order to get a deeper look at what's going on behind-the-scene, I'll need to see the related entries inside the paypal-ipn.log file as well. Please leave as much detail visible as possible.

If we are unable to resolve this after another round of logs, I'll need a Dashboard login and FTP access to your /wp-content/ directory ( or better ) please. That information can be provided through our private contact form here: http://www.s2member.com/contact/

Awaiting feedback at this time. Thanks!

Re: Authorize.net Automatic EOT behavior

PostPosted: July 25th, 2011, 5:26 pm
by nciske
Apparently Authorize.net limits MD5 hashes to 20 characters... but doesn't say that anywhere, it just truncates whatever you enter. It'd be nice if they alerted you to the fact that they were truncating your input... why they'd limit the key used to encrypt responses is beyond me...

So the hash in s2member was longer than the one at Auth.net, which appears to be the root of the issue.

I'll check the logs tomorrow and I suspect the errors will be gone -- and hopefully the early termination issue!

Re: Authorize.net Automatic EOT behavior

PostPosted: July 25th, 2011, 5:28 pm
by nciske
FYI- S2 is recording start times just fine -- I use those in my code to tell users how long they have left in their subscription.

If the MD5 fix doesn't help, I'll post the logs.

Re: Authorize.net Automatic EOT behavior

PostPosted: July 27th, 2011, 3:57 pm
by Jason Caldwell
Awesome work. Thanks for reporting this too.
~ MUCH appreciated. I'll see if we can post a note about this.