/** * 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; }
/** * Takes a timestamp for a date in the future and calculates the number of days between now and then * * @since 1.4 */ public static function calculate_trial_periods_until($future_timestamp) { _deprecated_function(__METHOD__, '2.0', 'wcs_calculate_paypal_trial_periods_until()'); return wcs_calculate_paypal_trial_periods_until($future_timestamp); }