/** * 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; }
/** * Checks if the PayPal account has reference transactions setup * * Subscriptions keeps a record of all accounts where reference transactions were found to be enabled just in case the * store manager switches to and from accounts. This record is stored as a JSON encoded array in the options table. * * @since 2.0 */ public static function are_reference_transactions_enabled($bypass_cache = '') { $api_username = self::get_option('api_username'); $transient_key = 'wcs_paypal_rt_enabled'; $reference_transactions_enabled = false; if (self::are_credentials_set()) { $accounts_with_reference_transactions_enabled = json_decode(get_option('wcs_paypal_rt_enabled_accounts', wcs_json_encode(array()))); if (in_array($api_username, $accounts_with_reference_transactions_enabled)) { $reference_transactions_enabled = true; } elseif ('bypass_cache' === $bypass_cache || get_transient($transient_key) !== $api_username) { if (self::get_api()->are_reference_transactions_enabled()) { $accounts_with_reference_transactions_enabled[] = $api_username; update_option('wcs_paypal_rt_enabled_accounts', wcs_json_encode($accounts_with_reference_transactions_enabled)); $reference_transactions_enabled = true; } else { set_transient($transient_key, $api_username, DAY_IN_SECONDS); } } } return apply_filters('wooocommerce_subscriptions_paypal_reference_transactions_enabled', $reference_transactions_enabled); }
/** * Processes an ajax request to change a subscription's next payment date. * * Deprecated because editing a subscription's next payment date is now done from the Edit Subscription screen. * * @since 1.2 * @deprecated 2.0 */ public static function ajax_update_next_payment_date() { _deprecated_function(__METHOD__, '2.0', 'wp_delete_post()'); $response = array('status' => 'error'); if (!wp_verify_nonce($_POST['wcs_nonce'], 'woocommerce-subscriptions')) { $response['message'] = '<div class="error">' . __('Invalid security token, please reload the page and try again.', 'woocommerce-subscriptions') . '</div>'; } elseif (!current_user_can('manage_woocommerce')) { $response['message'] = '<div class="error">' . __('Only store managers can edit payment dates.', 'woocommerce-subscriptions') . '</div>'; } elseif (empty($_POST['wcs_day']) || empty($_POST['wcs_month']) || empty($_POST['wcs_year'])) { $response['message'] = '<div class="error">' . __('Please enter all date fields.', 'woocommerce-subscriptions') . '</div>'; } else { $new_payment_date = sprintf('%s-%s-%s %s', (int) $_POST['wcs_year'], zeroise((int) $_POST['wcs_month'], 2), zeroise((int) $_POST['wcs_day'], 2), date('H:i:s', current_time('timestamp'))); $new_payment_timestamp = self::update_next_payment_date($new_payment_date, $_POST['wcs_subscription_key'], self::get_user_id_from_subscription_key($_POST['wcs_subscription_key']), 'user'); if (is_wp_error($new_payment_timestamp)) { $response['message'] = sprintf('<div class="error">%s</div>', $new_payment_timestamp->get_error_message()); } else { $new_payment_timestamp_user_time = $new_payment_timestamp + get_option('gmt_offset') * 3600; // The timestamp is returned in server time $time_diff = $new_payment_timestamp - gmdate('U'); if ($time_diff > 0 && $time_diff < 7 * 24 * 60 * 60) { // translators: placeholder is human time diff (e.g. "3 weeks") $date_to_display = sprintf(__('In %s', 'woocommerce-subscriptions'), human_time_diff(gmdate('U'), $new_payment_timestamp)); } else { $date_to_display = date_i18n(wc_date_format(), $new_payment_timestamp_user_time); } $response['status'] = 'success'; $response['message'] = '<div class="updated">' . __('Date Changed', 'woocommerce-subscriptions') . '</div>'; $response['dateToDisplay'] = $date_to_display; $response['timestamp'] = $new_payment_timestamp_user_time; } } echo wcs_json_encode($response); exit; }
/** * Migrate the trial expiration, next payment and expiration/end dates to a new subscription. * * @since 2.0 */ private static function migrate_dates($new_subscription, $old_subscription) { global $wpdb; $dates_to_update = array(); // old hook => new hook $date_keys = array('trial_end' => array('old_subscription_key' => 'trial_expiry_date', 'old_scheduled_hook' => 'scheduled_subscription_trial_end'), 'end' => array('old_subscription_key' => 'expiry_date', 'old_scheduled_hook' => 'scheduled_subscription_expiration'), 'end_date' => array('old_subscription_key' => '_subscription_end_date', 'old_scheduled_hook' => ''), 'next_payment' => array('old_subscription_key' => '', 'old_scheduled_hook' => 'scheduled_subscription_payment'), 'end_of_prepaid_term' => array('old_subscription_key' => '', 'old_scheduled_hook' => 'scheduled_subscription_end_of_prepaid_term')); $old_hook_args = array('user_id' => $old_subscription['user_id'], 'subscription_key' => $old_subscription['subscription_key']); foreach ($date_keys as $new_key => $old_keys) { // First check if there is a date stored on the subscription, and if so, use that if (!empty($old_keys['old_subscription_key']) && (isset($old_subscription[$old_keys['old_subscription_key']]) && 0 !== $old_subscription[$old_keys['old_subscription_key']])) { $dates_to_update[$new_key] = $old_subscription[$old_keys['old_subscription_key']]; } elseif (!empty($old_keys['old_scheduled_hook'])) { // Now check if there is a scheduled date, this is for next payment and end of prepaid term dates $next_scheduled = wc_next_scheduled_action($old_keys['old_scheduled_hook'], $old_hook_args); if ($next_scheduled > 0) { if ('end_of_prepaid_term' == $new_key) { wc_schedule_single_action($next_scheduled, 'woocommerce_scheduled_subscription_end_of_prepaid_term', array('subscription_id' => $new_subscription->id)); } else { $dates_to_update[$new_key] = date('Y-m-d H:i:s', $next_scheduled); } } } } // Trash all the hooks in one go to save write requests $wpdb->update($wpdb->posts, array('post_status' => 'trash'), array('post_type' => ActionScheduler_wpPostStore::POST_TYPE, 'post_content' => wcs_json_encode($old_hook_args)), array('%s', '%s')); $dates_to_update['start'] = $new_subscription->post->post_date_gmt; // v2.0 enforces new rules for dates when they are being set, so we need to massage the old data to conform to these new rules foreach ($dates_to_update as $date_type => $date) { if (0 == $date) { continue; } switch ($date_type) { case 'end': if (array_key_exists('next_payment', $dates_to_update) && $date <= $dates_to_update['next_payment']) { $dates_to_update[$date_type] = $date; } case 'next_payment': if (array_key_exists('trial_end', $dates_to_update) && $date < $dates_to_update['trial_end']) { $dates_to_update[$date_type] = $date; } case 'trial_end': if (array_key_exists('start', $dates_to_update) && $date <= $dates_to_update['start']) { $dates_to_update[$date_type] = $date; } } } try { if (!empty($dates_to_update)) { $new_subscription->update_dates($dates_to_update); } WCS_Upgrade_Logger::add(sprintf('For subscription %d: updated dates = %s', $new_subscription->id, str_replace(array('{', '}', '"'), '', wcs_json_encode($dates_to_update)))); } catch (Exception $e) { WCS_Upgrade_Logger::add(sprintf('For subscription %d: unable to update dates, exception "%s"', $new_subscription->id, $e->getMessage())); } }
/** * Because the upgrader may have attempted to set an invalid end date on the subscription, it could * lead to the entire date update process failing, which would mean that a next payment date would * not be set even when one existed. * * This method checks if a given subscription has no next payment date, and if it doesn't, it checks * if one was previously scheduled for the old subscription. If one was, and that date is in the future, * it will pass that date back for being set on the subscription. If a date was scheduled but that is now * in the past, it will recalculate it. * * @param WC_Subscription $subscription the subscription to check * @return string|bool false if the date does not need to be repaired or the new date if it should be repaired */ protected static function check_next_payment_date($subscription) { global $wpdb; // the subscription doesn't have a next payment date set, let's see if it should if (0 == $subscription->get_time('next_payment') && $subscription->has_status('active')) { $old_hook_args = array('user_id' => (int) $subscription->get_user_id(), 'subscription_key' => wcs_get_old_subscription_key($subscription)); // get the latest scheduled subscription payment in v1.5 $old_next_payment_date = $wpdb->get_var($wpdb->prepare("SELECT post_date_gmt FROM {$wpdb->posts}\n\t\t\t\t WHERE post_type = %s\n\t\t\t\t AND post_content = %s\n\t\t\t\t AND post_title = 'scheduled_subscription_payment'\n\t\t\t\t ORDER BY post_date_gmt DESC", ActionScheduler_wpPostStore::POST_TYPE, wcs_json_encode($old_hook_args))); WCS_Upgrade_Logger::add(sprintf('For subscription %d: new next payment date = %s.', $subscription->id, var_export($subscription->get_date('next_payment'), true))); WCS_Upgrade_Logger::add(sprintf('For subscription %d: old next payment date = %s.', $subscription->id, var_export($old_next_payment_date, true))); // if we have a date, make sure it's valid if (null !== $old_next_payment_date) { if (strtotime($old_next_payment_date) <= gmdate('U')) { $repair_date = $subscription->calculate_date('next_payment'); if (0 == $repair_date) { $repair_date = false; } WCS_Upgrade_Logger::add(sprintf('For subscription %d: old next payment date is in the past, setting it to %s.', $subscription->id, var_export($repair_date, true))); } else { $repair_date = $old_next_payment_date; } } else { // let's just double check we shouldn't have a date set by recalculating it $calculated_next_payment_date = $subscription->calculate_date('next_payment'); if (0 != $calculated_next_payment_date && strtotime($calculated_next_payment_date) > gmdate('U')) { $repair_date = $calculated_next_payment_date; } else { $repair_date = false; } WCS_Upgrade_Logger::add(sprintf('For subscription %d: no old next payment date, setting it to %s.', $subscription->id, var_export($repair_date, true))); } } else { $repair_date = false; } WCS_Upgrade_Logger::add(sprintf('For subscription %d: repair next payment date = %s.', $subscription->id, var_export($repair_date, true))); return $repair_date; }
} ?> <div class="wc-metaboxes-wrapper"> <div id="billing-schedule"> <?php if ($the_subscription->can_date_be_updated('next_payment')) { ?> <div class="billing-schedule-edit wcs-date-input"><?php // Subscription Period Interval echo woocommerce_wp_select(array('id' => '_billing_interval', 'class' => 'billing_interval', 'label' => __('Recurring:', 'woocommerce-subscriptions'), 'value' => empty($the_subscription->billing_interval) ? 1 : $the_subscription->billing_interval, 'options' => wcs_get_subscription_period_interval_strings())); // Billing Period echo woocommerce_wp_select(array('id' => '_billing_period', 'class' => 'billing_period', 'label' => __('Billing Period', 'woocommerce-subscriptions'), 'value' => empty($the_subscription->billing_period) ? 'month' : $the_subscription->billing_period, 'options' => wcs_get_subscription_period_strings())); ?> <input type="hidden" name="wcs-lengths" id="wcs-lengths" data-subscription_lengths="<?php echo esc_attr(wcs_json_encode(wcs_get_subscription_ranges())); ?> "> </div> <?php } else { ?> <strong><?php esc_html_e('Recurring:', 'woocommerce-subscriptions'); ?> </strong> <?php printf('%s %s', esc_html(wcs_get_subscription_period_interval_strings($the_subscription->billing_interval)), esc_html(wcs_get_subscription_period_strings(1, $the_subscription->billing_period))); ?> <?php }
/** * Move scheduled subscription hooks out of wp-cron and into the new Action Scheduler. * * Also set all existing subscriptions to "sold individually" to maintain previous behavior * for existing subscription products before the subscription quantities feature was enabled.. * * @since 1.5 */ public static function ajax_upgrade() { global $wpdb; check_admin_referer('wcs_upgrade_process', 'nonce'); self::set_upgrade_limits(); WCS_Upgrade_Logger::add(sprintf('Starting upgrade step: %s', $_POST['upgrade_step'])); if (ini_get('max_execution_time') < 600) { @set_time_limit(600); } @ini_set('memory_limit', apply_filters('admin_memory_limit', WP_MAX_MEMORY_LIMIT)); update_option('wc_subscriptions_is_upgrading', gmdate('U') + 60 * 2); switch ($_POST['upgrade_step']) { case 'really_old_version': $upgraded_versions = self::upgrade_really_old_versions(); $results = array('message' => sprintf(__('Database updated to version %s', 'woocommerce-subscriptions'), $upgraded_versions)); break; case 'products': require_once 'class-wcs-upgrade-1-5.php'; $upgraded_product_count = WCS_Upgrade_1_5::upgrade_products(); $results = array('message' => sprintf(_x('Marked %s subscription products as "sold individually".', 'used in the subscriptions upgrader', 'woocommerce-subscriptions'), $upgraded_product_count)); break; case 'hooks': require_once 'class-wcs-upgrade-1-5.php'; $upgraded_hook_count = WCS_Upgrade_1_5::upgrade_hooks(self::$upgrade_limit_hooks); $results = array('upgraded_count' => $upgraded_hook_count, 'message' => sprintf(__('Migrated %1$s subscription related hooks to the new scheduler (in %2$s seconds).', 'woocommerce-subscriptions'), $upgraded_hook_count, '{execution_time}')); break; case 'subscriptions': require_once 'class-wcs-repair-2-0.php'; require_once 'class-wcs-upgrade-2-0.php'; try { $upgraded_subscriptions = WCS_Upgrade_2_0::upgrade_subscriptions(self::$upgrade_limit_subscriptions); $results = array('upgraded_count' => $upgraded_subscriptions, 'message' => sprintf(__('Migrated %1$s subscriptions to the new structure (in %2$s seconds).', 'woocommerce-subscriptions'), $upgraded_subscriptions, '{execution_time}'), 'status' => 'success', 'time_message' => sprintf(_x('Estimated time left (minutes:seconds): %s', 'Message that gets sent to front end.', 'woocommerce-subscriptions'), '{time_left}')); } catch (Exception $e) { WCS_Upgrade_Logger::add(sprintf('Error on upgrade step: %s. Error: %s', $_POST['upgrade_step'], $e->getMessage())); $results = array('upgraded_count' => 0, 'message' => sprintf(__('Unable to upgrade subscriptions.<br/>Error: %1$s<br/>Please refresh the page and try again. If problem persists, %2$scontact support%3$s.', 'woocommerce-subscriptions'), '<code>' . $e->getMessage() . '</code>', '<a href="' . esc_url('https://woothemes.com/my-account/create-a-ticket/') . '">', '</a>'), 'status' => 'error'); } break; case 'subscription_dates_repair': require_once 'class-wcs-upgrade-2-0.php'; require_once 'class-wcs-repair-2-0-2.php'; $subscription_ids_to_repair = WCS_Repair_2_0_2::get_subscriptions_to_repair(self::$upgrade_limit_subscriptions); try { $subscription_counts = WCS_Repair_2_0_2::maybe_repair_subscriptions($subscription_ids_to_repair); // translators: placeholder is the number of subscriptions repaired $repair_incorrect = sprintf(_x('Repaired %d subscriptions with incorrect dates, line tax data or missing customer notes.', 'Repair message that gets sent to front end.', 'woocommerce-subscriptions'), $subscription_counts['repaired_count']); $repair_not_needed = ''; if ($subscription_counts['unrepaired_count'] > 0) { // translators: placeholder is number of subscriptions that were checked and did not need repairs. There's a space at the beginning! $repair_not_needed = sprintf(_nx(' %d other subscription was checked and did not need any repairs.', '%d other subscriptions were checked and did not need any repairs.', $subscription_counts['unrepaired_count'], 'Repair message that gets sent to front end.', 'woocommerce-subscriptions'), $subscription_counts['unrepaired_count']); } // translators: placeholder is "{execution_time}", which will be replaced on front end with actual time $repair_time = sprintf(_x('(in %s seconds)', 'Repair message that gets sent to front end.', 'woocommerce-subscriptions'), '{execution_time}'); // translators: $1: "Repaired x subs with incorrect dates...", $2: "X others were checked and no repair needed", $3: "(in X seconds)". Ordering for RTL languages. $repair_message = sprintf(_x('%1$s%2$s %3$s', 'The assembled repair message that gets sent to front end.', 'woocommerce-subscriptions'), $repair_incorrect, $repair_not_needed, $repair_time); $results = array('repaired_count' => $subscription_counts['repaired_count'], 'unrepaired_count' => $subscription_counts['unrepaired_count'], 'message' => $repair_message, 'status' => 'success', 'time_message' => sprintf(_x('Estimated time left (minutes:seconds): %s', 'Message that gets sent to front end.', 'woocommerce-subscriptions'), '{time_left}')); } catch (Exception $e) { WCS_Upgrade_Logger::add(sprintf('Error on upgrade step: %s. Error: %s', $_POST['upgrade_step'], $e->getMessage())); $results = array('repaired_count' => 0, 'unrepaired_count' => 0, 'message' => sprintf(_x('Unable to repair subscriptions.<br/>Error: %1$s<br/>Please refresh the page and try again. If problem persists, %2$scontact support%3$s.', 'Error message that gets sent to front end when upgrading Subscriptions', 'woocommerce-subscriptions'), '<code>' . $e->getMessage() . '</code>', '<a href="' . esc_url('https://woothemes.com/my-account/create-a-ticket/') . '">', '</a>'), 'status' => 'error'); } break; } if ('subscriptions' == $_POST['upgrade_step'] && 0 === self::get_total_subscription_count_query()) { self::upgrade_complete(); } elseif ('subscription_dates_repair' == $_POST['upgrade_step']) { $subscriptions_to_repair = WCS_Repair_2_0_2::get_subscriptions_to_repair(self::$upgrade_limit_subscriptions); if (empty($subscriptions_to_repair)) { self::upgrade_complete(); } } WCS_Upgrade_Logger::add(sprintf('Completed upgrade step: %s', $_POST['upgrade_step'])); header('Content-Type: application/json; charset=utf-8'); echo wcs_json_encode($results); exit; }
/** * Charge a payment against a reference token * * @link https://developer.paypal.com/docs/classic/express-checkout/integration-guide/ECReferenceTxns/#id094UM0DA0HS * @link https://developer.paypal.com/docs/classic/api/merchant/DoReferenceTransaction_API_Operation_NVP/ * * @param string $reference_id the ID of a refrence object, e.g. billing agreement ID. * @param WC_Order $order order object * @param array $args { * @type string 'payment_type' (Optional) Specifies type of PayPal payment you require for the billing agreement. It is one of the following values. 'Any' or 'InstantOnly'. Echeck is not supported for DoReferenceTransaction requests. * @type string 'payment_action' How you want to obtain payment. It is one of the following values: 'Authorization' - this payment is a basic authorization subject to settlement with PayPal Authorization and Capture; or 'Sale' - This is a final sale for which you are requesting payment. * @type string 'return_fraud_filters' (Optional) Flag to indicate whether you want the results returned by Fraud Management Filters. By default, you do not receive this information. * } * @since 2.0 */ public function do_reference_transaction($reference_id, $order, $args = array()) { $defaults = array('amount' => $order->get_total(), 'payment_type' => 'Any', 'payment_action' => 'Sale', 'return_fraud_filters' => 1, 'notify_url' => WC()->api_request_url('WC_Gateway_Paypal'), 'invoice_number' => WCS_PayPal::get_option('invoice_prefix') . wcs_str_to_ascii(ltrim($order->get_order_number(), _x('#', 'hash before the order number. Used as a character to remove from the actual order number', 'woocommerce-subscriptions'))), 'custom' => wcs_json_encode(array('order_id' => $order->id, 'order_key' => $order->order_key))); $args = wp_parse_args($args, $defaults); $this->set_method('DoReferenceTransaction'); // set base params $this->add_parameters(array('REFERENCEID' => $reference_id, 'BUTTONSOURCE' => 'WooThemes_Cart', 'RETURNFMFDETAILS' => $args['return_fraud_filters'], 'NOTIFYURL' => $args['notify_url'])); $this->add_payment_details_parameters($order, $args['payment_action'], true); }