| @@ -189,8 +189,9 @@ | ||
| 189 | 189 | // Do not guess term values in fallback vars (risk of incorrect EOT decisions). |
| 190 | 190 | if (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['ipn_signup_vars_fallback'])) { |
| 191 | 191 | $userdata = get_userdata((int)$user_id); |
| 192 | 192 | $ipn_signup_vars = array( |
| 193 | + 's2member_ipn_signup_vars_fallback' => '1', //260829.1709 Mark generated fallback vars explicitly so gateway-aware EOT logic can distinguish missing local signup metadata from malformed stored signup data. | |
| 193 | 194 | 'subscr_cid' => !empty($_subscr_cid) ? $_subscr_cid : '', |
| 194 | 195 | 'subscr_id' => $_subscr_id, |
| 195 | 196 | 'custom' => esc_html($_SERVER["HTTP_HOST"]), |
| 196 | 197 | 'period1' => '', |
| @@ -438,9 +439,9 @@ | ||
| 438 | 439 | * - `debug` A string of details that explain to a developer what was returned. For debugging only. |
| 439 | 440 | */ |
| 440 | 441 | public static function get_user_eot($user_id = 0, $check_gateway = TRUE, $favor = 'fixed') |
| 441 | 442 | { |
| 442 | - if(!($user_id = (integer)$user_id)) // Empty user ID in this call? | |
| 443 | + if(!($user_id = (int)$user_id)) // Empty user ID in this call? | |
| 443 | 444 | $user_id = get_current_user_id(); // Assume current user. |
| 444 | 445 | |
| 445 | 446 | if(!$favor || !in_array($favor, array('fixed', 'next'), TRUE)) |
| 446 | 447 | $favor = 'fixed'; // Default behavior. |
| @@ -445,10 +446,10 @@ | ||
| 445 | 446 | if(!$favor || !in_array($favor, array('fixed', 'next'), TRUE)) |
| 446 | 447 | $favor = 'fixed'; // Default behavior. |
| 447 | 448 | |
| 448 | 449 | $now = time(); // Current timestamp. |
| 449 | - $grace_time = (integer)$GLOBALS['WS_PLUGIN__']['s2member']['o']['eot_grace_time']; | |
| 450 | - $grace_time = (integer)apply_filters('ws_plugin__s2member_eot_grace_time', $grace_time); | |
| 450 | + $grace_time = (int)$GLOBALS['WS_PLUGIN__']['s2member']['o']['eot_grace_time']; | |
| 451 | + $grace_time = (int)apply_filters('ws_plugin__s2member_eot_grace_time', $grace_time); | |
| 451 | 452 | $demotion_role = c_ws_plugin__s2member_option_forces::force_demotion_role('subscriber'); |
| 452 | 453 | $empty_response = array('type' => '', 'time' => 0, 'tense' => '', 'debug' => ''); |
| 453 | 454 | |
| 454 | 455 | if(!$user_id || !($user = new WP_User($user_id)) || !$user->ID) |
| @@ -457,10 +458,10 @@ | ||
| 457 | 458 | $ipn_signup_vars = self::get_user_ipn_signup_vars($user->ID); |
| 458 | 459 | $subscr_gateway = (string)get_user_option('s2member_subscr_gateway', $user->ID); |
| 459 | 460 | $subscr_id = (string)get_user_option('s2member_subscr_id', $user->ID); |
| 460 | 461 | $subscr_cid = (string)get_user_option('s2member_subscr_cid', $user->ID); |
| 461 | - $last_auto_eot_time = (integer)get_user_option('s2member_last_auto_eot_time', $user->ID); | |
| 462 | - $auto_eot_time = (integer)get_user_option('s2member_auto_eot_time', $user->ID); | |
| 462 | + $last_auto_eot_time = (int)get_user_option('s2member_last_auto_eot_time', $user->ID); | |
| 463 | + $auto_eot_time = (int)get_user_option('s2member_auto_eot_time', $user->ID); | |
| 463 | 464 | |
| 464 | 465 | if($auto_eot_time) // They have a hard-coded EOT time at present? |
| 465 | 466 | return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', |
| 466 | 467 | 'debug' => 'This is a fixed EOT time recorded by s2Member. It can be altered in the WordPress Dashboard for this user.'); |
| @@ -465,127 +466,173 @@ | ||
| 465 | 466 | return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', |
| 466 | 467 | 'debug' => 'This is a fixed EOT time recorded by s2Member. It can be altered in the WordPress Dashboard for this user.'); |
| 467 | 468 | |
| 468 | 469 | if(!$subscr_gateway && !$subscr_id && !$subscr_cid && $last_auto_eot_time // EOTd? |
| 469 | - && (!user_can($user->ID, 'access_s2member_level1') || c_ws_plugin__s2member_user_access::user_access_role($user) === $demotion_role) | |
| 470 | + //260916.1840 A preserved unrelated role may sort before the destination role, so inspect all assigned roles instead of only s2Member's historical first-role result. | |
| 471 | + && (!user_can($user->ID, 'access_s2member_level1') || in_array($demotion_role, (array)$user->roles, TRUE)) | |
| 470 | 472 | && !c_ws_plugin__s2member_user_access::user_access_ccaps($user) // And no CCAPs either? |
| 471 | 473 | ) return array('type' => 'fixed', 'time' => $last_auto_eot_time, 'tense' => $last_auto_eot_time <= $now ? 'past' : 'future', |
| 472 | - 'debug' => 'This is an archived/fixed EOT time recorded by s2Member; i.e., the date this customer\'s access expired.'); | |
| 474 | + 'debug' => 'This is an archived/fixed EOT time recorded by s2Member; i.e., the date this customer\'s membership EOT was processed.'); | |
| 473 | 475 | |
| 474 | 476 | if(!$subscr_gateway || !$subscr_id || !is_array($ipn_signup_vars) || !$ipn_signup_vars) |
| 475 | 477 | return array_merge($empty_response, array('debug' => 'This user has no subscription; i.e., missing `subscr_id`, `subscr_gateway` or `ipn_signup_vars`.')); |
| 476 | 478 | |
| 477 | - if(empty($ipn_signup_vars['txn_type']) || $ipn_signup_vars['txn_type'] !== 'subscr_signup') | |
| 479 | + $ipn_signup_vars_fallback = !empty($ipn_signup_vars['s2member_ipn_signup_vars_fallback']); | |
| 480 | + //260829.1709 A PayPal fallback still has a bound local subscription ID, so allow the configured PayPal APIs to recover authoritative timing before rejecting it for missing legacy signup metadata. | |
| 481 | + $can_recover_paypal_fallback = ($check_gateway && $subscr_gateway === 'paypal' && $ipn_signup_vars_fallback); | |
| 482 | + | |
| 483 | + if((empty($ipn_signup_vars['txn_type']) || $ipn_signup_vars['txn_type'] !== 'subscr_signup') && !$can_recover_paypal_fallback) | |
| 478 | 484 | return array_merge($empty_response, array('debug' => 'This user has no subscription; i.e., `txn_type` != `subscr_signup`.')); |
| 479 | 485 | |
| 480 | - $auto_eot_time // Update this now; i.e., build a new EOT time based on IPN signup vars. | |
| 481 | - = c_ws_plugin__s2member_utils_time::auto_eot_time($user->ID, $ipn_signup_vars['period1'], $ipn_signup_vars['period3']); | |
| 486 | + //260829.1709 Never turn deliberately blank fallback billing terms into an estimated EOT of "now"; PayPal API recovery below must succeed or the existing empty/fallback behavior remains. | |
| 487 | + $auto_eot_time = ($ipn_signup_vars_fallback && empty($ipn_signup_vars['period3'])) | |
| 488 | + ? 0 | |
| 489 | + : c_ws_plugin__s2member_utils_time::auto_eot_time($user->ID, $ipn_signup_vars['period1'], $ipn_signup_vars['period3']); | |
| 482 | 490 | |
| 491 | + //260828.0710 !!! TO-DO: Track a gateway-independent `s2member_access_through_time`, meaning the end of the latest confirmed entitlement period, before EOT grace. | |
| 492 | + // 1. On signup/received payment, save the provider's then-current next billing/period-end time as access-through. Failed payments never advance it. 2. Cancellation/EOT should use this value when available, even if already past. | |
| 493 | + // 3. For older users without it, estimate conservatively from provider billing schedule + signup vars/last successful payment when reliable; otherwise keep the existing estimated EOT fallback. | |
| 483 | 494 | if($check_gateway) switch($subscr_gateway) // A bit different for each payment gateway. |
| 484 | 495 | { |
| 485 | 496 | case 'paypal': // PayPal (legacy Pro NVP/Payflow + PayPal Checkout REST). |
| 486 | 497 | |
| 487 | - //260213 PayPal Checkout subscriptions: use REST Subscriptions API for reconciliation (NVP GetRecurringPaymentsProfileDetails returns 11592). | |
| 488 | - if(!empty($ipn_signup_vars['s2member_paypal_proxy_use']) && $ipn_signup_vars['s2member_paypal_proxy_use'] === 'paypal_checkout') | |
| 498 | + $ppco_creds = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_creds(); | |
| 499 | + $can_try_ppco = (!empty($ppco_creds['client_id']) && !empty($ppco_creds['secret'])); | |
| 500 | + $can_try_standard = (!empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_username']) | |
| 501 | + && !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_password']) | |
| 502 | + && !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_signature'])); | |
| 503 | + $can_try_payflow = (c_ws_plugin__s2member_utils_conds::pro_is_installed() | |
| 504 | + && class_exists('c_ws_plugin__s2member_pro_paypal_utilities') | |
| 505 | + && !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_payflow_api_username'])); | |
| 506 | + | |
| 507 | + //260819.0543 Prefer positive product provenance, then fall through to other configured PayPal APIs when lookup fails. | |
| 508 | + // Classic Recurring Payments and REST Subscriptions can both use I-* IDs; Payflow profile IDs use RP/RT prefixes. | |
| 509 | + $ppco_hint = ((!empty($ipn_signup_vars['s2member_paypal_proxy_use']) && $ipn_signup_vars['s2member_paypal_proxy_use'] === 'paypal_checkout') | |
| 510 | + || (!empty($ipn_signup_vars['invoice']) && strpos((string)$ipn_signup_vars['invoice'], 's2mpf-') === 0)); | |
| 511 | + $payflow_hint = (bool)preg_match('/^R[PT]/i', $subscr_id); | |
| 512 | + if($ppco_hint) | |
| 513 | + $paypal_routes = array('ppco', 'standard', 'payflow'); | |
| 514 | + else if($payflow_hint) | |
| 515 | + $paypal_routes = array('payflow', 'standard', 'ppco'); | |
| 516 | + else | |
| 517 | + $paypal_routes = array('standard', 'ppco', 'payflow'); | |
| 518 | + | |
| 519 | + foreach($paypal_routes as $_paypal_route) | |
| 489 | 520 | { |
| 490 | - $ppco_enabled = !empty($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_enable']) && (string)$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_checkout_enable'] !== '0'; | |
| 521 | + switch($_paypal_route) | |
| 522 | + { | |
| 523 | + case 'ppco': | |
| 524 | + if(!$can_try_ppco) | |
| 525 | + break; | |
| 491 | 526 | |
| 492 | - $ppco_creds = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_creds(); | |
| 527 | + $subscription = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_subscription_details($subscr_id); | |
| 528 | + if(!$subscription || !empty($subscription['__error'])) | |
| 529 | + break; // Try another configured PayPal API family. | |
| 493 | 530 | |
| 494 | - if(!$ppco_enabled || empty($ppco_creds['client_id']) || empty($ppco_creds['secret'])) | |
| 495 | - return array_merge($empty_response, array( | |
| 496 | - 'debug' => 'PayPal Checkout subscription reconciliation skipped (disabled or missing REST API credentials).', | |
| 497 | - )); | |
| 531 | + $status = !empty($subscription['status']) ? strtoupper((string)$subscription['status']) : ''; | |
| 532 | + $next = !empty($subscription['billing_info']['next_billing_time']) ? (string)$subscription['billing_info']['next_billing_time'] : ''; | |
| 498 | 533 | |
| 499 | - $subscription_r = c_ws_plugin__s2member_paypal_utilities::paypal_checkout_api_request('GET', '/v1/billing/subscriptions/'.rawurlencode($subscr_id)); | |
| 534 | + if($status && $status !== 'ACTIVE') | |
| 535 | + { | |
| 536 | + if($auto_eot_time) | |
| 537 | + return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 538 | + 'debug' => 'This is the estimated EOT time. PayPal Checkout says this subscription is no longer active, and thus, access should be terminated at this time.'); | |
| 500 | 539 | |
| 501 | - $subscription_code = !empty($subscription_r['code']) ? (int)$subscription_r['code'] : 0; | |
| 502 | - $subscription_body = !empty($subscription_r['body']) ? (string)$subscription_r['body'] : ''; | |
| 540 | + return array_merge($empty_response, array('debug' => 'PayPal Checkout says this subscription is no longer active, but local signup billing terms are unavailable; refusing to guess an EOT.')); | |
| 541 | + } | |
| 503 | 542 | |
| 504 | - $subscription = array(); | |
| 505 | - if($subscription_body) | |
| 506 | - $subscription = json_decode($subscription_body, true); | |
| 543 | + if($next && ($time = strtotime($next)) > $now) | |
| 544 | + return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', | |
| 545 | + 'debug' => 'PayPal Checkout says this is the next payment time.'); | |
| 507 | 546 | |
| 508 | - if(!is_array($subscription)) | |
| 509 | - $subscription = array(); | |
| 547 | + return array_merge($empty_response, array( | |
| 548 | + 'debug' => 'PayPal Checkout says this subscription is active; no next billing time was returned.', | |
| 549 | + )); | |
| 510 | 550 | |
| 511 | - if(!($subscription_code >= 200 && $subscription_code <= 299 && !empty($subscription['id']))) | |
| 512 | - return array_merge($empty_response, array( | |
| 513 | - 'debug' => 'PayPal Checkout subscription reconciliation failed (REST subscription lookup unsuccessful); skipping legacy PayPal status checks.', | |
| 514 | - )); | |
| 551 | + case 'payflow': | |
| 552 | + if(!$can_try_payflow) | |
| 553 | + break; | |
| 515 | 554 | |
| 516 | - $status = !empty($subscription['status']) ? strtoupper((string)$subscription['status']) : ''; | |
| 517 | - $next = !empty($subscription['billing_info']['next_billing_time']) ? (string)$subscription['billing_info']['next_billing_time'] : ''; | |
| 555 | + if(!($api_response = c_ws_plugin__s2member_pro_paypal_utilities::payflow_get_profile($subscr_id)) || !empty($api_response['__error'])) | |
| 556 | + break; // Try another configured PayPal API family. | |
| 518 | 557 | |
| 519 | - if($status && $status !== 'ACTIVE') | |
| 520 | - return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 521 | - 'debug' => 'This is the estimated EOT time. PayPal Checkout says this subscription is no longer active, and thus, access should be terminated at this time.'); | |
| 558 | + if(preg_match('/^(?:Pending|PendingProfile)$/i', $api_response['STATUS'])) | |
| 559 | + return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says the subscription for this user is currently pending changes. Unable to determine at this moment. Please try again in 15 minutes.')); | |
| 522 | 560 | |
| 523 | - if($next && ($time = strtotime($next)) > $now) | |
| 524 | - return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', | |
| 525 | - 'debug' => 'PayPal Checkout says this is the next payment time.'); | |
| 561 | + if(!preg_match('/^(?:Active|ActiveProfile)$/i', $api_response['STATUS'])) | |
| 562 | + { | |
| 563 | + if($auto_eot_time) | |
| 564 | + return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 565 | + 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription is no longer active, and thus, access should be terminated at this time.'); | |
| 526 | 566 | |
| 527 | - return array_merge($empty_response, array( | |
| 528 | - 'debug' => 'PayPal Checkout says this subscription is active; no next billing time was returned.', | |
| 529 | - )); | |
| 530 | - } | |
| 567 | + return array_merge($empty_response, array('debug' => 'The PayPal Pro API says this subscription is no longer active, but local signup billing terms are unavailable; refusing to guess an EOT.')); | |
| 568 | + } | |
| 531 | 569 | |
| 532 | - if(!c_ws_plugin__s2member_utils_conds::pro_is_installed() | |
| 533 | - || !class_exists('c_ws_plugin__s2member_pro_paypal_utilities') | |
| 534 | - || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_username'] | |
| 535 | - || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_password'] | |
| 536 | - || !$GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_api_signature'] | |
| 537 | - ) return array_merge($empty_response, array('debug' => 'PayPal Pro API credentials missing in your s2Member configuration.')); | |
| 570 | + if($api_response['TERM'] > 0 && $api_response['PAYMENTSLEFT'] <= 0) | |
| 571 | + { | |
| 572 | + if($auto_eot_time) | |
| 573 | + return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 574 | + 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription has reached its last payment, and thus, access should be terminated at this time.'); | |
| 538 | 575 | |
| 539 | - if($GLOBALS['WS_PLUGIN__']['s2member']['o']['paypal_payflow_api_username']) | |
| 540 | - { | |
| 541 | - if(!($api_response = c_ws_plugin__s2member_pro_paypal_utilities::payflow_get_profile($subscr_id)) || !empty($api_response['__error'])) | |
| 542 | - return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says there is no subscription for this user.')); | |
| 576 | + return array_merge($empty_response, array('debug' => 'The PayPal Pro API says this subscription has reached its last payment, but local signup billing terms are unavailable; refusing to guess an EOT.')); | |
| 577 | + } | |
| 543 | 578 | |
| 544 | - if(preg_match('/^(?:Pending|PendingProfile)$/i', $api_response['STATUS'])) | |
| 545 | - return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says the subscription for this user is currently pending changes. Unable to determine at this moment. Please try again in 15 minutes.')); | |
| 579 | + if($api_response['TERM'] <= 0 || $api_response['PAYMENTSLEFT'] > 0) | |
| 580 | + if($api_response['NEXTPAYMENT'] && strlen($api_response['NEXTPAYMENT']) === 8) // MMDDYYYY format is not `strtotime()` compatible. | |
| 581 | + if(($time = strtotime(substr($api_response['NEXTPAYMENT'], -4).'-'.substr($api_response['NEXTPAYMENT'], 0, 2).'-'.substr($api_response['NEXTPAYMENT'], 2, 2))) > $now) | |
| 582 | + return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', | |
| 583 | + 'debug' => 'The PayPal Pro API says this is the next payment time.'); | |
| 546 | 584 | |
| 547 | - if(!preg_match('/^(?:Active|ActiveProfile)$/i', $api_response['STATUS'])) | |
| 548 | - return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 549 | - 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription is no longer active, and thus, access should be terminated at this time.'); | |
| 585 | + return array_merge($empty_response, array('debug' => 'No fixed EOT, and there are no more payments needed from this user.')); | |
| 550 | 586 | |
| 551 | - if($api_response['TERM'] > 0 && $api_response['PAYMENTSLEFT'] <= 0) | |
| 552 | - return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 553 | - 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription has reached its last payment, and thus, access should be terminated at this time.'); | |
| 587 | + case 'standard': | |
| 588 | + if(!$can_try_standard) | |
| 589 | + break; | |
| 554 | 590 | |
| 555 | - if($api_response['TERM'] <= 0 || $api_response['PAYMENTSLEFT'] > 0) | |
| 556 | - if($api_response['NEXTPAYMENT'] && strlen($api_response['NEXTPAYMENT']) === 8) // MMDDYYYY format is not `strtotime()` compatible. | |
| 557 | - if(($time = strtotime(substr($api_response['NEXTPAYMENT'], -4).'-'.substr($api_response['NEXTPAYMENT'], 0, 2).'-'.substr($api_response['NEXTPAYMENT'], 2, 2))) > $now) | |
| 558 | - return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', | |
| 559 | - 'debug' => 'The PayPal Pro API says this is the next payment time.'); | |
| 560 | - } | |
| 561 | - else // Use PayPal Pro API (old flavor). | |
| 562 | - { | |
| 563 | - $api_args = array( | |
| 564 | - 'METHOD' => 'GetRecurringPaymentsProfileDetails', | |
| 565 | - 'PROFILEID' => $subscr_id, | |
| 566 | - ); | |
| 567 | - if(!($api_response = c_ws_plugin__s2member_paypal_utilities::paypal_api_response($api_args)) || !empty($api_response['__error'])) | |
| 568 | - return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says there is no subscription for this user.')); | |
| 591 | + $api_args = array( | |
| 592 | + 'METHOD' => 'GetRecurringPaymentsProfileDetails', | |
| 593 | + 'PROFILEID' => $subscr_id, | |
| 594 | + ); | |
| 595 | + if(!($api_response = c_ws_plugin__s2member_paypal_utilities::paypal_api_response($api_args)) || !empty($api_response['__error'])) | |
| 596 | + break; // 11592 and other profile-family misses may resolve through REST. | |
| 569 | 597 | |
| 570 | - if(preg_match('/^(?:Pending|PendingProfile)$/i', $api_response['STATUS'])) | |
| 571 | - return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says the subscription for this user is currently pending changes. Unable to determine at this moment. Please try again in 15 minutes.')); | |
| 598 | + if(preg_match('/^(?:Pending|PendingProfile)$/i', $api_response['STATUS'])) | |
| 599 | + return array_merge($empty_response, array('debug' => 'No fixed EOT, and the PayPal Pro API says the subscription for this user is currently pending changes. Unable to determine at this moment. Please try again in 15 minutes.')); | |
| 572 | 600 | |
| 573 | - if(!preg_match('/^(?:Active|ActiveProfile)$/i', $api_response['STATUS'])) | |
| 574 | - return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 575 | - 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription is no longer active, and thus, access should be terminated at this time.'); | |
| 601 | + if(!preg_match('/^(?:Active|ActiveProfile)$/i', $api_response['STATUS'])) | |
| 602 | + { | |
| 603 | + if($auto_eot_time) | |
| 604 | + return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 605 | + 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription is no longer active, and thus, access should be terminated at this time.'); | |
| 576 | 606 | |
| 577 | - if($api_response['TOTALBILLINGCYCLES'] > 0 && $api_response['NUMCYCLESREMAINING'] <= 0) | |
| 578 | - return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 579 | - 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription has reached its last payment, and thus, access should be terminated at this time.'); | |
| 607 | + return array_merge($empty_response, array('debug' => 'The PayPal Pro API says this subscription is no longer active, but local signup billing terms are unavailable; refusing to guess an EOT.')); | |
| 608 | + } | |
| 580 | 609 | |
| 581 | - if($api_response['TOTALBILLINGCYCLES'] <= 0 || $api_response['NUMCYCLESREMAINING'] > 0) | |
| 582 | - if($api_response['NEXTBILLINGDATE'] && ($time = strtotime($api_response['NEXTBILLINGDATE'])) > $now) | |
| 583 | - return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', | |
| 584 | - 'debug' => 'The PayPal Pro API says this is the next payment time.'); | |
| 585 | - } | |
| 586 | - return array_merge($empty_response, array('debug' => 'No fixed EOT, and there are no more payments needed from this user.')); | |
| 610 | + if($api_response['TOTALBILLINGCYCLES'] > 0 && $api_response['NUMCYCLESREMAINING'] <= 0) | |
| 611 | + { | |
| 612 | + if($auto_eot_time) | |
| 613 | + return array('type' => 'fixed', 'time' => $auto_eot_time, 'tense' => $auto_eot_time <= $now ? 'past' : 'future', | |
| 614 | + 'debug' => 'This is the estimated EOT time. The PayPal Pro API says this subscription has reached its last payment, and thus, access should be terminated at this time.'); | |
| 587 | 615 | |
| 616 | + return array_merge($empty_response, array('debug' => 'The PayPal Pro API says this subscription has reached its last payment, but local signup billing terms are unavailable; refusing to guess an EOT.')); | |
| 617 | + } | |
| 618 | + | |
| 619 | + if($api_response['TOTALBILLINGCYCLES'] <= 0 || $api_response['NUMCYCLESREMAINING'] > 0) | |
| 620 | + if($api_response['NEXTBILLINGDATE'] && ($time = strtotime($api_response['NEXTBILLINGDATE'])) > $now) | |
| 621 | + return array('type' => 'next', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', | |
| 622 | + 'debug' => 'The PayPal Pro API says this is the next payment time.'); | |
| 623 | + | |
| 624 | + return array_merge($empty_response, array('debug' => 'No fixed EOT, and there are no more payments needed from this user.')); | |
| 625 | + } | |
| 626 | + } | |
| 627 | + | |
| 628 | + if(!$can_try_ppco && !$can_try_standard && !$can_try_payflow) | |
| 629 | + return array_merge($empty_response, array('debug' => 'PayPal subscription API credentials missing in your s2Member configuration.')); | |
| 630 | + | |
| 631 | + return array_merge($empty_response, array( | |
| 632 | + 'debug' => 'No fixed EOT, and no configured PayPal API could resolve this subscription. Older recurring profiles may still require legacy PayPal API credentials.', | |
| 633 | + )); | |
| 634 | + | |
| 588 | 635 | break; // Break switch. |
| 589 | 636 | |
| 590 | 637 | case 'authnet': // Authorize.Net (EOT only; w/ limited functionality). |
| 591 | 638 | |
| @@ -624,9 +671,9 @@ | ||
| 624 | 671 | |
| 625 | 672 | if(!is_object($stripe_subscription = c_ws_plugin__s2member_pro_stripe_utilities::get_customer_subscription($subscr_cid, $subscr_id)) || empty($stripe_subscription->id)) |
| 626 | 673 | return array_merge($empty_response, array('debug' => 'No fixed EOT, and the Stripe API says there is no subscription for this user.')); |
| 627 | 674 | |
| 628 | - if((integer)$stripe_subscription->ended_at > 0) // Done? | |
| 675 | + if((int)$stripe_subscription->ended_at > 0) // Done? | |
| 629 | 676 | { |
| 630 | 677 | $time = $stripe_subscription->ended_at + $grace_time; |
| 631 | 678 | return array('type' => 'fixed', 'time' => $time, 'tense' => $time <= $now ? 'past' : 'future', |
| 632 | 679 | 'debug' => 'The Stripe API says this subscription reached an expiration on this date + grace time.'); |
| @@ -639,9 +686,9 @@ | ||
| 639 | 686 | } |
| 640 | 687 | if(isset($stripe_subscription->plan->metadata->recurring, $stripe_subscription->plan->metadata->recurring_times) |
| 641 | 688 | && !$stripe_subscription->plan->metadata->recurring) // Non-recurring subscription? |
| 642 | 689 | { |
| 643 | - $time = (integer)$stripe_subscription->start; | |
| 690 | + $time = (int)$stripe_subscription->start; | |
| 644 | 691 | $time += $stripe_subscription->plan->trial_period_days * DAY_IN_SECONDS; |
| 645 | 692 | |
| 646 | 693 | switch($stripe_subscription->plan->interval) |
| 647 | 694 | { |
| @@ -688,9 +735,9 @@ | ||
| 688 | 735 | } |
| 689 | 736 | if(isset($stripe_subscription->plan->metadata->recurring, $stripe_subscription->plan->metadata->recurring_times) |
| 690 | 737 | && $stripe_subscription->plan->metadata->recurring && $stripe_subscription->plan->metadata->recurring_times > 0) |
| 691 | 738 | { |
| 692 | - $time = (integer)$stripe_subscription->start; | |
| 739 | + $time = (int)$stripe_subscription->start; | |
| 693 | 740 | $time += $stripe_subscription->plan->trial_period_days * DAY_IN_SECONDS; |
| 694 | 741 | |
| 695 | 742 | switch($stripe_subscription->plan->interval) |
| 696 | 743 | { |