/**
  * Setup the cart for paying for a delayed initial payment for a subscription.
  *
  * @since 2.0
  */
 public function maybe_setup_cart()
 {
     global $wp;
     if (isset($_GET['pay_for_order']) && isset($_GET['key']) && isset($wp->query_vars['order-pay'])) {
         // Pay for existing order
         $order_key = $_GET['key'];
         $order_id = isset($wp->query_vars['order-pay']) ? $wp->query_vars['order-pay'] : absint($_GET['order_id']);
         $order = wc_get_order($wp->query_vars['order-pay']);
         if ($order->order_key == $order_key && $order->has_status(array('pending', 'failed')) && !wcs_order_contains_subscription($order, array('renewal', 'resubscribe'))) {
             $subscriptions = wcs_get_subscriptions_for_order($order, array('order_type' => 'parent'));
             if (get_current_user_id() !== $order->get_user_id()) {
                 wc_add_notice(__('That doesn\'t appear to be your order.', 'woocommerce-subscriptions'), 'error');
                 wp_safe_redirect(get_permalink(wc_get_page_id('myaccount')));
                 exit;
             } elseif (!empty($subscriptions)) {
                 // Setup cart with all the original order's line items
                 $this->setup_cart($order, array('order_id' => $order_id));
                 WC()->session->set('order_awaiting_payment', $order_id);
                 // Set cart hash for orders paid in WC >= 2.6
                 $this->set_cart_hash($order_id);
                 wp_safe_redirect(WC()->cart->get_checkout_url());
                 exit;
             }
         }
     }
 }
 /**
  * Displays the renewal orders in the Related Orders meta box.
  *
  * @param object $post A WordPress post
  * @since 2.0
  */
 public static function output_rows($post)
 {
     $subscriptions = array();
     $orders = array();
     // On the subscription page, just show related orders
     if (wcs_is_subscription($post->ID)) {
         $subscriptions[] = wcs_get_subscription($post->ID);
     } elseif (wcs_order_contains_subscription($post->ID, array('parent', 'renewal'))) {
         $subscriptions = wcs_get_subscriptions_for_order($post->ID, array('order_type' => array('parent', 'renewal')));
     }
     // First, display all the subscriptions
     foreach ($subscriptions as $subscription) {
         $subscription->relationship = __('Subscription', 'woocommerce-subscriptions');
         $orders[] = $subscription;
     }
     //Resubscribed
     $initial_subscriptions = array();
     if (wcs_is_subscription($post->ID)) {
         $initial_subscriptions = wcs_get_subscriptions_for_resubscribe_order($post->ID);
         $resubscribed_subscriptions = get_posts(array('meta_key' => '_subscription_resubscribe', 'meta_value' => $post->ID, 'post_type' => 'shop_subscription', 'post_status' => 'any', 'posts_per_page' => -1));
         foreach ($resubscribed_subscriptions as $subscription) {
             $subscription = wcs_get_subscription($subscription);
             $subscription->relationship = _x('Resubscribed Subscription', 'relation to order', 'woocommerce-subscriptions');
             $orders[] = $subscription;
         }
     } else {
         if (wcs_order_contains_subscription($post->ID, array('resubscribe'))) {
             $initial_subscriptions = wcs_get_subscriptions_for_order($post->ID, array('order_type' => array('resubscribe')));
         }
     }
     foreach ($initial_subscriptions as $subscription) {
         $subscription->relationship = _x('Initial Subscription', 'relation to order', 'woocommerce-subscriptions');
         $orders[] = $subscription;
     }
     // Now, if we're on a single subscription or renewal order's page, display the parent orders
     if (1 == count($subscriptions)) {
         foreach ($subscriptions as $subscription) {
             if (false !== $subscription->order) {
                 $subscription->order->relationship = _x('Parent Order', 'relation to order', 'woocommerce-subscriptions');
                 $orders[] = $subscription->order;
             }
         }
     }
     // Finally, display the renewal orders
     foreach ($subscriptions as $subscription) {
         foreach ($subscription->get_related_orders('all', 'renewal') as $order) {
             $order->relationship = _x('Renewal Order', 'relation to order', 'woocommerce-subscriptions');
             $orders[] = $order;
         }
     }
     $orders = apply_filters('woocommerce_subscriptions_admin_related_orders_to_display', $orders, $subscriptions, $post);
     foreach ($orders as $order) {
         if ($order->id == $post->ID) {
             continue;
         }
         include 'views/html-related-orders-row.php';
     }
 }
 /**
  * Updates other subscription sources.
  */
 protected function save_source($order, $source)
 {
     parent::save_source($order, $source);
     // Also store it on the subscriptions being purchased or paid for in the order
     if (wcs_order_contains_subscription($order->id)) {
         $subscriptions = wcs_get_subscriptions_for_order($order->id);
     } elseif (wcs_order_contains_renewal($order->id)) {
         $subscriptions = wcs_get_subscriptions_for_renewal_order($order->id);
     } else {
         $subscriptions = array();
     }
     foreach ($subscriptions as $subscription) {
         update_post_meta($subscription->id, '_stripe_customer_id', $source->customer);
         update_post_meta($subscription->id, '_stripe_card_id', $source->source);
     }
 }
 /**
  * Render the column value
  *
  * @since 1.0.0
  * @param $column string
  */
 public function render_shop_order_columns($column)
 {
     global $post, $woocommerce, $the_order;
     if (empty($the_order) || $the_order->id != $post->ID) {
         $the_order = wc_get_order($post->ID);
     }
     switch ($column) {
         case 'order_subscription':
             $subscriptions = wcs_get_subscriptions_for_order($the_order->id, array('order_type' => array('parent', 'renewal')));
             if (count($subscriptions) === 0) {
                 return;
             }
             foreach ($subscriptions as $subscription) {
                 echo '<p><a href="' . get_edit_post_link($subscription->id) . '" class="button">' . __('View subscription', 'subcolumnforwoocommerce') . '</a></p>';
                 echo $this->render_subscriptions_info($subscription);
             }
             break;
     }
 }
 /**
  * Clearing for orders / subscriptions with sanitizing bits
  *
  * @param $post_id integer the ID of an order / subscription
  */
 public function purge_subscription_cache_on_update($post_id)
 {
     $post_type = get_post_type($post_id);
     if ('shop_subscription' !== $post_type && 'shop_order' !== $post_type) {
         return;
     }
     if ('shop_subscription' === $post_type) {
         $this->log('ID is subscription, calling wcs_clear_related_order_cache for ' . $post_id);
         $this->wcs_clear_related_order_cache($post_id);
     } else {
         $this->log('ID is order, getting subscription.');
         $subscription = wcs_get_subscriptions_for_order($post_id);
         if (empty($subscription)) {
             $this->log('No sub for this ID: ' . $post_id);
             return;
         }
         $subscription = array_shift($subscription);
         $this->log('Got subscription, calling wcs_clear_related_order_cache for ' . $subscription->id);
         $this->wcs_clear_related_order_cache($subscription->id);
     }
 }
 /**
  * Displays the renewal orders in the Related Orders meta box.
  *
  * @param object $post A WordPress post
  * @since 2.0
  */
 public static function output_rows($post)
 {
     $subscriptions = array();
     $orders = array();
     // On the subscription page, just show related orders
     if (wcs_is_subscription($post->ID)) {
         $subscriptions[] = wcs_get_subscription($post->ID);
     } elseif (wcs_order_contains_subscription($post->ID, array('parent', 'renewal'))) {
         $subscriptions = wcs_get_subscriptions_for_order($post->ID, array('order_type' => array('parent', 'renewal')));
     }
     // First, display all the subscriptions
     foreach ($subscriptions as $subscription) {
         $subscription->relationship = _x('Subscription', 'relation to order', 'woocommerce-subscriptions');
         $orders[] = $subscription;
     }
     // Now, if we're on a single subscription or renewal order's page, display the parent orders
     if (1 == count($subscriptions)) {
         foreach ($subscriptions as $subscription) {
             if (false !== $subscription->order) {
                 $subscription->order->relationship = _x('Parent Order', 'relation to order', 'woocommerce-subscriptions');
                 $orders[] = $subscription->order;
             }
         }
     }
     // Finally, display the renewal orders
     foreach ($subscriptions as $subscription) {
         foreach ($subscription->get_related_orders('all', 'renewal') as $order) {
             $order->relationship = _x('Renewal Order', 'relation to order', 'woocommerce-subscriptions');
             $orders[] = $order;
         }
     }
     foreach ($orders as $order) {
         if ($order->id == $post->ID) {
             continue;
         }
         include 'views/html-related-orders-row.php';
     }
 }
 /**
  * Automatically set the order's status to complete if all the subscriptions in an order
  * are synced and the order total is zero.
  *
  * @since 1.5.17
  */
 public static function order_autocomplete($new_order_status, $order_id)
 {
     $order = wc_get_order($order_id);
     if ('processing' == $new_order_status && $order->get_total() == 0 && wcs_order_contains_subscription($order)) {
         $subscriptions = wcs_get_subscriptions_for_order($order_id);
         $all_synced = true;
         foreach ($subscriptions as $subscription_id => $subscription) {
             if (!self::subscription_contains_synced_product($subscription_id)) {
                 $all_synced = false;
                 break;
             }
         }
         if ($all_synced) {
             $new_order_status = 'completed';
         }
     }
     return $new_order_status;
 }
 /**
  * WooCommerce's function receives the original order ID, the item and the list of files. This does not work for
  * download permissions stored on the subscription rather than the original order as the URL would have the wrong order
  * key. This function takes the same parameters, but queries the database again for download ids belonging to all the
  * subscriptions that were in the original order. Then for all subscriptions, it checks all items, and if the item
  * passed in here is in that subscription, it creates the correct download link to be passsed to the email.
  *
  * @param array $files List of files already included in the list
  * @param array $item An item (you get it by doing $order->get_items())
  * @param WC_Order $order The original order
  * @return array List of files with correct download urls
  */
 public static function get_item_downloads($files, $item, $order)
 {
     global $wpdb;
     if (wcs_order_contains_subscription($order, 'any')) {
         $subscriptions = wcs_get_subscriptions_for_order($order, array('order_type' => array('any')));
     } else {
         return $files;
     }
     $product_id = wcs_get_canonical_product_id($item);
     foreach ($subscriptions as $subscription) {
         foreach ($subscription->get_items() as $subscription_item) {
             if (wcs_get_canonical_product_id($subscription_item) === $product_id) {
                 $files = $subscription->get_item_downloads($subscription_item);
             }
         }
     }
     return $files;
 }
 /**
  * Save payment meta to the Subscription object after a successful transaction,
  * this is primarily used for the payment token and customer ID which are then
  * copied over to a renewal order prior to payment processing.
  *
  * @since 4.1.0
  * @param \WC_Order $order order
  */
 public function save_payment_meta($order)
 {
     // a single order can contain multiple subscriptions
     foreach (wcs_get_subscriptions_for_order($order->id) as $subscription) {
         // payment token
         if (!empty($order->payment->token)) {
             update_post_meta($subscription->id, $this->get_gateway()->get_order_meta_prefix() . 'payment_token', $order->payment->token);
         }
         // customer ID
         if (!empty($order->customer_id)) {
             update_post_meta($subscription->id, $this->get_gateway()->get_order_meta_prefix() . 'customer_id', $order->customer_id);
         }
     }
 }
 /**
  * Handle WC API requests where we need to run a reference transaction API operation
  *
  * @since 2.0
  */
 public static function handle_wc_api()
 {
     if (!isset($_GET['action'])) {
         return;
     }
     switch ($_GET['action']) {
         // called when the customer is returned from PayPal after authorizing their payment, used for retrieving the customer's checkout details
         case 'create_billing_agreement':
             // bail if no token
             if (!isset($_GET['token'])) {
                 return;
             }
             // get token to retrieve checkout details with
             $token = esc_attr($_GET['token']);
             try {
                 $express_checkout_details_response = self::get_api()->get_express_checkout_details($token);
                 // Make sure the billing agreement was accepted
                 if (1 == $express_checkout_details_response->get_billing_agreement_status()) {
                     $order = $express_checkout_details_response->get_order();
                     if (is_null($order)) {
                         throw new Exception(__('Unable to find order for PayPal billing agreement.', 'woocommerce-subscriptions'));
                     }
                     // we need to process an initial payment
                     if ($order->get_total() > 0 && !wcs_is_subscription($order)) {
                         $billing_agreement_response = self::get_api()->do_express_checkout($token, $order, array('payment_action' => 'Sale', 'payer_id' => $express_checkout_details_response->get_payer_id()));
                     } else {
                         $billing_agreement_response = self::get_api()->create_billing_agreement($token);
                     }
                     if ($billing_agreement_response->has_api_error()) {
                         throw new Exception($billing_agreement_response->get_api_error_message(), $billing_agreement_response->get_api_error_code());
                     }
                     // We're changing the payment method for a subscription, make sure we update it before updating the billing agreement ID so that an old PayPal subscription can be cancelled if the existing payment method is also PayPal
                     if (wcs_is_subscription($order)) {
                         WC_Subscriptions_Change_Payment_Gateway::update_payment_method($order, 'paypal');
                         $redirect_url = add_query_arg('utm_nooverride', '1', $order->get_view_order_url());
                     }
                     // Make sure PayPal is set as the payment method on the order and subscription
                     $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
                     $payment_method = isset($available_gateways[self::instance()->get_id()]) ? $available_gateways[self::instance()->get_id()] : false;
                     $order->set_payment_method($payment_method);
                     // Store the billing agreement ID on the order and subscriptions
                     wcs_set_paypal_id($order, $billing_agreement_response->get_billing_agreement_id());
                     foreach (wcs_get_subscriptions_for_order($order, array('order_type' => 'any')) as $subscription) {
                         $subscription->set_payment_method($payment_method);
                         wcs_set_paypal_id($subscription, $billing_agreement_response->get_billing_agreement_id());
                     }
                     if (!wcs_is_subscription($order)) {
                         if (0 == $order->get_total()) {
                             $order->payment_complete();
                         } else {
                             self::process_subscription_payment_response($order, $billing_agreement_response);
                         }
                         $redirect_url = add_query_arg('utm_nooverride', '1', $order->get_checkout_order_received_url());
                     }
                     // redirect customer to order received page
                     wp_safe_redirect(esc_url_raw($redirect_url));
                 } else {
                     wp_safe_redirect(WC()->cart->get_cart_url());
                 }
             } catch (Exception $e) {
                 wc_add_notice(__('An error occurred, please try again or try an alternate form of payment.', 'woocommerce-subscriptions'), 'error');
                 wp_redirect(WC()->cart->get_cart_url());
             }
             exit;
         case 'reference_transaction_account_check':
             exit;
     }
 }
 /**
  * Cancel subscriptions with PayPal Standard after the order has been successfully switched.
  *
  * @param int $order_id
  * @param string $old_status
  * @param string $new_status
  * @since 2.0.15
  */
 public static function maybe_cancel_paypal_after_switch($order_id, $old_status, $new_status)
 {
     $order_completed = in_array($new_status, array(apply_filters('woocommerce_payment_complete_order_status', 'processing', $order_id), 'processing', 'completed')) && in_array($old_status, apply_filters('woocommerce_valid_order_statuses_for_payment', array('pending', 'on-hold', 'failed')));
     if ($order_completed && wcs_order_contains_switch($order_id) && 'paypal_standard' == get_post_meta($order_id, '_old_payment_method', true)) {
         $old_profile_id = get_post_meta($order_id, '_old_paypal_subscription_id', true);
         if (!empty($old_profile_id)) {
             $subscriptions = wcs_get_subscriptions_for_order($order_id, array('order_type' => 'switch'));
             foreach ($subscriptions as $subscription) {
                 if (!wcs_is_paypal_profile_a($old_profile_id, 'billing_agreement')) {
                     $new_payment_method = $subscription->payment_method;
                     $new_profile_id = get_post_meta($subscription->id, '_paypal_subscription_id', true);
                     // grab the current paypal subscription id in case it's a billing agreement
                     update_post_meta($subscription->id, '_payment_method', 'paypal');
                     update_post_meta($subscription->id, '_paypal_subscription_id', $old_profile_id);
                     WCS_PayPal_Status_Manager::suspend_subscription($subscription);
                     // restore payment meta to the new data
                     update_post_meta($subscription->id, '_payment_method', $new_payment_method);
                     update_post_meta($subscription->id, '_paypal_subscription_id', $new_profile_id);
                 }
             }
         }
     }
 }
Beispiel #12
0
 /**
  * The '_switched_subscription_key' and '_switched_subscription_new_order' post meta values are no longer used to relate orders
  * and switched subscriptions, instead, we need to set a '_subscription_switch' value on the switch order and depreacted the old
  * meta keys by prefixing them with '_wcs_migrated'.
  *
  * Subscriptions also sets a '_switched_subscription_item_id' value on the new line item of for the switched item and a item meta
  * value of '_switched_subscription_new_item_id' on the old line item on the subscription, but the old switching process didn't
  * change order items, it just created a new order with the new item, so we won't bother setting this as it is purely for record
  * keeping.
  *
  * @param WC_Subscription $new_subscription A subscription object
  * @param WC_Order $switch_order The original order used to purchase the subscription
  * @param int $subscription_item_id The order item ID of the item added to the subscription by self::add_product()
  * @return null
  * @since 2.0
  */
 private static function migrate_switch_meta($new_subscription, $switch_order, $subscription_item_id)
 {
     global $wpdb;
     // If the order doesn't contain a switch, we don't need to do anything
     if ('' == get_post_meta($switch_order->id, '_switched_subscription_key', true)) {
         return;
     }
     $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET `meta_key` = concat( '_wcs_migrated', `meta_key` )\n\t\t\tWHERE `post_id` = %d AND `meta_key` IN ('_switched_subscription_first_payment_timestamp','_switched_subscription_key')", $switch_order->id));
     // Select the orders which had the items which were switched by this order
     $previous_order_id = get_posts(array('post_type' => 'shop_order', 'post_status' => 'any', 'fields' => 'ids', 'posts_per_page' => -1, 'meta_query' => array(array('key' => '_switched_subscription_new_order', 'value' => $switch_order->id))));
     if (!empty($previous_order_id)) {
         $previous_order_id = $previous_order_id[0];
         $wpdb->query($wpdb->prepare("UPDATE {$wpdb->postmeta} SET `meta_key` = concat( '_wcs_migrated', `meta_key` )\n\t\t\t\tWHERE `post_id` = %d AND `meta_key` = '_switched_subscription_new_order'", $previous_order_id));
         // Because self::get_subscriptions() orders by order ID, it's safe to use wcs_get_subscriptions_for_order() here because the subscription in the new format will have been created for the original order (because its ID will be < the switch order's ID)
         $old_subscriptions = wcs_get_subscriptions_for_order($previous_order_id);
         $old_subscription = array_shift($old_subscriptions);
         // there can be only one
         if (wcs_is_subscription($old_subscription)) {
             // Link the old subscription's ID to the switch order using the new switch meta key
             update_post_meta($switch_order->id, '_subscription_switch', $old_subscription->id);
             // Now store the new/old item IDs for record keeping
             foreach ($old_subscription->get_items() as $item_id => $item) {
                 wc_add_order_item_meta($item_id, '_switched_subscription_new_item_id', $subscription_item_id, true);
                 wc_add_order_item_meta($subscription_item_id, '_switched_subscription_item_id', $item_id, true);
             }
             WCS_Upgrade_Logger::add(sprintf('For subscription %d: migrated switch data for subscription %d purchased in order %d', $new_subscription->id, $old_subscription->id, $previous_order_id));
         }
     }
 }
 /**
  * Store the customer and card IDs on the order and subscriptions in the order.
  *
  * @param int $order_id
  * @param string $customer_id
  */
 protected function save_subscription_meta($order_id, $customer_id)
 {
     $customer_id = wc_clean($customer_id);
     update_post_meta($order_id, '_simplify_customer_id', $customer_id);
     // Also store it on the subscriptions being purchased in the order
     foreach (wcs_get_subscriptions_for_order($order_id) as $subscription) {
         update_post_meta($subscription->id, '_simplify_customer_id', $customer_id);
     }
 }
 /**
  * Returns the renewal orders for a given parent order
  *
  * @param int $order_id The ID of a WC_Order object.
  * @param string $output (optional) How you'd like the result. Can be 'ID' for IDs only or 'WC_Order' for order objects.
  * @since 1.2
  * @deprecated 2.0
  */
 public static function get_renewal_orders($order_id, $output = 'ID')
 {
     _deprecated_function(__METHOD__, '2.0', 'WC_Subscription::get_related_orders()');
     $subscriptions = wcs_get_subscriptions_for_order($order_id, array('order_type' => 'parent'));
     $subscription = array_shift($subscriptions);
     if ('WC_Order' == $output) {
         $renewal_orders = $subscription->get_related_orders('all', 'renewal');
     } else {
         $renewal_orders = $subscription->get_related_orders('ids', 'renewal');
     }
     return apply_filters('woocommerce_subscriptions_renewal_orders', $renewal_orders, $order_id);
 }
 /**
  * Creates a 2.0 updated version of the "subscriptions_switched" callback for developers to hook onto.
  *
  * The subscription passed to the new `woocommerce_subscriptions_switched_item` callback is strictly the subscription
  * to which the `$new_order_item` belongs to; this may be a new or the original subscription.
  *
  * @since 2.0.5
  * @param WC_Order $order
  */
 public static function maybe_add_switched_callback($order)
 {
     if (wcs_order_contains_switch($order)) {
         $subscriptions = wcs_get_subscriptions_for_order($order);
         foreach ($subscriptions as $subscription) {
             foreach ($subscription->get_items() as $new_order_item) {
                 if (isset($new_order_item['switched_subscription_item_id'])) {
                     $product_id = wcs_get_canonical_product_id($new_order_item);
                     // we need to check if the switch order contains the line item that has just been switched so that we don't call the hook on items that were previously switched in another order
                     foreach ($order->get_items() as $order_item) {
                         if (wcs_get_canonical_product_id($order_item) == $product_id) {
                             do_action('woocommerce_subscriptions_switched_item', $subscription, $new_order_item, WC_Subscriptions_Order::get_item_by_id($new_order_item['switched_subscription_item_id']));
                             break;
                         }
                     }
                 }
             }
         }
     }
 }
 /**
  * Override quantities used to lower stock levels by when using synced subscriptions. If it's a synced product
  * that does not have proration enabled and the payment date is not today, do not lower stock levels.
  *
  * @param integer $qty the original quantity that would be taken out of the stock level
  * @param array $order order data
  * @param array $item item data for each item in the order
  *
  * @return int
  */
 public static function maybe_do_not_reduce_stock($qty, $order, $order_item)
 {
     if (wcs_order_contains_subscription($order, array('parent', 'resubscribe')) && 0 == $order_item['line_total']) {
         $subscriptions = wcs_get_subscriptions_for_order($order);
         $product_id = wcs_get_canonical_product_id($order_item);
         foreach ($subscriptions as $subscription) {
             if (self::subscription_contains_synced_product($subscription) && $subscription->has_product($product_id)) {
                 foreach ($subscription->get_items() as $subscription_item) {
                     if (wcs_get_canonical_product_id($subscription_item) == $product_id && 0 < $subscription_item['line_total']) {
                         $qty = 0;
                     }
                 }
             }
         }
     }
     return $qty;
 }
 /**
  * Returns an array of order IDs for valid orders that grant group
  * membership for the given group to the user related to the order.
  * 
  * @param int $user_id
  * @param int $group_id
  * @return array of int, order IDs
  */
 public static function get_valid_order_ids_granting_group_membership_from_order_items($user_id, $group_id)
 {
     $order_ids = array();
     if (!empty($user_id)) {
         $base_statuses = array('processing', 'completed');
         $statuses = array('completed');
         $options = get_option('groups-woocommerce', array());
         $order_status = isset($options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS]) ? $options[GROUPS_WS_MEMBERSHIP_ORDER_STATUS] : GROUPS_WS_DEFAULT_MEMBERSHIP_ORDER_STATUS;
         if ($order_status == 'processing') {
             $statuses[] = 'processing';
         }
         // DO NOT use groups_ws_order_status( $statuses ) for $statuses or $base_statuses here,
         // $order->status doesn't provide the wc- prefix.
         $groups_product_groups = get_user_meta($user_id, '_groups_product_groups', true);
         if (empty($groups_product_groups)) {
             $groups_product_groups = array();
         }
         foreach ($groups_product_groups as $order_id => $product_ids) {
             if ($order = Groups_WS_Helper::get_order($order_id)) {
                 // If this is a completed/processing order, consider group assignments.
                 // We check the order status for non-subscription products below,
                 // for subscriptions the subscription status is checked.
                 if (in_array($order->status, $base_statuses)) {
                     // Note that for orders placed with versions up to 1.4.1, the following won't give the results we might expect if the product group-related information has changed since the order was placed.
                     // As we don't store that information (WC doesn't store the whole lot of the product when purchased, nor does GW) checking the duration based on the product is the best effort at
                     // finding out about the group membership duration we can make.
                     // Use the order items (only existing order items are taken into account).
                     if ($items = $order->get_items()) {
                         foreach ($items as $item) {
                             if ($product = $order->get_product_from_item($item)) {
                                 // Use the groups that were stored for the product when it was ordered,
                                 // this avoids hickups when the product's groups were changed since.
                                 if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['groups'])) {
                                     $product_groups = $product_ids[$product->id]['groups'];
                                     if (in_array($group_id, $product_groups)) {
                                         // non-subscriptions
                                         if (!class_exists('WC_Subscriptions_Product') || !WC_Subscriptions_Product::is_subscription($product->id)) {
                                             if (in_array($order->status, $statuses)) {
                                                 if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) {
                                                     $has_duration = isset($product_ids[$product->id]['duration']) && $product_ids[$product->id]['duration'] && isset($product_ids[$product->id]['duration_uom']);
                                                 } else {
                                                     $has_duration = Groups_WS_Product::has_duration($product);
                                                 }
                                                 // unlimited membership
                                                 if (!$has_duration) {
                                                     if (!in_array($order_id, $order_ids)) {
                                                         $order_ids[] = $order_id;
                                                     }
                                                 } else {
                                                     if (isset($product_ids[$product->id]) && isset($product_ids[$product->id]['version'])) {
                                                         $duration = Groups_WS_Product::calculate_duration($product_ids[$product->id]['duration'], $product_ids[$product->id]['duration_uom']);
                                                     } else {
                                                         // <= 1.4.1
                                                         $duration = Groups_WS_Product::get_duration($product);
                                                     }
                                                     // time-limited membership
                                                     if ($duration) {
                                                         $start_date = $order->order_date;
                                                         if ($paid_date = get_post_meta($order_id, '_paid_date', true)) {
                                                             $start_date = $paid_date;
                                                         }
                                                         $end = strtotime($start_date) + $duration;
                                                         if (time() < $end) {
                                                             if (!in_array($order_id, $order_ids)) {
                                                                 $order_ids[] = $order_id;
                                                             }
                                                         }
                                                     }
                                                 }
                                             }
                                         } else {
                                             // include active subscriptions ( subscriptions >= 2.x )
                                             if (function_exists('wcs_get_subscriptions_for_order')) {
                                                 if ($subscriptions = wcs_get_subscriptions_for_order($order_id)) {
                                                     if (is_array($subscriptions)) {
                                                         foreach ($subscriptions as $subscription) {
                                                             if ($subscription->has_product($product->id)) {
                                                                 $valid = false;
                                                                 if ($subscription->get_status() == 'active') {
                                                                     $valid = true;
                                                                 } else {
                                                                     if ($subscription->get_status() == 'cancelled') {
                                                                         $hook_args = array('subscription_id' => $subscription->id);
                                                                         $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args);
                                                                         if ($end_timestamp !== false && $end_timestamp > time()) {
                                                                             $valid = true;
                                                                         }
                                                                     }
                                                                 }
                                                                 if ($valid) {
                                                                     if (!in_array($order_id, $order_ids)) {
                                                                         $order_ids[] = $order_id;
                                                                         break;
                                                                     }
                                                                 }
                                                             }
                                                         }
                                                     }
                                                 }
                                             } else {
                                                 $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id);
                                                 $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key);
                                                 if (isset($subscription['status'])) {
                                                     $valid = false;
                                                     if ($subscription['status'] == 'active') {
                                                         $valid = true;
                                                     } else {
                                                         if ($subscription['status'] == 'cancelled') {
                                                             $hook_args = array('user_id' => (int) $user_id, 'subscription_key' => $subscription_key);
                                                             $end_timestamp = wp_next_scheduled('scheduled_subscription_end_of_prepaid_term', $hook_args);
                                                             if ($end_timestamp !== false && $end_timestamp > time()) {
                                                                 $valid = true;
                                                             }
                                                         }
                                                     }
                                                     if ($valid) {
                                                         if (!in_array($order_id, $order_ids)) {
                                                             $order_ids[] = $order_id;
                                                         }
                                                     }
                                                 }
                                             }
                                         }
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
     }
     return $order_ids;
 }
 /**
  * Store the Payeezy card data on the order and subscriptions in the order
  *
  * @param int $order_id
  * @param array $card
  */
 protected function save_subscription_meta($order_id, $card)
 {
     update_post_meta($order_id, '_payeezy_token', $card['token']);
     update_post_meta($order_id, '_payeezy_expiry', $card['expiry']);
     update_post_meta($order_id, '_payeezy_cardtype', $card['cardtype']);
     // Also store it on the subscriptions being purchased in the order
     foreach (wcs_get_subscriptions_for_order($order_id) as $subscription) {
         update_post_meta($subscription->id, '_payeezy_token', $card['token']);
         update_post_meta($subscription->id, '_payeezy_expiry', $card['expiry']);
         update_post_meta($subscription->id, '_payeezy_cardtype', $card['cardtype']);
     }
 }
Beispiel #19
0
		/**
		 * Store the customer and card IDs on the order and subscriptions in the order
		 *
		 * @param int $order_id
		 * @param string $customer_id
		 */
		protected function save_subscription_meta( $order_id, $customer_id ) {
			$customer_id = wc_clean( $customer_id );
			update_post_meta( $order_id, '_nab_crn', $customer_id );

			// Also store it on the subscriptions being purchased in the order
			if (function_exists('wcs_get_subscriptions_for_order')) {
				foreach( wcs_get_subscriptions_for_order( $order_id ) as $subscription ) {
					update_post_meta( $subscription->id, '_nab_crn', $customer_id );
				}
			}
		}
/**
 * Checks an order to see if it contains a subscription.
 *
 * @param mixed $order A WC_Order object or the ID of the order which the subscription was purchased in.
 * @param array|string $order_type Can include 'parent', 'renewal', 'resubscribe' and/or 'switch'. Defaults to 'parent'.
 * @return bool True if the order contains a subscription that belongs to any of the given order types, otherwise false.
 * @since 2.0
 */
function wcs_order_contains_subscription($order, $order_type = array('parent', 'resubscribe', 'switch'))
{
    // Accept either an array or string (to make it more convenient for singular types, like 'parent' or 'any')
    if (!is_array($order_type)) {
        $order_type = array($order_type);
    }
    if (!is_object($order)) {
        $order = new WC_Order($order);
    }
    $contains_subscription = false;
    $get_all = in_array('any', $order_type) ? true : false;
    if ((in_array('parent', $order_type) || $get_all) && count(wcs_get_subscriptions_for_order($order->id, array('order_type' => 'parent'))) > 0) {
        $contains_subscription = true;
    } elseif ((in_array('renewal', $order_type) || $get_all) && wcs_order_contains_renewal($order)) {
        $contains_subscription = true;
    } elseif ((in_array('resubscribe', $order_type) || $get_all) && wcs_order_contains_resubscribe($order)) {
        $contains_subscription = true;
    } elseif ((in_array('switch', $order_type) || $get_all) && wcs_order_contains_switch($order)) {
        $contains_subscription = true;
    }
    return $contains_subscription;
}
 /**
  * Records the initial payment against a subscription.
  *
  * This function is called when a gateway calls @see WC_Order::payment_complete() and payment
  * is completed on an order. It is also called when an orders status is changed to completed or
  * processing for those gateways which never call @see WC_Order::payment_complete(), like the
  * core WooCommerce Cheque and Bank Transfer gateways.
  *
  * It will also set the start date on the subscription to the time the payment is completed.
  *
  * @param WC_Order|int $order A WC_Order object or ID of a WC_Order order.
  * @since 1.1.2
  * @deprecated 2.0
  */
 public static function maybe_record_order_payment($order)
 {
     _deprecated_function(__METHOD__, '2.0', __CLASS__ . 'maybe_record_subscription_payment::( $order, $old_status, $new_status )');
     if (!wcs_order_contains_renewal($order)) {
         $subscriptions = wcs_get_subscriptions_for_order($order, array('order_type' => 'parent'));
         foreach ($subscriptions as $subscription_id => $subscription) {
             // No payments have been recorded yet
             if (0 == $subscription->get_completed_payment_count()) {
                 $subscription->update_dates(array('start' => current_time('mysql', true)));
                 $subscription->payment_complete();
             }
         }
     }
 }
 /**
  * process_payment
  *
  * Completes the initial payment on the subscription order
  *
  * Although PayPal Braintree supports subscription products (they call them plans),
  * they don't support the wide variety of intervals we do, nor multiple subscription
  * products in a single order.
  *
  * So, this extension does all the subscription work itself, storing a customer
  * in the vault on the first payment, and using those stored credentials for
  * renewal orders
  *
  * @param  int $order_id
  * @return mixed
  */
 public function process_payment($order_id)
 {
     // If the order contains no subscriptions, just let the parent process it
     if (!$this->order_contains_subscription($order_id)) {
         return parent::process_payment($order_id);
     }
     $order = new WC_Order($order_id);
     $this->log(__FUNCTION__, "Info: Beginning processing of payment for (subscription) order {$order_id} for the amount of {$order->order_total}");
     $this->log(__FUNCTION__, "Info: Merchant ID = {$this->merchant_id}");
     $paypal_braintree_nonce = self::get_posted_variable('paypalbraintree_nonce');
     if (empty($paypal_braintree_nonce)) {
         $this->log(__FUNCTION__, 'Error: The paypal_braintree_nonce was unexpectedly empty');
         wc_add_notice(__('Error: PayPal Powered by Braintree did not supply a payment nonce. Please try again later or use another means of payment.', 'woocommerce-gateway-paypal-braintree'), 'error');
         return false;
     }
     $user_id = $order->get_user_id();
     if (!is_user_logged_in()) {
         $this->log(__FUNCTION__, 'Error: No user logged in / being created for the initial subscription payment');
         wc_add_notice(__('Error: You must login or create an account before you can purchase a subscription.', 'woocommerce-gateway-paypal-braintree'), 'error');
         return false;
     }
     // Create the gateway instance up front
     require_once dirname(__FILE__) . '/../braintree_sdk/lib/Braintree.php';
     $gateway = new Braintree_Gateway(array('accessToken' => $this->merchant_access_token));
     // Check their user meta for a stored braintree customer id
     $braintree_customer_id = get_user_meta($user_id, '_wc_paypal_braintree_customer_id', true);
     if (empty($braintree_customer_id)) {
         $this->log(__FUNCTION__, 'Info: Did not find braintree customer id on user meta. Need to create customer');
         // Create a new customer id, passing the nonce so we can add the card to the vault
         // ref https://developers.braintreepayments.com/reference/request/customer/create/php
         $customer_args = array('firstName' => $order->billing_first_name, 'lastName' => $order->billing_last_name, 'company' => $order->billing_company, 'phone' => $order->billing_phone, 'email' => $order->billing_email, 'paymentMethodNonce' => $paypal_braintree_nonce);
         try {
             $result = $gateway->customer()->create($customer_args);
         } catch (Exception $e) {
             $this->log(__FUNCTION__, 'Error: Unable to create customer. Reason: ' . $e->getMessage());
             wc_add_notice(__('Error: PayPal Powered by Braintree was unable to create a customer record for you. Please try again later or use another means of payment.', 'woocommerce-gateway-paypal-braintree'), 'error');
             return false;
         }
         if (!$result->success) {
             $this->log(__FUNCTION__, "Error: Unable to create customer: {$result->message}");
             wc_add_notice(__('Error: PayPal Powered by Braintree was unable to create a customer record for you. Please try again later or use another means of payment.', 'woocommerce-gateway-paypal-braintree'), 'error');
             return false;
         }
         $braintree_customer_id = $result->customer->id;
         update_user_meta($user_id, '_wc_paypal_braintree_customer_id', $braintree_customer_id);
         $this->log(__FUNCTION__, "Info: Created customer successfully - braintree customer id = {$braintree_customer_id}");
         $payment_methods = $result->customer->paymentMethods;
         $payment_method_token = '';
         foreach ((array) $payment_methods as $payment_method) {
             if ($payment_method->default) {
                 $payment_method_token = $payment_method->token;
             }
         }
         $authentication = array('paymentMethodToken' => $payment_method_token);
     } else {
         // We found the braintree customer id in the customer's meta
         $this->log(__FUNCTION__, "Info: Found a braintree customer id in the users meta - customer id = {$braintree_customer_id}");
         $authentication = array('paymentMethodNonce' => $paypal_braintree_nonce);
     }
     $sale_args = $this->generate_sales_args($order, $braintree_customer_id);
     $sale_args = array_merge($sale_args, $authentication);
     $transaction_id = '';
     // Process trial periods and possible coupon discounts.
     if (isset($sale_args['amount']) && 0.0 === doubleval($sale_args['amount'])) {
         $user_id = $order->get_user_id();
         $this->log(__FUNCTION__, "Zero payment amount for trial or coupon. Order ID: {$order_id}, User ID:  {$user_id}");
         $customer = $gateway->customer()->find($braintree_customer_id);
         $payment_method_token = '';
         foreach ((array) $customer->paymentMethods as $payment_method) {
             if ($payment_method->default) {
                 $payment_method_token = $payment_method->token;
             }
         }
     } else {
         // charges more than zero should be sent away
         // We have a customer id now, so let's do the sale and store the payment method in the vault.
         $result = $gateway->transaction()->sale($sale_args);
         if (!$result->success) {
             $notice = sprintf(__('Error: PayPal Powered by Braintree was unable to complete the transaction. Please try again later or use another means of payment. Reason: %s', 'woocommerce-gateway-paypal-braintree'), $error_message);
             wc_add_notice($notice, 'error');
             $this->log(__FUNCTION__, "Error: Unable to complete transaction. Reason: {$result->message}");
             return false;
         }
         $transaction_id = $result->transaction->id;
         $this->log(__FUNCTION__, "Info: Successfully processed initial payment, transaction id = {$transaction_id}");
         $credit_card_meta = $result->transaction->creditCard;
         $payment_method_token = $credit_card_meta['token'];
         if (empty($payment_method_token)) {
             $this->log(__FUNCTION__, 'Info: Customer used the paypal subflow');
             $paypal_meta = $result->transaction->paypal;
             $payment_method_token = $paypal_meta['token'];
         } else {
             $this->log(__FUNCTION__, 'Info: Customer used the credit card subflow');
         }
         $braintree_customer_id = $result->transaction->customer['id'];
     }
     if (empty($payment_method_token)) {
         $this->log(__FUNCTION__, 'Warning: Initial payment succeeded, but no token was provided by the gateway for recurring payments.');
     }
     // Save the customer ID in each subscription for this order for later use during renewal
     if (empty($braintree_customer_id)) {
         $this->log(__FUNCTION__, 'Warning: Initial payment succeeded, but no braintree customer ID was provided by the gateway for recurring payments.');
     } else {
         $this->log(__FUNCTION__, "Info: Saving to subscription(s) recurring payment braintree customer ID {$braintree_customer_id}");
     }
     // Note: A single order may contain multiple subscriptions
     // Save the token in each subscription for this order for later use during renewal
     foreach (wcs_get_subscriptions_for_order($order->id) as $subscription) {
         update_post_meta($subscription->id, '_wc_paypal_braintree_payment_method_token', $payment_method_token);
         update_post_meta($subscription->id, '_wc_paypal_braintree_customer_id', $braintree_customer_id);
     }
     $order->payment_complete($transaction_id);
     $this->log(__FUNCTION__, "Info: Completed processing of payment for order {$order_id}");
     return array('result' => 'success', 'redirect' => $this->get_return_url($order));
 }
 /**
  * Returns the string key for a subscription purchased in an order specified by $order_id
  *
  * @param order_id int The ID of the order in which the subscription was purchased.
  * @param product_id int The ID of the subscription product.
  * @return string The key representing the given subscription.
  * @since 1.0
  */
 public static function get_subscription_key($order_id, $product_id = '')
 {
     _deprecated_function(__METHOD__, '2.0', 'wcs_get_old_subscription_key( WC_Subscription $subscription )');
     // If we have a child renewal order, we need the parent order's ID
     if (wcs_order_contains_renewal($order_id)) {
         $order_id = WC_Subscriptions_Renewal_Order::get_parent_order_id($order_id);
     }
     // Get the ID of the first order item in a subscription created by this order
     if (empty($product_id)) {
         $subscriptions = wcs_get_subscriptions_for_order($order_id, array('order_type' => 'parent'));
         foreach ($subscriptions as $subscription) {
             $subscription_items = $subscription->get_items();
             if (!empty($subscription_items)) {
                 break;
             }
         }
         if (!empty($subscription_items)) {
             $first_item = reset($subscription_items);
             $product_id = WC_Subscriptions_Order::get_items_product_id($first_item);
         } else {
             $product_id = '';
         }
     }
     $subscription_key = $order_id . '_' . $product_id;
     return apply_filters('woocommerce_subscription_key', $subscription_key, $order_id, $product_id);
 }
 /**
  * When a store manager or user reactivates a subscription in the store, also reactivate the subscription with PayPal.
  *
  * How PayPal Handles suspension is discussed here: https://www.x.com/developers/paypal/forums/nvp/reactivate-recurring-profile
  *
  * @since 1.1
  */
 public static function reactivate_subscription_with_paypal($order, $product_id)
 {
     _deprecated_function(__METHOD__, '2.0', 'WCS_PayPal::reactivate_subscription( $subscription )');
     foreach (wcs_get_subscriptions_for_order($order, array('order_type' => 'parent')) as $subscription) {
         WCS_PayPal_Status_Manager::reactivate_subscription($subscription);
     }
 }
 /**
  * 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;
 }
Beispiel #26
0
    exit;
}
// Display Klarna iframe
if ($this->is_rest()) {
    $snippet = '<div>' . $klarna_order['html_snippet'] . '</div>';
} else {
    $snippet = '<div class="klarna-thank-you-snippet">' . $klarna_order['gui']['snippet'] . '</div>';
}
do_action('klarna_before_kco_confirmation', intval($_GET['sid']));
// WC Subscriptions 2.0 needs this
if (class_exists('WC_Subscriptions_Cart') && WC_Subscriptions_Cart::cart_contains_subscription()) {
    sleep(5);
    $parent_order = new WC_Order(intval($_GET['sid']));
    $subscriptions = array();
    // First clear out any subscriptions created for a failed payment to give us a clean slate for creating new subscriptions
    $subscriptions = wcs_get_subscriptions_for_order($parent_order->id, array('order_type' => 'parent'));
    if (!empty($subscriptions)) {
        foreach ($subscriptions as $subscription) {
            wp_delete_post($subscription->id);
        }
    }
    WC()->cart->calculate_totals();
    // Create new subscriptions for each group of subscription products in the cart (that is not a renewal)
    foreach (WC()->cart->recurring_carts as $recurring_cart) {
        $subscription = WC_Subscriptions_Checkout::create_subscription($parent_order, $recurring_cart);
        // Exceptions are caught by WooCommerce
        $subscription->payment_complete();
        if (is_wp_error($subscription)) {
            throw new Exception($subscription->get_error_message());
        }
        do_action('woocommerce_checkout_subscription_created', $subscription, $parent_order, $recurring_cart);
 /**
  * Process an initial subscription payment if the order contains a
  * subscription, otherwise use the parent::process_payment() method
  *
  * @since  1.4
  * @param int $order_id the order identifier
  * @return array
  */
 public function process_payment($order_id)
 {
     require_once 'class-wc-realex-api.php';
     // processing subscription (which means we are ineligible for 3DSecure for now)
     if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0() ? wcs_order_contains_subscription($order_id) : WC_Subscriptions_Order::order_contains_subscription($order_id)) {
         $order = wc_get_order($order_id);
         // redirect to payment page for payment if 3D secure is enabled
         if ($this->get_threedsecure()->is_3dsecure_available() && !SV_WC_Helper::get_post('woocommerce_pay_page')) {
             // empty cart before redirecting from Checkout page
             WC()->cart->empty_cart();
             // redirect to payment page to continue payment
             return array('result' => 'success', 'redirect' => $order->get_checkout_payment_url(true));
         }
         $order->payment_total = SV_WC_Helper::number_format(SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0() ? $order->get_total() : WC_Subscriptions_Order::get_total_initial_payment($order));
         // create the realex api client
         $realex_client = new Realex_API($this->get_endpoint_url(), $this->get_realvault_endpoint_url(), $this->get_shared_secret());
         // create the customer/cc tokens, and authorize the initial payment amount, if any
         $result = $this->authorize($realex_client, $order);
         // subscription with initial payment, everything is now taken care of
         if (is_array($result)) {
             // for Subscriptions 2.0.x, save payment token to subscription object
             if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) {
                 // a single order can contain multiple subscriptions
                 foreach (wcs_get_subscriptions_for_order($order->id) as $subscription) {
                     // payment token
                     update_post_meta($subscription->id, '_realex_cardref', get_post_meta($order->id, '_realex_cardref', true));
                 }
             }
             return $result;
         }
         // otherwise there was no initial payment, so we mark the order as complete, etc
         if ($order->payment_total == 0) {
             // mark order as having received payment
             $order->payment_complete();
             WC()->cart->empty_cart();
             return array('result' => 'success', 'redirect' => $this->get_return_url($order));
         }
     } else {
         // processing regular product
         return parent::process_payment($order_id);
     }
 }
 /**
  * Checks a set of args and derives an Order ID with backward compatibility for WC < 1.7 where 'custom' was the Order ID.
  *
  * @since 2.0
  */
 public static function get_order_id_and_key($args, $order_type = 'shop_order')
 {
     $order_id = $order_key = '';
     if (isset($args['subscr_id'])) {
         // PayPal Standard IPN message
         $subscription_id = $args['subscr_id'];
     } elseif (isset($args['recurring_payment_id'])) {
         // PayPal Express Checkout IPN, most likely 'recurring_payment_suspended_due_to_max_failed_payment', for a PayPal Standard Subscription
         $subscription_id = $args['recurring_payment_id'];
     } else {
         $subscription_id = '';
     }
     // First try and get the order ID by the subscription ID
     if (!empty($subscription_id)) {
         $posts = get_posts(array('numberposts' => 1, 'orderby' => 'ID', 'order' => 'ASC', 'meta_key' => '_paypal_subscription_id', 'meta_value' => $subscription_id, 'post_type' => $order_type, 'post_status' => 'any', 'suppress_filters' => true));
         if (!empty($posts)) {
             $order_id = $posts[0]->ID;
             $order_key = get_post_meta($order_id, '_order_key', true);
         }
     }
     // Couldn't find the order ID by subscr_id, so it's either not set on the order yet or the $args doesn't have a subscr_id, either way, let's get it from the args
     if (empty($order_id) && isset($args['custom'])) {
         // WC < 1.6.5
         if (is_numeric($args['custom']) && 'shop_order' == $order_type) {
             $order_id = $args['custom'];
             $order_key = $args['invoice'];
         } else {
             $order_details = json_decode($args['custom']);
             if (is_object($order_details)) {
                 // WC 2.3.11+ converted the custom value to JSON, if we have an object, we've got valid JSON
                 if ('shop_order' == $order_type) {
                     $order_id = $order_details->order_id;
                     $order_key = $order_details->order_key;
                 } elseif (isset($order_details->subscription_id)) {
                     // Subscription created with Subscriptions 2.0+
                     $order_id = $order_details->subscription_id;
                     $order_key = $order_details->subscription_key;
                 } else {
                     // Subscription created with Subscriptions < 2.0
                     $subscriptions = wcs_get_subscriptions_for_order($order_details->order_id, array('order_type' => array('parent')));
                     if (!empty($subscriptions)) {
                         $subscription = array_pop($subscriptions);
                         $order_id = $subscription->id;
                         $order_key = $subscription->order_key;
                     }
                 }
             } elseif (preg_match('/^a:2:{/', $args['custom']) && !preg_match('/[CO]:\\+?[0-9]+:"/', $args['custom']) && ($order_details = maybe_unserialize($args['custom']))) {
                 // WC 2.0 - WC 2.3.11, only allow serialized data in the expected format, do not allow objects or anything nasty to sneak in
                 if ('shop_order' == $order_type) {
                     $order_id = $order_details[0];
                     $order_key = $order_details[1];
                 } else {
                     // Subscription, but we didn't have the subscription data in old, serialized value, so we need to pull it based on the order
                     $subscriptions = wcs_get_subscriptions_for_order($order_details[0], array('order_type' => array('parent')));
                     if (!empty($subscriptions)) {
                         $subscription = array_pop($subscriptions);
                         $order_id = $subscription->id;
                         $order_key = $subscription->order_key;
                     }
                 }
             } else {
                 // WC 1.6.5 - WC 2.0 or invalid data
                 $order_id = str_replace(WCS_PayPal::get_option('invoice_prefix'), '', $args['invoice']);
                 $order_key = $args['custom'];
             }
         }
     }
     return array('order_id' => (int) $order_id, 'order_key' => $order_key);
 }
 /**
  * Store the billing and shipping addresses for this order in meta
  * for both the order and the subscriptions it contains
  *
  * @param int    $order_id
  * @param object $response SetBillingAgreementDetails response object
  */
 function store_subscription_destination($order_id, $response)
 {
     if (!is_wp_error($response) && isset($response->GetBillingAgreementDetailsResult->BillingAgreementDetails->Destination->PhysicalDestination)) {
         $billing_agreement_details = $response->GetBillingAgreementDetailsResult->BillingAgreementDetails;
         $this->store_order_address_details($order_id, $billing_agreement_details);
         $subscriptions = wcs_get_subscriptions_for_order($order_id);
         foreach ($subscriptions as $subscription) {
             $this->store_order_address_details($subscription->id, $billing_agreement_details);
         }
     }
 }
 /**
  * Create subscriptions purchased on checkout.
  *
  * @param int $order_id The post_id of a shop_order post/WC_Order object
  * @param array $posted_data The data posted on checkout
  * @since 2.0
  */
 public static function process_checkout($order_id, $posted_data)
 {
     if (!WC_Subscriptions_Cart::cart_contains_subscription()) {
         return;
     }
     $order = new WC_Order($order_id);
     $subscriptions = array();
     // First clear out any subscriptions created for a failed payment to give us a clean slate for creating new subscriptions
     $subscriptions = wcs_get_subscriptions_for_order($order->id, array('order_type' => 'parent'));
     if (!empty($subscriptions)) {
         remove_action('before_delete_post', 'WC_Subscriptions_Manager::maybe_cancel_subscription');
         foreach ($subscriptions as $subscription) {
             wp_delete_post($subscription->id);
         }
         add_action('before_delete_post', 'WC_Subscriptions_Manager::maybe_cancel_subscription');
     }
     WC_Subscriptions_Cart::set_global_recurring_shipping_packages();
     // Create new subscriptions for each group of subscription products in the cart (that is not a renewal)
     foreach (WC()->cart->recurring_carts as $recurring_cart) {
         $subscription = self::create_subscription($order, $recurring_cart);
         // Exceptions are caught by WooCommerce
         if (is_wp_error($subscription)) {
             throw new Exception($subscription->get_error_message());
         }
         do_action('woocommerce_checkout_subscription_created', $subscription, $order, $recurring_cart);
     }
     do_action('subscriptions_created_for_order', $order);
     // Backward compatibility
 }