/**
  * Get PayPal Args for passing to PP
  *
  * Based on the HTML Variables documented here: https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU
  *
  * @param WC_Order $order
  * @return array
  */
 public static function get_paypal_args($paypal_args, $order)
 {
     $is_payment_change = WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment;
     $order_contains_failed_renewal = false;
     // Payment method changes act on the subscription not the original order
     if ($is_payment_change) {
         $subscriptions = array(wcs_get_subscription($order->id));
         $subscription = array_pop($subscriptions);
         $order = $subscription->order;
         // We need the subscription's total
         remove_filter('woocommerce_order_amount_total', 'WC_Subscriptions_Change_Payment_Gateway::maybe_zero_total', 11, 2);
     } else {
         // Otherwise the order is the $order
         if ($cart_item = wcs_cart_contains_failed_renewal_order_payment() || false !== WC_Subscriptions_Renewal_Order::get_failed_order_replaced_by($order->id)) {
             $subscriptions = wcs_get_subscriptions_for_renewal_order($order);
             $order_contains_failed_renewal = true;
         } else {
             $subscriptions = wcs_get_subscriptions_for_order($order);
         }
         // Only one subscription allowed per order with PayPal
         $subscription = array_pop($subscriptions);
     }
     if ($order_contains_failed_renewal || !empty($subscription) && $subscription->get_total() > 0 && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) {
         // It's a subscription
         $paypal_args['cmd'] = '_xclick-subscriptions';
         // Store the subscription ID in the args sent to PayPal so we can access them later
         $paypal_args['custom'] = wcs_json_encode(array('order_id' => $order->id, 'order_key' => $order->order_key, 'subscription_id' => $subscription->id, 'subscription_key' => $subscription->order_key));
         foreach ($subscription->get_items() as $item) {
             if ($item['qty'] > 1) {
                 $item_names[] = $item['qty'] . ' x ' . wcs_get_paypal_item_name($item['name']);
             } elseif ($item['qty'] > 0) {
                 $item_names[] = wcs_get_paypal_item_name($item['name']);
             }
         }
         // translators: 1$: subscription ID, 2$: order ID, 3$: names of items, comma separated
         $paypal_args['item_name'] = wcs_get_paypal_item_name(sprintf(_x('Subscription %1$s (Order %2$s) - %3$s', 'item name sent to paypal', 'woocommerce-subscriptions'), $subscription->get_order_number(), $order->get_order_number(), implode(', ', $item_names)));
         $unconverted_periods = array('billing_period' => $subscription->billing_period, 'trial_period' => $subscription->trial_period);
         $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 = $subscription->get_total();
         $subscription_interval = $subscription->billing_interval;
         $start_timestamp = $subscription->get_time('start');
         $trial_end_timestamp = $subscription->get_time('trial_end');
         $next_payment_timestamp = $subscription->get_time('next_payment');
         $is_synced_subscription = WC_Subscriptions_Synchroniser::subscription_contains_synced_product($subscription->id);
         if ($is_synced_subscription) {
             $length_from_timestamp = $next_payment_timestamp;
         } elseif ($trial_end_timestamp > 0) {
             $length_from_timestamp = $trial_end_timestamp;
         } else {
             $length_from_timestamp = $start_timestamp;
         }
         $subscription_length = wcs_estimate_periods_between($length_from_timestamp, $subscription->get_time('end'), $subscription->billing_period);
         $subscription_installments = $subscription_length / $subscription_interval;
         $initial_payment = $is_payment_change ? 0 : $order->get_total();
         if ($order_contains_failed_renewal || $is_payment_change) {
             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
                 $suffix = '-wcscpm-' . wp_create_nonce();
             } else {
                 // Failed renewal order, append a descriptor and renewal order's ID
                 $suffix = '-wcsfrp-' . $order->id;
             }
             // Change the 'invoice' and the 'custom' values to be for the original order (if there is one)
             if (false === $subscription->order) {
                 // No original order so we need to use the subscriptions values instead
                 $order_number = ltrim($subscription->get_order_number(), _x('#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions')) . '-subscription';
                 $order_id_key = array('order_id' => $subscription->id, 'order_key' => $subscription->order_key);
             } else {
                 $order_number = ltrim($subscription->order->get_order_number(), _x('#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions'));
                 $order_id_key = array('order_id' => $subscription->order->id, 'order_key' => $subscription->order->order_key);
             }
             $order_details = false !== $subscription->order ? $subscription->order : $subscription;
             // 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'] = WCS_PayPal::get_option('invoice_prefix') . $order_number . $suffix;
             $paypal_args['custom'] = wcs_json_encode(array_merge($order_id_key, array('subscription_id' => $subscription->id, 'subscription_key' => $subscription->order_key)));
         }
         if ($order_contains_failed_renewal) {
             $subscription_trial_length = 0;
             $subscription_installments = max($subscription_installments - $subscription->get_completed_payment_count(), 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_synced_subscription) {
             $next_payment_timestamp = $subscription->get_time('next_payment');
             // When the subscription is on hold
             if (false != $next_payment_timestamp && !empty($next_payment_timestamp)) {
                 $trial_until = wcs_calculate_paypal_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 this 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 = max($subscription_installments - $subscription->get_completed_payment_count(), 0);
             }
         } else {
             $subscription_trial_length = wcs_estimate_periods_between($start_timestamp, $trial_end_timestamp, $subscription->trial_period);
         }
         if ($subscription_trial_length > 0) {
             // Specify a free trial period
             $paypal_args['a1'] = $initial_payment > 0 ? $initial_payment : 0;
             // 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 ($initial_payment != $price_per_period) {
             // No trial period, but initial amount includes a sign-up fee and/or other items, so charge it as a separate period
             if (1 == $subscription_installments) {
                 $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) || 1 == $param_number) {
             // 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 (1 == $subscription_installments || $initial_payment != $price_per_period && 0 == $subscription_trial_length && 2 == $subscription_installments) {
             // Non-recurring payments
             $paypal_args['src'] = 0;
         } else {
             $paypal_args['src'] = 1;
             if ($subscription_installments > 0) {
                 // An initial period is being used to charge a sign-up fee
                 if ($initial_payment != $price_per_period && 0 == $subscription_trial_length) {
                     $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;
         // Reattach the filter we removed earlier
         if ($is_payment_change) {
             add_filter('woocommerce_order_amount_total', 'WC_Subscriptions_Change_Payment_Gateway::maybe_zero_total', 11, 2);
         }
     }
     return $paypal_args;
 }
 /**
  * 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;
 }