/**
  * Fire a gateway specific hook for when a subscription payment is due.
  * 
  * @since 1.0
  */
 public static function gateway_scheduled_subscription_payment($user_id, $subscription_key)
 {
     $subscription = WC_Subscriptions_Manager::get_users_subscription($user_id, $subscription_key);
     $order = new WC_Order($subscription['order_id']);
     $amount_to_charge = WC_Subscriptions_Order::get_recurring_total($order);
     $outstanding_payments = WC_Subscriptions_Order::get_outstanding_balance($order, $subscription['product_id']);
     if ($outstanding_payments > 0) {
         $amount_to_charge += $outstanding_payments;
     }
     do_action('scheduled_subscription_payment_' . $order->payment_method, $amount_to_charge, $order, $subscription['product_id']);
 }
 /**
  * Fire a gateway specific hook for when a subscription payment is due.
  *
  * @since 1.0
  */
 public static function gateway_scheduled_subscription_payment($user_id, $subscription_key)
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     $order = new WC_Order($subscription['order_id']);
     if (!WC_Subscriptions_Order::requires_manual_renewal($order)) {
         $amount_to_charge = WC_Subscriptions_Order::get_recurring_total($order);
         $outstanding_payments = WC_Subscriptions_Order::get_outstanding_balance($order, $subscription['product_id']);
         if ('yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_add_outstanding_balance', 'no') && $outstanding_payments > 0) {
             $amount_to_charge += $outstanding_payments;
         }
         do_action('scheduled_subscription_payment_' . $order->recurring_payment_method, $amount_to_charge, $order, $subscription['product_id']);
     }
 }
 /**
  * When a scheduled subscription payment hook is fired, automatically process the subscription payment
  * if the amount is for $0 (and therefore, there is no payment to be processed by a gateway, and likely
  * no gateway used on the initial order).
  *
  * If a subscription has a $0 recurring total and is not already active (after being actived by something else
  * handling the 'scheduled_subscription_payment' with the default priority of 10), then this function will call
  * @see self::process_subscription_payment() to reactive the subscription, generate a renewal order etc.
  *
  * @param $user_id int The id of the user who the subscription belongs to
  * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key()
  * @since 1.3.2
  */
 public static function maybe_process_subscription_payment($user_id, $subscription_key)
 {
     $subscription = self::get_users_subscription($user_id, $subscription_key);
     $amount_to_charge = WC_Subscriptions_Order::get_recurring_total($subscription['order_id']);
     // Don't reschedule for cancelled, suspended or expired subscriptions
     if ($amount_to_charge == 0 && !in_array($subscription['status'], array('expired', 'cancelled', 'active'))) {
         // Process payment, which will generate renewal orders, reactive the subscription etc.
         self::process_subscription_payment($user_id, $subscription_key);
     }
 }
Пример #4
0
 private function processSubscriptions()
 {
     global $wpdb;
     // check wether subscriptions addon is activated
     if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($this->order)) {
         $products = $this->order->get_items();
         foreach ($products as $product) {
             if (is_array($product) && isset($product['product_id']) && intval($product['product_id']) > 0 && isset($product['subscription_period']) && $product['subscription_period'] != '') {
                 // product is a subscription?
                 $woo_sub_key = WC_Subscriptions_Manager::get_subscription_key($this->order_id, $product['product_id']);
                 // required vars
                 $amount = floatval(WC_Subscriptions_Order::get_recurring_total($this->order)) * 100;
                 $currency = get_woocommerce_currency();
                 $interval = intval($product['subscription_interval']);
                 $period = strtoupper($product['subscription_period']);
                 $length = strtoupper($product['subscription_length']);
                 if ($length > 0) {
                     $periodOfValidity = $length . ' ' . $period;
                 } else {
                     $periodOfValidity = false;
                 }
                 $trial_end = strtotime(WC_Subscriptions_Product::get_trial_expiration_date($product['product_id'], get_gmt_from_date($this->order->order_date)));
                 if ($trial_end === false) {
                     $trial_time = 0;
                 } else {
                     $datediff = $trial_end - time();
                     $trial_time = ceil($datediff / (60 * 60 * 24));
                 }
                 // md5 name
                 $woo_sub_md5 = md5($amount . $currency . $interval . $trial_time);
                 // get offer
                 $name = 'woo_' . $product['product_id'] . '_' . $woo_sub_md5;
                 $offer = $this->subscriptions->offerGetDetailByName($name);
                 // check wether offer exists in paymill
                 if ($offer === false) {
                     // offer does not exist in paymill yet, create it
                     $params = array('amount' => $amount, 'currency' => $currency, 'interval' => $interval . ' ' . $period, 'name' => $name, 'trial_period_days' => intval($trial_time));
                     $offer = $this->subscriptions->offerCreate($params);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                 }
                 // create user subscription
                 $user_sub = $this->subscriptions->create($this->clientClass->getCurrentClientID(), $offer, $this->paymentClass->getPaymentID(), isset($_POST['paymill_delivery_date']) ? $_POST['paymill_delivery_date'] : false, $periodOfValidity);
                 if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                     //maybe offer cache is outdated, recache and try again
                     $GLOBALS['paymill_loader']->paymill_errors->reset();
                     // reset error status
                     $this->subscriptions->offerGetList(true);
                     $params = array('amount' => $amount, 'currency' => $currency, 'interval' => $interval . ' ' . $period, 'name' => $name, 'trial_period_days' => intval($trial_time));
                     $offer = $this->subscriptions->offerCreate($params);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                     $user_sub = $this->subscriptions->create($this->clientClass->getCurrentClientID(), $offer, $this->paymentClass->getPaymentID(), isset($_POST['paymill_delivery_date']) ? $_POST['paymill_delivery_date'] : false, $periodOfValidity);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                 }
                 $wpdb->query($wpdb->prepare('INSERT INTO ' . $wpdb->prefix . 'paymill_subscriptions (paymill_sub_id, woo_user_id, woo_offer_id) VALUES (%s, %s, %s)', array($user_sub, get_current_user_id(), $woo_sub_key)));
                 // subscription successful
                 do_action('paymill_woocommerce_subscription_created', array('product_id' => $product['product_id'], 'offer_id' => $offer));
                 return true;
             }
         }
     } else {
         return true;
     }
 }
 /**
  * Override the default PayPal standard args in WooCommerce for subscription purchases.
  *
  * Based on the HTML Variables documented here: https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU
  *
  * @since 1.0
  */
 public static function paypal_standard_subscription_args($paypal_args)
 {
     extract(self::get_order_id_and_key($paypal_args));
     if (WC_Subscriptions_Order::order_contains_subscription($order_id) && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
         $order = new WC_Order($order_id);
         $order_items = $order->get_items();
         // Only one subscription allowed in the cart when PayPal Standard is active
         $product = $order->get_product_from_item(array_pop($order_items));
         // It's a subscription
         $paypal_args['cmd'] = '_xclick-subscriptions';
         if (count($order->get_items()) > 1) {
             foreach ($order->get_items() as $item) {
                 if ($item['qty'] > 1) {
                     $item_names[] = $item['qty'] . ' x ' . $item['name'];
                 } else {
                     if ($item['qty'] > 0) {
                         $item_names[] = $item['name'];
                     }
                 }
             }
             $paypal_args['item_name'] = sprintf(__('Order %s', WC_Subscriptions::$text_domain), $order->get_order_number());
         } else {
             $paypal_args['item_name'] = $product->get_title();
         }
         $unconverted_periods = array('billing_period' => WC_Subscriptions_Order::get_subscription_period($order), 'trial_period' => WC_Subscriptions_Order::get_subscription_trial_period($order));
         $converted_periods = array();
         // Convert period strings into PayPay's format
         foreach ($unconverted_periods as $key => $period) {
             switch (strtolower($period)) {
                 case 'day':
                     $converted_periods[$key] = 'D';
                     break;
                 case 'week':
                     $converted_periods[$key] = 'W';
                     break;
                 case 'year':
                     $converted_periods[$key] = 'Y';
                     break;
                 case 'month':
                 default:
                     $converted_periods[$key] = 'M';
                     break;
             }
         }
         $price_per_period = WC_Subscriptions_Order::get_recurring_total($order);
         $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order);
         $subscription_length = WC_Subscriptions_Order::get_subscription_length($order);
         $subscription_installments = $subscription_length / $subscription_interval;
         $is_payment_change = WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment;
         $is_switch_order = WC_Subscriptions_Switcher::order_contains_subscription_switch($order->id);
         $sign_up_fee = $is_payment_change ? 0 : WC_Subscriptions_Order::get_sign_up_fee($order);
         $initial_payment = $is_payment_change ? 0 : WC_Subscriptions_Order::get_total_initial_payment($order);
         if ($is_payment_change) {
             // Add a nonce to the order ID to avoid "This invoice has already been paid" error when changing payment method to PayPal when it was previously PayPal
             $paypal_args['invoice'] = $paypal_args['invoice'] . '-wcscpm-' . wp_create_nonce();
             // Set a flag on the order if changing from PayPal *to* PayPal to prevent incorrectly cancelling the subscription
             if ('paypal' == $order->recurring_payment_method) {
                 add_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal', 'true', true);
             }
         }
         // If we're changing the payment date or switching subs, we need to set the trial period to the next payment date & installments to be the number of installments left
         if ($is_payment_change || $is_switch_order) {
             $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id);
             // Give a free trial until the next payment date
             $next_payment_timestamp = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $order->user_id, 'timestamp');
             // When the subscription is on hold
             if ($next_payment_timestamp != false) {
                 $trial_until = self::calculate_trial_periods_until($next_payment_timestamp);
                 $subscription_trial_length = $trial_until['first_trial_length'];
                 $converted_periods['trial_period'] = $trial_until['first_trial_period'];
                 $second_trial_length = $trial_until['second_trial_length'];
                 $second_trial_period = $trial_until['second_trial_period'];
             }
             // If is a payment change, we need to account for completed payments on the number of installments owing
             if ($is_payment_change && $subscription_length > 0) {
                 $subscription_installments -= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key);
             }
         } else {
             $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order);
         }
         if ($subscription_trial_length > 0) {
             // Specify a free trial period
             if ($is_switch_order) {
                 $paypal_args['a1'] = $initial_payment > 0 ? $initial_payment : 0;
             } else {
                 $paypal_args['a1'] = $sign_up_fee > 0 ? $sign_up_fee : 0;
             }
             // Maybe add the sign up fee to the free trial period
             // Trial period length
             $paypal_args['p1'] = $subscription_trial_length;
             // Trial period
             $paypal_args['t1'] = $converted_periods['trial_period'];
             // We need to use a second trial period before we have more than 90 days until the next payment
             if (WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment && $second_trial_length > 0) {
                 $paypal_args['a2'] = 0;
                 $paypal_args['p2'] = $second_trial_length;
                 $paypal_args['t2'] = $second_trial_period;
             }
         } elseif ($sign_up_fee > 0 || $initial_payment !== $price_per_period) {
             // No trial period, so charge sign up fee and per period price for the first period
             if ($subscription_installments == 1) {
                 $param_number = 3;
             } else {
                 $param_number = 1;
             }
             $paypal_args['a' . $param_number] = $initial_payment;
             // Sign Up interval
             $paypal_args['p' . $param_number] = $subscription_interval;
             // Sign Up unit of duration
             $paypal_args['t' . $param_number] = $converted_periods['billing_period'];
         }
         // We have a recurring payment
         if (!isset($param_number) || $param_number == 1) {
             // Subscription price
             $paypal_args['a3'] = $price_per_period;
             // Subscription duration
             $paypal_args['p3'] = $subscription_interval;
             // Subscription period
             $paypal_args['t3'] = $converted_periods['billing_period'];
         }
         // Recurring payments
         if ($subscription_installments == 1 || $sign_up_fee > 0 && $subscription_trial_length == 0 && $subscription_installments == 2) {
             // Non-recurring payments
             $paypal_args['src'] = 0;
         } else {
             $paypal_args['src'] = 1;
             if ($subscription_installments > 0) {
                 if ($sign_up_fee > 0 && $subscription_trial_length == 0) {
                     // An initial period is being used to charge a sign-up fee
                     $subscription_installments--;
                 }
                 $paypal_args['srt'] = $subscription_installments;
             }
         }
         // Don't reattempt failed payments, instead let Subscriptions handle the failed payment
         $paypal_args['sra'] = 0;
         // Force return URL so that order description & instructions display
         $paypal_args['rm'] = 2;
     }
     return $paypal_args;
 }
 /**
  * If a gateway doesn't manage payment schedules, then we should suspend the subscription until it is paid (i.e. for manual payments
  * or token gateways like Stripe). If the gateway does manage the scheduling, then we shouldn't suspend the subscription because a
  * gateway may use batch processing on the time payments are charged and a subscription could end up being incorrectly suspended.
  *
  * @param int $user_id The id of the user whose subscription should be put on-hold.
  * @param string $subscription_key A subscription key of the form created by @see self::get_subscription_key()
  * @since 1.2.5
  */
 public static function maybe_put_subscription_on_hold($user_id, $subscription_key)
 {
     global $woocommerce;
     $subscription = self::get_subscription($subscription_key);
     if (empty($subscription) || $subscription['status'] == 'on-hold') {
         return false;
     }
     $order = new WC_Order($subscription['order_id']);
     $payment_gateways = $woocommerce->payment_gateways->payment_gateways();
     $order_uses_manual_payments = WC_Subscriptions_Order::requires_manual_renewal($order) ? true : false;
     // If the subscription is using manual payments, the gateway isn't active or it manages scheduled payments
     if (0 == WC_Subscriptions_Order::get_recurring_total($order) || $order_uses_manual_payments || !isset($payment_gateways[$order->recurring_payment_method]) || !$payment_gateways[$order->recurring_payment_method]->supports('gateway_scheduled_payments')) {
         self::put_subscription_on_hold($user_id, $subscription_key);
     }
 }
 /**
  * Generate an order to record a subscription payment.
  *
  * This function is hooked to the scheduled subscription payment hook to create a pending
  * order for each scheduled subscription payment.
  *
  * When a payment gateway calls the @see WC_Subscriptions_Manager::process_subscription_payment()
  * @see WC_Order::payment_complete() will be called for the renewal order.
  *
  * @param int $user_id The id of the user who purchased the subscription
  * @param string $subscription_key A subscription key of the form created by @see WC_Subscriptions_Manager::get_subscription_key()
  * @since 1.2
  */
 public static function maybe_generate_manual_renewal_order($user_id, $subscription_key)
 {
     if (WC_Subscriptions_Manager::requires_manual_renewal($subscription_key, $user_id)) {
         $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
         // $0 renewals don't require a pending renewal order, instead a paid renewal order will be created by WC_Subscriptions_Manager::maybe_process_subscription_payment()
         if (WC_Subscriptions_Order::get_recurring_total($subscription['order_id']) > 0) {
             $renewal_order_id = self::generate_renewal_order($subscription['order_id'], $subscription['product_id'], array('new_order_role' => 'child'));
             do_action('woocommerce_generated_manual_renewal_order', $renewal_order_id);
         }
     }
 }
 /**
  * Override the default PayPal standard args in WooCommerce for subscription purchases when
  * automatic payments are enabled and when the recurring order totals is over $0.00 (because
  * PayPal doesn't support subscriptions with a $0 recurring total, we need to circumvent it and
  * manage it entirely ourselves.)
  *
  * Based on the HTML Variables documented here: https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU
  *
  * @since 1.0
  */
 public static function paypal_standard_subscription_args($paypal_args)
 {
     extract(self::get_order_id_and_key($paypal_args));
     $order = new WC_Order($order_id);
     if ($cart_item = WC_Subscriptions_Cart::cart_contains_failed_renewal_order_payment() || false !== WC_Subscriptions_Renewal_Order::get_failed_order_replaced_by($order_id)) {
         $renewal_order = $order;
         $order = WC_Subscriptions_Renewal_Order::get_parent_order($renewal_order);
         $order_contains_failed_renewal = true;
     } else {
         $order_contains_failed_renewal = false;
     }
     if ($order_contains_failed_renewal || WC_Subscriptions_Order::order_contains_subscription($order) && WC_Subscriptions_Order::get_recurring_total($order) > 0 && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
         // Only one subscription allowed in the cart when PayPal Standard is active
         $product = $order->get_product_from_item(array_pop(WC_Subscriptions_Order::get_recurring_items($order)));
         // It's a subscription
         $paypal_args['cmd'] = '_xclick-subscriptions';
         if (count($order->get_items()) > 1) {
             foreach ($order->get_items() as $item) {
                 if ($item['qty'] > 1) {
                     $item_names[] = $item['qty'] . ' x ' . self::paypal_item_name($item['name']);
                 } elseif ($item['qty'] > 0) {
                     $item_names[] = self::paypal_item_name($item['name']);
                 }
             }
             $paypal_args['item_name'] = self::paypal_item_name(sprintf(__('Order %s', 'woocommerce-subscriptions'), $order->get_order_number() . " - " . implode(', ', $item_names)));
         } else {
             $paypal_args['item_name'] = self::paypal_item_name($product->get_title());
         }
         $unconverted_periods = array('billing_period' => WC_Subscriptions_Order::get_subscription_period($order), 'trial_period' => WC_Subscriptions_Order::get_subscription_trial_period($order));
         $converted_periods = array();
         // Convert period strings into PayPay's format
         foreach ($unconverted_periods as $key => $period) {
             switch (strtolower($period)) {
                 case 'day':
                     $converted_periods[$key] = 'D';
                     break;
                 case 'week':
                     $converted_periods[$key] = 'W';
                     break;
                 case 'year':
                     $converted_periods[$key] = 'Y';
                     break;
                 case 'month':
                 default:
                     $converted_periods[$key] = 'M';
                     break;
             }
         }
         $price_per_period = WC_Subscriptions_Order::get_recurring_total($order);
         $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order);
         $subscription_length = WC_Subscriptions_Order::get_subscription_length($order);
         $subscription_installments = $subscription_length / $subscription_interval;
         $is_payment_change = WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment;
         $is_switch_order = WC_Subscriptions_Switcher::order_contains_subscription_switch($order->id);
         $is_synced_subscription = WC_Subscriptions_Synchroniser::order_contains_synced_subscription($order->id);
         $sign_up_fee = $is_payment_change ? 0 : WC_Subscriptions_Order::get_sign_up_fee($order);
         $initial_payment = $is_payment_change ? 0 : WC_Subscriptions_Order::get_total_initial_payment($order);
         if ($is_payment_change) {
             // Add a nonce to the order ID to avoid "This invoice has already been paid" error when changing payment method to PayPal when it was previously PayPal
             $paypal_args['invoice'] = $paypal_args['invoice'] . '-wcscpm-' . wp_create_nonce();
         } elseif ($order_contains_failed_renewal) {
             // Set the invoice details to the original order's invoice but also append a special string and this renewal orders ID so that we can match it up as a failed renewal order payment later
             $paypal_args['invoice'] = self::$invoice_prefix . ltrim($order->get_order_number(), '#') . '-wcsfrp-' . $renewal_order->id;
             $paypal_args['custom'] = serialize(array($order->id, $order->order_key));
         }
         if ($order_contains_failed_renewal) {
             $sign_up_fee = 0;
             $initial_payment = $renewal_order->get_total();
             // Initial payment can be left in case the customer is purchased other products with the payment
             $subscription_trial_length = 0;
             $subscription_installments = max($subscription_installments - WC_Subscriptions_Manager::get_subscriptions_completed_payment_count(WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id)), 0);
             // If we're changing the payment date or switching subs, we need to set the trial period to the next payment date & installments to be the number of installments left
         } elseif ($is_payment_change || $is_switch_order || $is_synced_subscription) {
             $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id);
             // Give a free trial until the next payment date
             if ($is_switch_order) {
                 $next_payment_timestamp = get_post_meta($order->id, '_switched_subscription_first_payment_timestamp', true);
             } elseif ($is_synced_subscription) {
                 $next_payment_timestamp = WC_Subscriptions_Synchroniser::calculate_first_payment_date($product, 'timestamp');
             } else {
                 $next_payment_timestamp = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $order->user_id, 'timestamp');
             }
             // When the subscription is on hold
             if ($next_payment_timestamp != false && !empty($next_payment_timestamp)) {
                 $trial_until = self::calculate_trial_periods_until($next_payment_timestamp);
                 $subscription_trial_length = $trial_until['first_trial_length'];
                 $converted_periods['trial_period'] = $trial_until['first_trial_period'];
                 $second_trial_length = $trial_until['second_trial_length'];
                 $second_trial_period = $trial_until['second_trial_period'];
             } else {
                 $subscription_trial_length = 0;
             }
             // If is a payment change, we need to account for completed payments on the number of installments owing
             if ($is_payment_change && $subscription_length > 0) {
                 $subscription_installments -= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key);
             }
         } else {
             $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order);
         }
         if ($subscription_trial_length > 0) {
             // Specify a free trial period
             if ($is_switch_order || $is_synced_subscription || $initial_payment != $sign_up_fee) {
                 $paypal_args['a1'] = $initial_payment > 0 ? $initial_payment : 0;
             } else {
                 $paypal_args['a1'] = $sign_up_fee > 0 ? $sign_up_fee : 0;
                 // Maybe add the sign up fee to the free trial period
             }
             // Trial period length
             $paypal_args['p1'] = $subscription_trial_length;
             // Trial period
             $paypal_args['t1'] = $converted_periods['trial_period'];
             // We need to use a second trial period before we have more than 90 days until the next payment
             if (isset($second_trial_length) && $second_trial_length > 0) {
                 $paypal_args['a2'] = 0.01;
                 // Alas, although it's undocumented, PayPal appears to require a non-zero value in order to allow a second trial period
                 $paypal_args['p2'] = $second_trial_length;
                 $paypal_args['t2'] = $second_trial_period;
             }
         } elseif ($sign_up_fee > 0 || $initial_payment != $price_per_period) {
             // No trial period, so charge sign up fee and per period price for the first period
             if ($subscription_installments == 1) {
                 $param_number = 3;
             } else {
                 $param_number = 1;
             }
             $paypal_args['a' . $param_number] = $initial_payment;
             // Sign Up interval
             $paypal_args['p' . $param_number] = $subscription_interval;
             // Sign Up unit of duration
             $paypal_args['t' . $param_number] = $converted_periods['billing_period'];
         }
         // We have a recurring payment
         if (!isset($param_number) || $param_number == 1) {
             // Subscription price
             $paypal_args['a3'] = $price_per_period;
             // Subscription duration
             $paypal_args['p3'] = $subscription_interval;
             // Subscription period
             $paypal_args['t3'] = $converted_periods['billing_period'];
         }
         // Recurring payments
         if ($subscription_installments == 1 || $sign_up_fee > 0 && $subscription_trial_length == 0 && $subscription_installments == 2) {
             // Non-recurring payments
             $paypal_args['src'] = 0;
         } else {
             $paypal_args['src'] = 1;
             if ($subscription_installments > 0) {
                 if ($sign_up_fee > 0 && $subscription_trial_length == 0) {
                     // An initial period is being used to charge a sign-up fee
                     $subscription_installments--;
                 }
                 $paypal_args['srt'] = $subscription_installments;
             }
         }
         // Don't reattempt failed payments, instead let Subscriptions handle the failed payment
         $paypal_args['sra'] = 0;
         // Force return URL so that order description & instructions display
         $paypal_args['rm'] = 2;
     }
     return $paypal_args;
 }
 /**
  * Calculate the maximum amount that can be charged throughout the life of a subscription. Amazon displays this
  * to the customer when they're authorizing their payment.
  *
  * @since 2.0
  * @param WC_Order $order the WC order object
  * @return float the maximum total amount that can be charged, rounded to the nearest whole number
  */
 private function calculate_lifetime_subscription_total(WC_Order $order)
 {
     // start with the total initial payment, which includes any sign up fee or one-off shipping/tax charge
     $total = WC_Subscriptions_Order::get_total_initial_payment($order);
     // add the total from all the recurring periods
     if (WC_Subscriptions_Order::get_subscription_length($order) > 0) {
         $total += WC_Subscriptions_Order::get_recurring_total($order) * WC_Subscriptions_Order::get_subscription_length($order);
         // If a subscription never ends, use 5 years worth of recurring charges as a sensible maximum
     } else {
         // first get the subscription period in year terms
         switch (WC_Subscriptions_Order::get_subscription_period($order)) {
             case 'day':
                 $period = 365;
                 break;
             case 'week':
                 $period = 52;
                 break;
             case 'month':
                 $period = 12;
                 break;
             case 'year':
                 $period = 1;
                 break;
             default:
                 $period = 1;
                 break;
         }
         // divide by the interval (e.g. recurs every Xth week)
         $period = $period / WC_Subscriptions_Order::get_subscription_interval($order);
         // multiply by recurring total per period by the number of periods in a year by 5 years to get the total
         $total += WC_Subscriptions_Order::get_recurring_total($order) * $period * 5;
     }
     // finally increase by 25% to account for price increases / upgrades
     $total *= 1.25;
     /**
      * Round to whole number and allow an entirely different total to be set
      *
      * @since 2.0
      * @param float $lifetime_subscription_total the total amount that may be charged, as shown to the customer during checkout @ Amazon
      * @param WC_Order $order the WC Order object
      */
     return apply_filters('wc_amazon_fps_lifetime_subscription_total', round($total, 0), $order);
 }
 /**
  * Override the default PayPal standard args in WooCommerce for subscription purchases.
  *
  * @since 1.0
  */
 public static function paypal_standard_subscription_args($paypal_args)
 {
     extract(self::get_order_id_and_key($paypal_args));
     if (WC_Subscriptions_Order::order_contains_subscription($order_id) && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
         $order = new WC_Order($order_id);
         $order_items = $order->get_items();
         // Only one subscription allowed in the cart when PayPal Standard is active
         $product = $order->get_product_from_item(array_pop($order_items));
         // It's a subscription
         $paypal_args['cmd'] = '_xclick-subscriptions';
         if (count($order->get_items()) > 1) {
             foreach ($order->get_items() as $item) {
                 if ($item['qty'] > 1) {
                     $item_names[] = $item['qty'] . ' x ' . $item['name'];
                 } else {
                     if ($item['qty'] > 0) {
                         $item_names[] = $item['name'];
                     }
                 }
             }
             $paypal_args['item_name'] = sprintf(__('Order %s', WC_Subscriptions::$text_domain), $order->get_order_number());
         } else {
             $paypal_args['item_name'] = $product->get_title();
         }
         $unconverted_periods = array('billing_period' => WC_Subscriptions_Order::get_subscription_period($order), 'trial_period' => WC_Subscriptions_Order::get_subscription_trial_period($order));
         $converted_periods = array();
         // Convert period strings into PayPay's format
         foreach ($unconverted_periods as $key => $period) {
             switch (strtolower($period)) {
                 case 'day':
                     $converted_periods[$key] = 'D';
                     break;
                 case 'week':
                     $converted_periods[$key] = 'W';
                     break;
                 case 'year':
                     $converted_periods[$key] = 'Y';
                     break;
                 case 'month':
                 default:
                     $converted_periods[$key] = 'M';
                     break;
             }
         }
         $sign_up_fee = WC_Subscriptions_Order::get_sign_up_fee($order);
         $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order);
         $price_per_period = WC_Subscriptions_Order::get_recurring_total($order);
         $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order);
         $subscription_installments = WC_Subscriptions_Order::get_subscription_length($order) / $subscription_interval;
         $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order);
         if ($subscription_trial_length > 0) {
             // Specify a free trial period
             $paypal_args['a1'] = $sign_up_fee > 0 ? $sign_up_fee : 0;
             // Maybe add the sign up fee to the free trial period
             // Trial period length
             $paypal_args['p1'] = $subscription_trial_length;
             // Trial period
             $paypal_args['t1'] = $converted_periods['trial_period'];
         } elseif ($sign_up_fee > 0 || $initial_payment !== $price_per_period) {
             // No trial period, so charge sign up fee and per period price for the first period
             if ($subscription_installments == 1) {
                 $param_number = 3;
             } else {
                 $param_number = 1;
             }
             $paypal_args['a' . $param_number] = $initial_payment;
             // Sign Up interval
             $paypal_args['p' . $param_number] = $subscription_interval;
             // Sign Up unit of duration
             $paypal_args['t' . $param_number] = $converted_periods['billing_period'];
         }
         // We have a recurring payment
         if (!isset($param_number) || $param_number == 1) {
             // Subscription price
             $paypal_args['a3'] = $price_per_period;
             // Subscription duration
             $paypal_args['p3'] = $subscription_interval;
             // Subscription period
             $paypal_args['t3'] = $converted_periods['billing_period'];
         }
         // Recurring payments
         if ($subscription_installments == 1 || $sign_up_fee > 0 && $subscription_trial_length == 0 && $subscription_installments == 2) {
             // Non-recurring payments
             $paypal_args['src'] = 0;
         } else {
             $paypal_args['src'] = 1;
             if ($subscription_installments > 0) {
                 if ($sign_up_fee > 0 && $subscription_trial_length == 0) {
                     // An initial period is being used to charge a sign-up fee
                     $subscription_installments--;
                 }
                 $paypal_args['srt'] = $subscription_installments;
             }
         }
         // Force return URL so that order description & instructions display
         $paypal_args['rm'] = 2;
     }
     return $paypal_args;
 }
 /**
  * Check if a given subscription can be renewed.
  *
  * For a subscription to be renewable, it must:
  * 1. be inactive (expired or cancelled)
  * 2. had at least one payment, to avoid circumventing sign-up fees
  * 3. its parent order must not have already been superseded by a renewal order (to prevent
  * displaying "Renew" links on subscriptions that have already been renewed)
  * 4. be for a product which has not been deleted
  * 5. have a recurring total more than $0 (i.e. the entire cost of the subscription wasn't front-end loaded in a sign-up fee)
  *
  * @param string $subscription_key A subscription key of the form created by @see WC_Subscriptions_Manager::get_subscription_key()
  * @param int $user_id The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance.
  * @since 1.2
  */
 public static function can_subscription_be_renewed($subscription_key, $user_id = '')
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     if (empty($subscription)) {
         $subscription_can_be_renewed = false;
     } else {
         $renewal_orders = get_posts(array('meta_query' => array(array('key' => '_original_order', 'compare' => '=', 'value' => $subscription['order_id'], 'type' => 'numeric')), 'post_type' => 'shop_order', 'post_status' => 'any', 'post_parent' => 0));
         $product = !empty($subscription['variation_id']) ? get_product($subscription['variation_id']) : get_product($subscription['product_id']);
         if (empty($renewal_orders) && !empty($subscription['completed_payments']) && false !== $product && in_array($subscription['status'], array('cancelled', 'expired', 'trash', 'failed')) && WC_Subscriptions_Order::get_recurring_total($subscription['order_id'])) {
             $subscription_can_be_renewed = true;
         } else {
             $subscription_can_be_renewed = false;
         }
     }
     return apply_filters('woocommerce_can_subscription_be_renewed', $subscription_can_be_renewed, $subscription, $subscription_key, $user_id);
 }
 /**
  * Fire a gateway specific hook for when a subscription payment is due.
  *
  * @since 1.0
  */
 public static function gateway_scheduled_subscription_payment($user_id, $subscription_key)
 {
     $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
     $order = new WC_Order($subscription['order_id']);
     if (!WC_Subscriptions_Order::requires_manual_renewal($order)) {
         $amount_to_charge = WC_Subscriptions_Order::get_recurring_total($order);
         $outstanding_payments = WC_Subscriptions_Order::get_outstanding_balance($order, $subscription['product_id']);
         if ('yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_add_outstanding_balance', 'no') && $outstanding_payments > 0) {
             $amount_to_charge += $outstanding_payments;
         }
         if ($amount_to_charge > 0) {
             $transaction_id = get_post_meta($order->id, '_transaction_id', true);
             update_post_meta($order->id, '_transaction_id_original', $transaction_id);
             delete_post_meta($order->id, '_transaction_id', $transaction_id);
             // just in case the gateway uses add_post_meta() not update_post_meta() - this will be set later based on `'_transaction_id_original'` regardless of whether the payment fails or succeeds
             do_action('scheduled_subscription_payment_' . $order->recurring_payment_method, $amount_to_charge, $order, $subscription['product_id']);
         }
     }
 }