/** * Process the payment */ function process_payment($order_id) { global $woocommerce; if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($order_id)) { $order = new WC_Order($order_id); $stripe_token = isset($_POST['stripe_token']) ? woocommerce_clean($_POST['stripe_token']) : ''; // Use Stripe CURL API for payment try { $post_data = array(); $customer_id = 0; // Check if paying via customer ID if (isset($_POST['stripe_customer_id']) && $_POST['stripe_customer_id'] !== 'new' && is_user_logged_in()) { $customer_ids = get_user_meta(get_current_user_id(), '_stripe_customer_id', false); if (isset($customer_ids[$_POST['stripe_customer_id']]['customer_id'])) { $customer_id = $customer_ids[$_POST['stripe_customer_id']]['customer_id']; } else { throw new Exception(__('Invalid card.', 'wc_stripe')); } } elseif (empty($stripe_token)) { throw new Exception(__('Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'wc_stripe')); } if (method_exists('WC_Subscriptions_Order', 'get_total_initial_payment')) { $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order); } else { $initial_payment = WC_Subscriptions_Order::get_sign_up_fee($order) + WC_Subscriptions_Order::get_price_per_period($order); } $customer_response = $this->add_customer_to_order($order, $customer_id, $stripe_token); if ($initial_payment > 0) { $payment_response = $this->process_subscription_payment($order, $initial_payment); } if (is_wp_error($customer_response)) { throw new Exception($customer_response->get_error_message()); } else { if (isset($payment_response) && is_wp_error($payment_response)) { throw new Exception($payment_response->get_error_message()); } else { // Payment complete $order->payment_complete(); // Remove cart $woocommerce->cart->empty_cart(); // Activate subscriptions WC_Subscriptions_Manager::activate_subscriptions_for_order($order); // Store token if ($stripe_token) { update_post_meta($order->id, '_stripe_token', $stripe_token); } // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } } catch (Exception $e) { $woocommerce->add_error(__('Error:', 'wc_stripe') . ' "' . $e->getMessage() . '"'); return; } } else { return parent::process_payment($order_id); } }
/** * Process the payment and return the result * * @access public * @param int $order_id * @return array */ public function process_payment($order_id) { if (WC_Subscriptions_Order::order_contains_subscription($order_id)) { if ($this->send_to_stripe($order_id)) { $this->order_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($this->order); $result = array('result' => 'success', 'redirect' => $this->get_return_url($this->order)); return $result; } else { $this->payment_failed(); // Add a generic error message if we don't currently have any others if (wc_notice_count('error') == 0) { wc_add_notice(__('Transaction Error: Could not complete your subscription payment.', 'stripe-for-woocommerce'), 'error'); } } } else { return parent::process_payment($order_id); } }
function paymill_webhooks() { global $wpdb; // is there a webhook from Paymill? if (class_exists('WC_Subscriptions_Manager')) { // grab data from webhook $body = @file_get_contents('php://input'); $event_json = json_decode($body, true); // retrieve sub ID if (isset($event_json['event']['event_resource']['id']) && strlen($event_json['event']['event_resource']['id']) > 0) { $paymill_sub_id = $event_json['event']['event_resource']['id']; } elseif (isset($event_json['event']['event_resource']['subscription']['id']) && strlen($event_json['event']['event_resource']['subscription']['id']) > 0) { $paymill_sub_id = $event_json['event']['event_resource']['subscription']['id']; } error_log("\n\n########################################################################################################################\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); error_log(date(DATE_RFC822) . ' - Webhook ' . $event_json['event']['event_type'] . ' (Resource-ID: ' . $paymill_sub_id . ') triggered - start processing' . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); /* output example: array(1) { ["event"]=> array(4) { ["event_type"]=> string(20) "subscription.deleted" ["event_resource"]=> array(13) { ["id"]=> string(24) "sub_b71adbf5....." ["offer"]=> array(10) { ["id"]=> string(26) "offer_8083a5b....." ["name"]=> string(39) "woo_91_73da6....." ["amount"]=> int(100) ["currency"]=> string(3) "EUR" ["interval"]=> string(5) "1 DAY" ["trial_period_days"]=> int(0) ["created_at"]=> int(1389547028) ["updated_at"]=> int(1389547028) ["subscription_count"]=> array(2) { ["active"]=> string(1) "1" ["inactive"]=> string(1) "1" } ["app_id"]=> NULL } ["livemode"]=> bool(false) ["cancel_at_period_end"]=> bool(false) ["trial_start"]=> NULL ["trial_end"]=> NULL ["next_capture_at"]=> int(1389836717) ["created_at"]=> int(1389663382) ["updated_at"]=> int(1389750317) ["canceled_at"]=> NULL ["app_id"]=> NULL ["payment"]=> array(12) { ["id"]=> string(28) "pay_4e3759f....." ["type"]=> string(10) "creditcard" ["client"]=> string(27) "client_dbe164....." ["card_type"]=> string(4) "visa" ["country"]=> NULL ["expire_month"]=> string(2) "12" ["expire_year"]=> string(4) "2020" ["card_holder"]=> string(13) "dfgdfgdfgdfgd" ["last4"]=> string(4) "1111" ["created_at"]=> int(1389663369) ["updated_at"]=> int(1389663380) ["app_id"]=> NULL } ["client"]=> array(8) { ["id"]=> string(27) "client_dbe164....." ["email"]=> string(22) "*****@*****.**" ["description"]=> string(15) "Matthias Reuter" ["created_at"]=> int(1389547027) ["updated_at"]=> int(1389547027) ["app_id"]=> NULL ["payment"]=> array(2) { [0]=> array(12) { ["id"]=> string(28) "pay_1a5ff8....." ["type"]=> string(10) "creditcard" ["client"]=> string(27) "client_dbe16....." ["card_type"]=> string(4) "visa" ["country"]=> NULL ["expire_month"]=> string(2) "12" ["expire_year"]=> string(4) "2020" ["card_holder"]=> string(10) "dfgdfgdfgd" ["last4"]=> string(4) "1111" ["created_at"]=> int(1389547027) ["updated_at"]=> int(1389547028) ["app_id"]=> NULL } [1]=> array(12) { ["id"]=> string(28) "pay_4e375....." ["type"]=> string(10) "creditcard" ["client"]=> string(27) "client_dbe164....." ["card_type"]=> string(4) "visa" ["country"]=> NULL ["expire_month"]=> string(2) "12" ["expire_year"]=> string(4) "2020" ["card_holder"]=> string(13) "dfgdfgdfgdfgd" ["last4"]=> string(4) "1111" ["created_at"]=> int(1389663369) ["updated_at"]=> int(1389663380) ["app_id"]=> NULL } } ["subscription"]=> array(2) { [0]=> string(24) "sub_fcc4....." [1]=> string(24) "sub_b71a....." } } } ["created_at"]=> int(1389816435) ["app_id"]=> NULL } } */ //error_log(var_export($event_json,true)."\n\n", 3, PAYMILL_DIR.'lib/debug/PHP_errors.log'); // get subscription info, if available if (isset($paymill_sub_id) && strlen($paymill_sub_id) > 0) { $sql = $wpdb->prepare('SELECT * FROM ' . $wpdb->prefix . 'paymill_subscriptions WHERE paymill_sub_id=%s', array($paymill_sub_id)); $sub_cache = $wpdb->get_results($sql, ARRAY_A); $sub_cache = $sub_cache[0]; /* output example: SELECT * FROM wp_paymill_subscriptions WHERE paymill_sub_id="sub_b71adbf5e097bbe5ba80" */ error_log("\n\n" . $sql . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); /* output example: 1 30 */ //error_log($sub_cache['woo_user_id']."\n\n".$sub_cache['woo_offer_id']."\n\n", 3, PAYMILL_DIR.'lib/debug/PHP_errors.log'); $subscription = WC_Subscriptions_Manager::get_subscription($sub_cache['woo_offer_id']); // update subscriptions when webhook is triggered if (isset($sub_cache['woo_offer_id']) && strlen($sub_cache['woo_offer_id']) > 0) { // subscription successfully created if ($event_json['event']['event_type'] == 'subscription.created') { } // tell WooCommerce when payment for subscription is successfully processed if ($event_json['event']['event_type'] == 'subscription.succeeded') { /* example data WC_Subscriptions_Manager::get_subscription: array(15) { ["order_id"]=> string(3) "201" ["product_id"]=> string(2) "91" ["variation_id"]=> string(0) "" ["status"]=> string(6) "active" ["period"]=> string(3) "day" ["interval"]=> string(1) "1" ["length"]=> string(2) "12" ["start_date"]=> string(19) "2014-01-12 17:17:10" ["expiry_date"]=> string(19) "2014-01-24 17:17:10" ["end_date"]=> string(1) "0" ["trial_expiry_date"]=> string(1) "0" ["failed_payments"]=> string(1) "0" ["completed_payments"]=> array(1) { [0]=> string(19) "2014-01-12 17:17:10" } ["suspension_count"]=> string(1) "0" ["last_payment_date"]=> string(19) "2014-01-12 17:17:10" } */ error_log(var_export($subscription, true) . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); // prevent multiple subscription renewals because of multiple webhook attempts. $whole_period = 0; switch ($subscription['period']) { case 'day': default: $whole_period = intval($subscription['interval']) * 86400; break; case 'week': $whole_period = intval($subscription['interval']) * 604800; break; case 'month': $whole_period = intval($subscription['interval']) * 2160000; // using 25 days to prevent problems with shorter months break; case 'year': $whole_period = intval($subscription['interval']) * 30240000; // using 350 days to prevent any timezone problems whatsoever break; } if (count($subscription['completed_payments']) >= 1) { if (strtotime(date(DATE_RFC822)) > strtotime($subscription['last_payment_date']) + $whole_period - 18000) { // minus 5 hours to prevent any problems with pending triggers $order = new WC_Order($subscription['order_id']); //WC_Subscriptions_Manager::process_subscription_payments_on_order($order, $subscription['product_id']); WC_Subscriptions_Manager::process_subscription_payments_on_order($order); } } else { $order = new WC_Order($subscription['order_id']); $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($subscription['order_id']); } WC_Subscriptions_Manager::set_next_payment_date($sub_cache['woo_offer_id'], $order->customer_user); } // cancel subscription, as it was deleted through Paymill dashboard if ($event_json['event']['event_type'] == 'subscription.deleted') { $sql = $wpdb->prepare('DELETE FROM ' . $wpdb->prefix . 'paymill_subscriptions WHERE woo_user_id=%s AND woo_offer_id=%s', array($sub_cache['woo_user_id'], $sub_cache['woo_offer_id'])); $wpdb->query($sql); error_log("\n\n" . $sql . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); //WC_Subscriptions_Manager::cancel_subscriptions_for_order( $order ); WC_Subscriptions_Manager::cancel_subscription($sub_cache['woo_user_id'], $sub_cache['woo_offer_id']); } // tell WC that payment failure occured if ($event_json['event']['event_type'] == 'subscription.failed') { WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($subscription['order_id'], $subscription['product_id']); } } } error_log(date(DATE_RFC822) . ' - Webhook ' . $event_json['event']['event_type'] . ' finished - end processing' . "\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); error_log("\n\n########################################################################################################################\n\n", 3, PAYMILL_DIR . 'lib/debug/PHP_errors.log'); } }
/** * Process the subscription * * Saves the card, if needed, and activates the subscription. This is called when the subscription is first purchased * * @param int $order_id * * @return array * * @since 0.6.0 */ public function process_subscription($order_id) { global $woocommerce; $order = new WC_Order($order_id); $user_id = get_current_user_id(); $profile_id = $this->profiles_enabled ? $this->saved_cards->get_user_profile_id($user_id) : false; $token = isset($_POST['card_connect_token']) ? wc_clean($_POST['card_connect_token']) : false; $card_name = isset($_POST['card_connect-card-name']) ? wc_clean($_POST['card_connect-card-name']) : false; $store_new_card = isset($_POST['card_connect-save-card']) ? wc_clean($_POST['card_connect-save-card']) : false; $saved_card_id = isset($_POST['card_connect-cards']) ? wc_clean($_POST['card_connect-cards']) : false; $card_alias = isset($_POST['card_connect-new-card-alias']) ? wc_clean($_POST['card_connect-new-card-alias']) : false; if (!$token && !$saved_card_id) { wc_add_notice(__('Payment error: ', 'woothemes') . 'Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'error'); return; } $request = array('merchid' => $this->api_credentials['mid'], 'cvv2' => wc_clean($_POST['card_connect-card-cvc']), 'amount' => $order->order_total * 100, 'currency' => "USD", 'orderid' => sprintf(__('%s - Order #%s', 'woocommerce'), esc_html(get_bloginfo('name', 'display')), $order->get_order_number()), 'name' => $card_name ? $card_name : trim($order->billing_first_name . ' ' . $order->billing_last_name), 'street' => $order->billing_address_1, 'city' => $order->billing_city, 'region' => $order->billing_state, 'country' => $order->billing_country, 'postal' => $order->billing_postcode, 'capture' => $this->mode === 'capture' ? 'Y' : 'N'); if ($saved_card_id) { // Payment is using a stored card, no token or account number to pass $request['profile'] = "{$profile_id}/{$saved_card_id}"; } else { // Either a basic purchase or adding a new card. Either way, include the expiration date $request['expiry'] = preg_replace('/[^\\d]/i', '', wc_clean($_POST['card_connect-card-expiry'])); // Adding an additional card to an existing profile -- This requires a separate API call, handled in `add_account_to_profile` if ($profile_id) { $request['profile'] = $profile_id; // The `token` key isn't used by the Auth/Capture service however it's ignored if it's passed as `account` when updating profiles $request['token'] = $token; // Get the new card's account id, remove the token key $new_account_id = $this->saved_cards->add_account_to_profile($user_id, $card_alias, $request); unset($request['token']); // Overwrite the profile field with the `profile/acctid` format required by the Auth/Capture service $request['profile'] = "{$profile_id}/{$new_account_id}"; // Adding a new card, no existing profile } else { $request['profile'] = 'Y'; $request['account'] = $token; } } //Authorizes transaction to be processed if (!is_null($this->get_cc_client())) { $response = $this->get_cc_client()->authorizeTransaction($request); } else { wc_add_notice(__('Payment error: ', 'woothemes') . 'CardConnect is not configured! ', 'error'); $order->add_order_note('CardConnect is not configured!'); return; } // 'A' response is for accepted if ('A' === $response['respstat']) { // Need to verify customer data before marking complete $order_verification = $this->verify_customer_data($response); if (!$order_verification['is_valid']) { $request = array('merchid' => $this->api_credentials['mid'], 'currency' => 'USD', 'retref' => $response['retref']); if (!is_null($this->get_cc_client())) { $void_response = $this->get_cc_client()->voidTransaction($request); } else { wc_add_notice(__('Payment error: ', 'woothemes') . 'CardConnect is not configured! ', 'error'); $order->add_order_note('CardConnect is not configured!'); return; } if ($void_response['authcode'] === 'REVERS') { $order->update_status('failed', __('Payment Failed', 'cardconnect-payment-gateway')); foreach ($order_verification['errors'] as $error) { $order->add_order_note(sprintf(__($error, 'woocommerce'))); wc_add_notice(__('Payment error: ', 'woothemes') . $error, 'error'); } return; } } // Mark order complete and begin completion process $order->payment_complete($response['retref']); update_post_meta($order_id, '_transaction_id', $response['retref']); // Reduce stock levels $order->reduce_order_stock(); // Remove cart $woocommerce->cart->empty_cart(); $order->add_order_note(sprintf(__('CardConnect payment approved (ID: %s, Authcode: %s)', 'woocommerce'), $response['retref'], $response['authcode'])); // First time this customer has saved a card, pull the response fields and store in user meta if (!$saved_card_id && !$profile_id) { $this->saved_cards->set_user_profile_id($user_id, $response['profileid']); $this->saved_cards->save_user_card($user_id, array($response['acctid'] => $card_alias)); } // Activate the subscription WC_Subscriptions_Manager::activate_subscriptions_for_order($order); // Return thankyou redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } else { if ('C' === $response['respstat']) { wc_add_notice(__('Payment error: ', 'woothemes') . 'Order Declined : ' . $response['resptext'], 'error'); $order->add_order_note(sprintf(__('CardConnect declined transaction. Response: %s', 'woocommerce'), $response['resptext'])); } else { wc_add_notice(__('Payment error: ', 'woothemes') . 'An error prevented this transaction from completing. Please confirm your information and try again.', 'error'); $order->add_order_note(sprintf(__('CardConnect failed transaction. Response: %s', 'woocommerce'), $response['resptext'])); } } $order->update_status('failed', __('Payment Failed', 'cardconnect-payment-gateway')); return; }
/** * When a PayPal IPN messaged is received for a subscription transaction, * check the transaction details and * * @since 1.0 */ public static function process_paypal_ipn_request($transaction_details) { global $wpdb; $transaction_details = stripslashes_deep($transaction_details); if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) { return; } if (empty($transaction_details['custom']) || empty($transaction_details['invoice'])) { return; } // Get the $order_id & $order_key with backward compatibility extract(self::get_order_id_and_key($transaction_details)); $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']); if (self::$debug) { self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']); } if (self::$debug) { self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true)); } $order = new WC_Order($order_id); // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the order by order key if (!isset($order->id)) { $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'"); $order = new WC_Order($order_id); } if ($order->order_key !== $order_key) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.'); } return; } if ('paypal' != $order->recurring_payment_method) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, recurring payment method has changed.'); } return; } if (isset($transaction_details['ipn_track_id'])) { // Make sure the IPN request has not already been handled $handled_ipn_requests = get_post_meta($order_id, '_paypal_ipn_tracking_ids', true); if (empty($handled_ipn_requests)) { $handled_ipn_requests = array(); } // The 'ipn_track_id' is not a unique ID and is shared between different transaction types, so create a unique ID by prepending the transaction type $transaction_id = $transaction_details['txn_type'] . '_' . $transaction_details['ipn_track_id']; if (in_array($transaction_id, $handled_ipn_requests)) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: This IPN message has already been correctly handled.'); } return; } } if (isset($transaction_details['subscr_id'])) { update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); } // Get the subscription this IPN message relates to $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order); $subscription_item = array_pop($subscriptions_in_order); $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, WC_Subscriptions_Order::get_items_product_id($subscription_item)); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $is_first_payment = empty($subscription['completed_payments']) ? true : false; if ('switched' === $subscription['status']) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, subscription has been switched.'); } return; } switch ($transaction_details['txn_type']) { case 'subscr_signup': // Store PayPal Details update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); $default_invoice_string = self::$paypal_settings['invoice_prefix'] . ltrim($order->get_order_number(), '#'); // If the invoice ID doesn't match the default invoice ID and contains the string '-wcscpm-', the IPN is for a subscription payment method change if ($default_invoice_string != $transaction_details['invoice'] && false !== strpos($transaction_details['invoice'], '-wcscpm-')) { $is_payment_change = true; } else { $is_payment_change = false; } $switched_subscription_key = get_post_meta($order_id, '_switched_subscription_key', true); $no_initial_payment = 0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0 ? true : false; // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription if (!$is_payment_change && (!empty($switched_subscription_key) || $no_initial_payment)) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } // Payment completed if ($is_payment_change) { $order->add_order_note(__('IPN subscription payment method changed.', WC_Subscriptions::$text_domain)); } else { $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain)); } if (self::$debug) { if ($is_payment_change) { self::$log->add('paypal', 'IPN subscription payment method changed for order ' . $order_id); } else { self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id); } } break; case 'subscr_payment': if ('completed' == strtolower($transaction_details['payment_status'])) { // Store PayPal Details update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']); // Subscription Payment completed $order->add_order_note(__('IPN subscription payment completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id); } // First payment on order, process payment & activate subscription if ($is_first_payment) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } else { // We don't need to reactivate the subscription because Subs didn't suspend it remove_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); WC_Subscriptions_Manager::process_subscription_payments_on_order($order); add_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); } } elseif ('failed' == strtolower($transaction_details['payment_status'])) { // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id); } // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']); } } break; case 'subscr_cancel': if ('true' == get_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal', true)) { // The flag has served its purpose delete_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal'); if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancellation request ignored as changing PayPal to PayPal, for order ' . $order_id); } } else { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); // Subscription Cancellation Completed $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id); } } break; case 'subscr_eot': // Subscription ended, either due to failed payments or expiration $subscription_length = WC_Subscriptions_Order::get_subscription_length($order); // PayPal fires the 'subscr_eot' notice immediately if a subscription is only for one billing period, so ignore the request when we only have one billing period if (1 != $subscription_length && $subscription_length != WC_Subscriptions_Order::get_subscription_interval($order)) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription end-of-term for order ' . $order_id); } // Record subscription ended $order->add_order_note(__('IPN subscription end-of-term for order.', WC_Subscriptions::$text_domain)); // Ended due to failed payments so cancel the subscription if (gmdate('U') + 24 * 60 * 60 < strtotime(WC_Subscriptions_Manager::get_subscription_expiration_date(WC_Subscriptions_Manager::get_subscription_key($order->id), $order->customer_user))) { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); } else { WC_Subscriptions_Manager::expire_subscriptions_for_order($order); } } break; case 'subscr_failed': // Subscription sign up failed if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failure for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failure.', WC_Subscriptions::$text_domain)); // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order_id); break; } // Store the transaction ID to avoid handling requests duplicated by PayPal if (isset($transaction_details['ipn_track_id'])) { $handled_ipn_requests[] = $transaction_id; update_post_meta($order_id, '_paypal_ipn_tracking_ids', $handled_ipn_requests); } // Prevent default IPN handling for subscription txn_types exit; }
/** * When a PayPal IPN messaged is received for a subscription transaction, * check the transaction details and * * @since 1.0 */ public static function process_paypal_ipn_request($transaction_details) { global $wpdb; $transaction_details = stripslashes_deep($transaction_details); if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) { return; } // Get the $order_id & $order_key with backward compatibility extract(self::get_order_id_and_key($transaction_details)); $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']); if (self::$debug) { self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']); } if (self::$debug) { self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true)); } $order = new WC_Order($order_id); // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the order by order key if (!isset($order->id)) { $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'"); $order = new WC_Order($order_id); } if ($order->order_key !== $order_key) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.'); } exit; } if ('paypal' != $order->recurring_payment_method) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, recurring payment method has changed.'); } exit; } if (isset($transaction_details['ipn_track_id'])) { // Make sure the IPN request has not already been handled $handled_ipn_requests = get_post_meta($order_id, '_paypal_ipn_tracking_ids', true); if (empty($handled_ipn_requests)) { $handled_ipn_requests = array(); } // The 'ipn_track_id' is not a unique ID and is shared between different transaction types, so create a unique ID by prepending the transaction type $ipn_id = $transaction_details['txn_type'] . '_' . $transaction_details['ipn_track_id']; if (in_array($ipn_id, $handled_ipn_requests)) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: This IPN message has already been correctly handled.'); } exit; } } if (isset($transaction_details['txn_id'])) { // Make sure the IPN request has not already been handled $handled_transactions = get_post_meta($order_id, '_paypal_transaction_ids', true); if (empty($handled_transactions)) { $handled_transactions = array(); } $transaction_id = $transaction_details['txn_id']; if (isset($transaction_details['txn_type'])) { $transaction_id .= '_' . $transaction_details['txn_type']; } // The same transaction ID is used for different payment statuses, so make sure we handle it only once. See: http://stackoverflow.com/questions/9240235/paypal-ipn-unique-identifier if (isset($transaction_details['payment_status'])) { $transaction_id .= '_' . $transaction_details['payment_status']; } if (in_array($transaction_id, $handled_transactions)) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: This transaction has already been correctly handled.'); } exit; } } // Save the profile ID if it's not a cancellation/expiration request if (isset($transaction_details['subscr_id']) && !in_array($transaction_details['txn_type'], array('subscr_cancel', 'subscr_eot'))) { update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); } // Get the subscription this IPN message relates to $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order); $subscription_item = array_pop($subscriptions_in_order); $product_id = WC_Subscriptions_Order::get_items_product_id($subscription_item); $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $product_id); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); $is_first_payment = empty($subscription['completed_payments']) ? true : false; if ('switched' === $subscription['status']) { if (self::$debug) { self::$log->add('paypal', 'IPN ignored, subscription has been switched.'); } exit; } switch ($transaction_details['txn_type']) { case 'subscr_signup': // Store PayPal Details update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); $default_invoice_string = self::$paypal_settings['invoice_prefix'] . ltrim($order->get_order_number(), '#'); // If the invoice ID doesn't match the default invoice ID and contains the string '-wcscpm-', the IPN is for a subscription payment method change if ($default_invoice_string != $transaction_details['invoice'] && false !== strpos($transaction_details['invoice'], '-wcscpm-')) { $is_payment_change = true; } else { $is_payment_change = false; } $switched_subscription_key = get_post_meta($order_id, '_switched_subscription_key', true); $no_initial_payment = 0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0 ? true : false; // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription if (!$is_payment_change && (!empty($switched_subscription_key) || $no_initial_payment)) { $order->payment_complete(); } // Payment completed if ($is_payment_change) { $old_payment_method = get_post_meta($order->id, '_old_recurring_payment_method', true); // We need to cancel the subscription now that the method has been changed successfully if ('paypal' == $old_payment_method) { $profile_id = get_post_meta($order->id, '_old_paypal_subscriber_id', true); self::cancel_subscription_with_paypal($order, $product_id, $profile_id); } $order->add_order_note(__('IPN subscription payment method changed.', 'woocommerce-subscriptions')); } else { $order->add_order_note(__('IPN subscription sign up completed.', 'woocommerce-subscriptions')); } if (self::$debug) { if ($is_payment_change) { self::$log->add('paypal', 'IPN subscription payment method changed for order ' . $order_id); } else { self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id); } } break; case 'subscr_payment': if ('completed' == strtolower($transaction_details['payment_status'])) { // Store PayPal Details update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']); // Subscription Payment completed $order->add_order_note(__('IPN subscription payment completed.', 'woocommerce-subscriptions')); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id); } // First payment on order, process payment & activate subscription if ($is_first_payment) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); // Ignore the first IPN message if the PDT should have handled it (if it didn't handle it, it will have been dealt with as first payment), but set a flag to make sure we only ignore it once } elseif (count($subscription['completed_payments']) == 1 && !empty(self::$paypal_settings['identity_token']) && 'true' != get_post_meta($order_id, '_paypal_first_ipn_ignored_for_pdt', true)) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment ignored for order ' . $order_id . ' due to PDT previously handling the payment.'); } update_post_meta($order_id, '_paypal_first_ipn_ignored_for_pdt', 'true'); // Process the payment if the subscription is active } elseif (!in_array($subscription['status'], array('cancelled', 'expired', 'switched', 'trash'))) { // We don't need to reactivate the subscription because Subs didn't suspend it remove_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); WC_Subscriptions_Manager::process_subscription_payments_on_order($order); // Make sure the next payment date is sync with when PayPal processes the payments WC_Subscriptions_Manager::set_next_payment_date($subscription_key, $order->customer_user); add_action('reactivated_subscription_paypal', __CLASS__ . '::reactivate_subscription_with_paypal', 10, 2); } } elseif ('failed' == strtolower($transaction_details['payment_status'])) { // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failed.', 'woocommerce-subscriptions')); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id); } // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']); } } break; case 'subscr_cancel': // Make sure the subscription hasn't been linked to a new payment method if ($transaction_details['subscr_id'] != self::get_subscriptions_paypal_id($order)) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancellation request ignored - new PayPal Profile ID linked to this subscription, for order ' . $order_id); } } else { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); // Subscription Cancellation Completed $order->add_order_note(__('IPN subscription cancelled for order.', 'woocommerce-subscriptions')); if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id); } } break; case 'subscr_eot': // Subscription ended, either due to failed payments or expiration if (self::$debug) { self::$log->add('paypal', 'IPN EOT request ignored for order ' . $order_id); } break; case 'subscr_failed': // Subscription sign up failed if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failure for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failure.', 'woocommerce-subscriptions')); // First payment on order, don't generate a renewal order if ($is_first_payment) { remove_action('processed_subscription_payment_failure', 'WC_Subscriptions_Renewal_Order::generate_failed_payment_renewal_order', 10, 2); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); break; } // Store the transaction IDs to avoid handling requests duplicated by PayPal if (isset($transaction_details['ipn_track_id'])) { $handled_ipn_requests[] = $ipn_id; update_post_meta($order_id, '_paypal_ipn_tracking_ids', $handled_ipn_requests); } if (isset($transaction_details['txn_id'])) { $handled_transactions[] = $transaction_id; update_post_meta($order_id, '_paypal_transaction_ids', $handled_transactions); } // Prevent default IPN handling for subscription txn_types exit; }
/** * When a PayPal IPN messaged is received for a subscription transaction, * check the transaction details and * * @since 1.0 */ public static function process_paypal_ipn_request($transaction_details) { if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) { return; } if (empty($transaction_details['custom']) || empty($transaction_details['invoice'])) { return; } // Get the $order_id & $order_key with backward compatibility extract(self::get_order_id_and_key($transaction_details)); $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']); if (self::$debug) { self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']); } if (self::$debug && 'subscr_modify' == $transaction_details['txn_type']) { self::$log->add('paypal', 'Subscription subscr_modify details: ' . print_r($transaction_details, true)); } $order = new WC_Order($order_id); if ($order->order_key !== $order_key) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.'); } return; } switch ($transaction_details['txn_type']) { case 'subscr_signup': // Store PayPal Details update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); // Payment completed if (!in_array($order->status, array('completed', 'processing'))) { $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id); } $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } break; case 'subscr_payment': if ('completed' == strtolower($transaction_details['payment_status'])) { // Store PayPal Details update_post_meta($order_id, 'Transaction ID', $transaction_details['txn_id']); update_post_meta($order_id, 'Payer first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer last name', $transaction_details['last_name']); update_post_meta($order_id, 'Payment type', $transaction_details['payment_type']); // Subscription Payment completed $order->add_order_note(__('IPN subscription payment completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id); } WC_Subscriptions_Manager::process_subscription_payments_on_order($order); } elseif ('failed' == strtolower($transaction_details['payment_status'])) { // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']); } } break; case 'subscr_cancel': if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain)); WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); break; case 'subscr_eot': // Subscription ended if (self::$debug) { self::$log->add('paypal', 'IPN subscription expired for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription expired for order.', WC_Subscriptions::$text_domain)); WC_Subscriptions_Manager::expire_subscriptions_for_order($order); break; case 'subscr_failed': // Subscription sign up failed if (self::$debug) { self::$log->add('paypal', 'IPN subscription sign up failure for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription sign up failure.', WC_Subscriptions::$text_domain)); WC_Subscriptions_Manager::failed_subscription_sign_ups_for_order($order); break; } // Prevent default IPN handling for subscription txn_types exit; }
/** * Process the subscription * * @param int $order_id * @return array */ public function process_subscription($order_id, $retry = true) { $order = new WC_Order($order_id); $stripe_token = isset($_POST['stripe_token']) ? wc_clean($_POST['stripe_token']) : ''; $card_id = isset($_POST['stripe_card_id']) ? wc_clean($_POST['stripe_card_id']) : ''; $customer_id = is_user_logged_in() ? get_user_meta(get_current_user_id(), '_stripe_customer_id', true) : 0; if (!$customer_id || !is_string($customer_id)) { $customer_id = 0; } // Use Stripe CURL API for payment try { $post_data = array(); // Pay using a saved card! if ($card_id !== 'new' && $card_id && $customer_id) { $post_data['customer'] = $customer_id; $post_data['card'] = $card_id; } elseif (empty($stripe_token)) { $error_msg = __('Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'woocommerce-gateway-stripe'); if ($this->testmode) { $error_msg .= ' ' . __('Developers: Please make sure that you are including jQuery and there are no JavaScript errors on the page.', 'woocommerce-gateway-stripe'); } throw new Exception($error_msg); } // Save token if (!$customer_id) { $customer_id = $this->add_customer($order, $stripe_token); if (is_wp_error($customer_id)) { throw new Exception($customer_id->get_error_message()); } unset($post_data['card']); $post_data['customer'] = $customer_id; } elseif (!$card_id || $card_id === 'new') { $card_id = $this->add_card($customer_id, $stripe_token); if (is_wp_error($card_id)) { // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id and retry. if ('customer' === $card_id->get_error_code() && $retry) { delete_user_meta(get_current_user_id(), '_stripe_customer_id'); return $this->process_subscription($order_id, false); // false to prevent retry again (endless loop) } throw new Exception($card_id->get_error_message()); } $post_data['card'] = $card_id; $post_data['customer'] = $customer_id; } // Store the ID in the order update_post_meta($order_id, '_stripe_customer_id', $customer_id); update_post_meta($order_id, '_stripe_card_id', $card_id); $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order); if ($initial_payment > 0) { $payment_response = $this->process_subscription_payment($order, $initial_payment); } if (isset($payment_response) && is_wp_error($payment_response)) { throw new Exception($payment_response->get_error_message()); } else { if (isset($payment_response->balance_transaction) && isset($payment_response->balance_transaction->fee)) { $fee = number_format($payment_response->balance_transaction->fee / 100, 2, '.', ''); update_post_meta($order->id, 'Stripe Fee', $fee); update_post_meta($order->id, 'Net Revenue From Stripe', $order->order_total - $fee); } // Payment complete $order->payment_complete($payment_response->id); // Remove cart WC()->cart->empty_cart(); // Activate subscriptions WC_Subscriptions_Manager::activate_subscriptions_for_order($order); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } catch (Exception $e) { wc_add_notice(__('Error:', 'woocommerce-gateway-stripe') . ' "' . $e->getMessage() . '"', 'error'); return; } }
/** * When a PayPal IPN messaged is received for a subscription transaction, * check the transaction details and * * @since 1.0 */ public static function process_paypal_ipn_request($transaction_details) { if (!in_array($transaction_details['txn_type'], array('subscr_signup', 'subscr_payment', 'subscr_cancel', 'subscr_eot', 'subscr_failed', 'subscr_modify'))) { return; } if (empty($transaction_details['custom']) || empty($transaction_details['invoice'])) { return; } // Get the $order_id & $order_key with backward compatibility extract(self::get_order_id_and_key($transaction_details)); $transaction_details['txn_type'] = strtolower($transaction_details['txn_type']); if (self::$debug) { self::$log->add('paypal', 'Subscription Transaction Type: ' . $transaction_details['txn_type']); } if (self::$debug) { self::$log->add('paypal', 'Subscription transaction details: ' . print_r($transaction_details, true)); } $order = new WC_Order($order_id); // We have an invalid $order_id, probably because invoice_prefix has changed since the subscription was first created, so get the if (!isset($order->id)) { $order_id = function_exists('woocommerce_get_order_id_by_order_key') ? woocommerce_get_order_id_by_order_key($order_key) : $wpdb->get_var("SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_order_key' AND meta_value = '{$order_key}'"); $order = new WC_Order($order_id); } if ($order->order_key !== $order_key) { if (self::$debug) { self::$log->add('paypal', 'Subscription IPN Error: Order Key does not match invoice.'); } return; } switch ($transaction_details['txn_type']) { case 'subscr_signup': // Store PayPal Details update_post_meta($order_id, 'Payer PayPal address', $transaction_details['payer_email']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Subscriber ID', $transaction_details['subscr_id']); // Payment completed $order->add_order_note(__('IPN subscription sign up completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription sign up completed for order ' . $order_id); } // When there is a free trial & no initial payment amount, we need to mark the order as paid and activate the subscription if (0 == WC_Subscriptions_Order::get_total_initial_payment($order) && WC_Subscriptions_Order::get_subscription_trial_length($order) > 0) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } break; case 'subscr_payment': if ('completed' == strtolower($transaction_details['payment_status'])) { // Store PayPal Details update_post_meta($order_id, 'PayPal Transaction ID', $transaction_details['txn_id']); update_post_meta($order_id, 'Payer PayPal first name', $transaction_details['first_name']); update_post_meta($order_id, 'Payer PayPal last name', $transaction_details['last_name']); update_post_meta($order_id, 'PayPal Payment type', $transaction_details['payment_type']); // Subscription Payment completed $order->add_order_note(__('IPN subscription payment completed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment completed for order ' . $order_id); } $subscriptions_in_order = WC_Subscriptions_Order::get_recurring_items($order); $subscription_item = array_pop($subscriptions_in_order); $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order->id, $subscription_item['id']); $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key, $order->customer_user); // First payment on order, process payment & activate subscription if (empty($subscription['completed_payments'])) { $order->payment_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($order); } else { WC_Subscriptions_Manager::process_subscription_payments_on_order($order); } } elseif ('failed' == strtolower($transaction_details['payment_status'])) { // Subscription Payment completed $order->add_order_note(__('IPN subscription payment failed.', WC_Subscriptions::$text_domain)); if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment failed for order ' . $order_id); } WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { if (self::$debug) { self::$log->add('paypal', 'IPN subscription payment notification received for order ' . $order_id . ' with status ' . $transaction_details['payment_status']); } } break; case 'subscr_cancel': if (self::$debug) { self::$log->add('paypal', 'IPN subscription cancelled for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription cancelled for order.', WC_Subscriptions::$text_domain)); WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); break; case 'subscr_eot': // Subscription ended, either due to failed payments or expiration // PayPal fires the 'subscr_eot' notice immediately if a subscription is only for one billing period, so ignore the request when we only have one billing period if (1 != WC_Subscriptions_Order::get_subscription_length($order)) { if (self::$debug) { self::$log->add('paypal', 'IPN subscription end-of-term for order ' . $order_id); } // Record subscription ended $order->add_order_note(__('IPN subscription end-of-term for order.', WC_Subscriptions::$text_domain)); // Ended due to failed payments so cancel the subscription if (time() < strtotime(WC_Subscriptions_Manager::get_subscription_expiration_date(WC_Subscriptions_Manager::get_subscription_key($order->id), $order->customer_user))) { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order); } else { WC_Subscriptions_Manager::expire_subscriptions_for_order($order); } } break; case 'subscr_failed': // Subscription sign up failed if (self::$debug) { self::$log->add('paypal', 'IPN subscription sign up failure for order ' . $order_id); } // Subscription Payment completed $order->add_order_note(__('IPN subscription sign up failure.', WC_Subscriptions::$text_domain)); WC_Subscriptions_Manager::failed_subscription_sign_ups_for_order($order); break; } // Prevent default IPN handling for subscription txn_types exit; }