/** * Prompt the store manager to enter their PayPal API credentials if they are using * PayPal and have yet not entered their API credentials. * * @return void */ public static function maybe_show_admin_notice() { self::get_wc_paypal_settings(); if (!in_array(get_woocommerce_currency(), apply_filters('woocommerce_paypal_supported_currencies', array('AUD', 'BRL', 'CAD', 'MXN', 'NZD', 'HKD', 'SGD', 'USD', 'EUR', 'JPY', 'TRY', 'NOK', 'CZK', 'DKK', 'HUF', 'ILS', 'MYR', 'PHP', 'PLN', 'SEK', 'CHF', 'TWD', 'THB', 'GBP', 'RMB')))) { $valid_for_use = false; } else { $valid_for_use = true; } if (WC_Subscriptions::is_woocommerce_pre_2_1()) { $payment_gateway_tab_url = admin_url('admin.php?page=woocommerce_settings&tab=payment_gateways§ion=WC_Gateway_Paypal'); } else { $payment_gateway_tab_url = admin_url('admin.php?page=wc-settings&tab=checkout§ion=wc_gateway_paypal'); } if (!self::are_credentials_set() && $valid_for_use && 'yes' == self::$paypal_settings['enabled'] && !has_action('admin_notices', 'WC_Subscriptions_Admin::admin_installed_notice') && current_user_can('manage_options')) { ?> <div id="message" class="updated warning"> <p> <?php printf(__('Just a few more steps to configure PayPal to sell subscriptions. Please %sset up the PayPal IPN%s and %senter your API credentials%s so that you can suspend and cancel subscriptions.', 'woocommerce-subscriptions'), '<a href="http://docs.woothemes.com/document/subscriptions/store-manager-guide/#section-4" target="_blank">', '</a>', '<a href="' . $payment_gateway_tab_url . '">', '</a>'); ?> </p> </div> <?php } }
/** * Add a "Change Payment Method" button to the "My Subscriptions" table. * * @param array $all_actions The $subscription_key => $actions array with all actions that will be displayed for a subscription on the "My Subscriptions" table * @param array $subscriptions All of a given users subscriptions that will be displayed on the "My Subscriptions" table * @since 1.4 */ public static function change_payment_method_button($all_actions, $subscriptions) { foreach ($all_actions as $subscription_key => $actions) { $order = new WC_Order($subscriptions[$subscription_key]['order_id']); if (WC_Subscriptions_Manager::can_subscription_be_changed_to('new-payment-method', $subscription_key, get_current_user_id())) { if (!WC_Subscriptions::is_woocommerce_pre_2_1()) { // WC 2.1+ $url = add_query_arg(array('change_payment_method' => $subscription_key, 'order_id' => $order->id), $order->get_checkout_payment_url()); $url = wp_nonce_url($url, __FILE__); } else { $url = add_query_arg(array('change_payment_method' => $subscription_key, 'order_id' => $order->id, 'order' => $order->order_key), get_permalink(woocommerce_get_page_id('pay'))); $url = wp_nonce_url($url, __FILE__); } $all_actions[$subscription_key] = array('change_payment_method' => array('url' => $url, 'name' => __('Change Payment Method', 'woocommerce-subscriptions'))) + $all_actions[$subscription_key]; } } return $all_actions; }
/** * A WooCommerce version aware function for getting the Subscriptions admin settings * tab URL. * * @since 1.4.5 * @return string */ public static function settings_tab_url() { if (WC_Subscriptions::is_woocommerce_pre_2_1()) { $settings_tab_url = admin_url('admin.php?page=woocommerce_settings&tab=subscriptions'); } else { $settings_tab_url = admin_url('admin.php?page=wc-settings&tab=subscriptions'); } return apply_filters('woocommerce_subscriptions_settings_tab_url', $settings_tab_url); }
/** * Creates a new order for renewing a subscription product based on the details of a previous order. * * No trial periods or sign up fees are applied to the renewal order. However, if the order has failed * payments and the store manager has set failed payments to be added to renewal orders, then the * orders totals will be set to include the outstanding balance. * * If the $args['new_order_role'] flag is set to 'parent', then the renewal order will supersede the existing * order. The existing order and subscription associated with it will be cancelled. A new order and * subscription will be created. * * If the $args['new_order_role'] flag is 'child', the $original_order will remain the master order for the * subscription and the new order is just for accepting a recurring payment on the subscription. * * Renewal orders have the same meta data as the original order. If the renewal order is set to be a 'child' * then any subscription related meta data will not be stored on the new order. This is to keep subscription * meta data associated only with the one master order for the subscription. * * @param WC_Order|int $order The WC_Order object or ID of the order for which the a new order should be created. * @param string $product_id The ID of the subscription product in the order which needs to be added to the new order. * @param array $args (optional) An array of name => value flags: * 'new_order_role' string A flag to indicate whether the new order should become the master order for the subscription. Accepts either 'parent' or 'child'. Defaults to 'parent' - replace the existing order. * 'checkout_renewal' bool Indicates if invoked from an interactive cart/checkout session and certain order items are not set, like taxes, shipping as they need to be set in teh calling function, like @see WC_Subscriptions_Checkout::filter_woocommerce_create_order(). Default false. * 'failed_order_id' int For checkout_renewal true, indicates order id being replaced * @since 1.2 */ public static function generate_renewal_order($original_order, $product_id, $args = array()) { global $wpdb, $woocommerce; if (!is_object($original_order)) { $original_order = new WC_Order($original_order); } if (!WC_Subscriptions_Order::order_contains_subscription($original_order) || !WC_Subscriptions_Order::is_item_subscription($original_order, $product_id)) { return false; } if (self::is_renewal($original_order, array('order_role' => 'child'))) { $original_order = self::get_parent_order($original_order); } if (!is_array($args)) { _deprecated_argument(__CLASS__ . '::' . __FUNCTION__, '1.3', __('Third parameter is now an array of name => value pairs. Use array( "new_order_role" => "parent" ) instead.', 'woocommerce-subscriptions')); $args = array('new_order_role' => $args); } $args = wp_parse_args($args, array('new_order_role' => 'parent', 'checkout_renewal' => false)); $renewal_order_key = uniqid('order_'); // Create the new order $renewal_order_data = array('post_type' => 'shop_order', 'post_title' => sprintf(__('Subscription Renewal Order – %s', 'woocommerce-subscriptions'), strftime(_x('%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', 'woocommerce-subscriptions'))), 'post_status' => 'publish', 'ping_status' => 'closed', 'post_excerpt' => $original_order->customer_note, 'post_author' => 1, 'post_password' => $renewal_order_key); $create_new_order = true; if ('child' == $args['new_order_role']) { $renewal_order_data['post_parent'] = $original_order->id; } if (true === $args['checkout_renewal']) { $renewal_order_id = null; if ($woocommerce->session->order_awaiting_payment > 0) { $renewal_order_id = absint($woocommerce->session->order_awaiting_payment); } elseif (isset($args['failed_order_id'])) { $failed_order_id = $args['failed_order_id']; /* Check order is unpaid by getting its status */ $terms = wp_get_object_terms($failed_order_id, 'shop_order_status', array('fields' => 'slugs')); $order_status = isset($terms[0]) ? $terms[0] : 'pending'; /* If paying on a pending order, we are resuming */ if ($order_status == 'pending') { $renewal_order_id = $failed_order_id; } } if ($renewal_order_id) { /* Check order is unpaid by getting its status */ $terms = wp_get_object_terms($renewal_order_id, 'shop_order_status', array('fields' => 'slugs')); $order_status = isset($terms[0]) ? $terms[0] : 'pending'; // Resume the unpaid order if its pending if ($order_status == 'pending' || $order_status == 'failed') { // Update the existing order as we are resuming it $create_new_order = false; $renewal_order_data['ID'] = $renewal_order_id; wp_update_post($renewal_order_data); // Clear the old line items - we'll add these again in case they changed $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}woocommerce_order_itemmeta WHERE order_item_id IN ( SELECT order_item_id FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d )", $renewal_order_id)); $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d", $renewal_order_id)); } } } if ($create_new_order) { $renewal_order_id = wp_insert_post($renewal_order_data); } // Set the order as pending wp_set_object_terms($renewal_order_id, 'pending', 'shop_order_status'); // Set a unique key for this order update_post_meta($renewal_order_id, '_order_key', $renewal_order_key); $order_meta_query = "SELECT `meta_key`, `meta_value`\n\t\t\t\t\t\t\t FROM {$wpdb->postmeta}\n\t\t\t\t\t\t\t WHERE `post_id` = {$original_order->id}\n\t\t\t\t\t\t\t AND `meta_key` NOT IN ('_paid_date', '_completed_date', '_order_key', '_edit_lock', '_original_order')"; // Superseding existing order so don't carry over payment details if ('parent' == $args['new_order_role'] || true === $args['checkout_renewal']) { $order_meta_query .= " AND `meta_key` NOT IN ('_payment_method', '_payment_method_title', '_recurring_payment_method', '_recurring_payment_method_title', '_shipping_method', '_shipping_method_title', '_recurring_shipping_method', '_recurring_shipping_method_title')"; } else { $order_meta_query .= " AND `meta_key` NOT LIKE '_order_recurring_%' AND `meta_key` NOT IN ('_payment_method', '_payment_method_title', '_recurring_payment_method', '_recurring_payment_method_title', '_shipping_method', '_shipping_method_title', '_recurring_shipping_method', '_recurring_shipping_method_title')"; } // Allow extensions to add/remove order meta $order_meta_query = apply_filters('woocommerce_subscriptions_renewal_order_meta_query', $order_meta_query, $original_order->id, $renewal_order_id, $args['new_order_role']); // Carry all the required meta from the old order over to the new order $order_meta = $wpdb->get_results($order_meta_query, 'ARRAY_A'); $order_meta = apply_filters('woocommerce_subscriptions_renewal_order_meta', $order_meta, $original_order->id, $renewal_order_id, $args['new_order_role']); foreach ($order_meta as $meta_item) { add_post_meta($renewal_order_id, $meta_item['meta_key'], maybe_unserialize($meta_item['meta_value']), true); } $outstanding_balance = WC_Subscriptions_Order::get_outstanding_balance($original_order, $product_id); $failed_payment_multiplier = 1; if (false == $args['checkout_renewal']) { // If there are outstanding payment amounts, add them to the order, otherwise set the order details to the values of the recurring totals if ($outstanding_balance > 0 && 'yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_add_outstanding_balance', 'no')) { $failed_payment_multiplier = WC_Subscriptions_Order::get_failed_payment_count($original_order, $product_id); } // Set order totals based on recurring totals from the original order $cart_discount = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_discount_cart', true); $order_discount = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_discount_total', true); $order_shipping_tax = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_shipping_tax_total', true); $order_shipping = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_shipping_total', true); $order_tax = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_tax_total', true); $order_total = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_total', true); update_post_meta($renewal_order_id, '_cart_discount', $cart_discount); update_post_meta($renewal_order_id, '_order_discount', $order_discount); update_post_meta($renewal_order_id, '_order_shipping_tax', $order_shipping_tax); update_post_meta($renewal_order_id, '_order_shipping', $order_shipping); update_post_meta($renewal_order_id, '_order_tax', $order_tax); update_post_meta($renewal_order_id, '_order_total', $order_total); // Set shipping for orders created with WC 2.0.n (or when we are using WC 2.0.n) if (WC_Subscriptions::is_woocommerce_pre_2_1() || isset($original_order->recurring_shipping_method)) { update_post_meta($renewal_order_id, '_shipping_method', $original_order->recurring_shipping_method); update_post_meta($renewal_order_id, '_shipping_method_title', $original_order->recurring_shipping_method_title); // Also set recurring shipping as it's a parent renewal order if ('parent' == $args['new_order_role']) { update_post_meta($renewal_order_id, '_recurring_shipping_method', $original_order->recurring_shipping_method); update_post_meta($renewal_order_id, '_recurring_shipping_method_title', $original_order->recurring_shipping_method_title); } } // Apply the recurring shipping & payment methods to child renewal orders if ('child' == $args['new_order_role']) { update_post_meta($renewal_order_id, '_payment_method', $original_order->recurring_payment_method); update_post_meta($renewal_order_id, '_payment_method_title', $original_order->recurring_payment_method_title); } // Set order taxes based on recurring taxes from the original order $recurring_order_taxes = WC_Subscriptions_Order::get_recurring_taxes($original_order); foreach ($recurring_order_taxes as $index => $recurring_order_tax) { $item_ids = array(); $item_ids[] = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $recurring_order_tax['name'], 'order_item_type' => 'tax')); // Also set recurring taxes on parent renewal orders if ('parent' == $args['new_order_role']) { $item_ids[] = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $recurring_order_tax['name'], 'order_item_type' => 'recurring_tax')); } // Add line item meta foreach ($item_ids as $item_id) { woocommerce_add_order_item_meta($item_id, 'compound', absint(isset($recurring_order_tax['compound']) ? $recurring_order_tax['compound'] : 0)); woocommerce_add_order_item_meta($item_id, 'tax_amount', woocommerce_clean($failed_payment_multiplier * $recurring_order_tax['tax_amount'])); woocommerce_add_order_item_meta($item_id, 'shipping_tax_amount', woocommerce_clean($failed_payment_multiplier * $recurring_order_tax['shipping_tax_amount'])); if (isset($recurring_order_tax['rate_id'])) { woocommerce_add_order_item_meta($item_id, 'rate_id', $recurring_order_tax['rate_id']); } if (isset($recurring_order_tax['label'])) { woocommerce_add_order_item_meta($item_id, 'label', $recurring_order_tax['label']); } } } // Set up shipping items on renewal order $recurring_shipping_items = WC_Subscriptions_Order::get_recurring_shipping_methods($original_order); foreach ($recurring_shipping_items as $index => $recurring_shipping_item) { $item_ids = array(); $item_ids[] = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $recurring_shipping_item['name'], 'order_item_type' => 'shipping')); // Also set recurring shipping as it's a parent renewal order if ('parent' == $args['new_order_role']) { $item_ids[] = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $recurring_shipping_item['name'], 'order_item_type' => 'recurring_shipping')); } // Add shipping item meta foreach ($item_ids as $item_id) { woocommerce_add_order_item_meta($item_id, 'method_id', $recurring_shipping_item['method_id']); woocommerce_add_order_item_meta($item_id, 'cost', woocommerce_clean($failed_payment_multiplier * $recurring_shipping_item['cost'])); } } } // Set line totals to be recurring line totals and remove the subscription/recurring related item meta from each order item $order_items = WC_Subscriptions_Order::get_recurring_items($original_order); // Allow extensions to add/remove items or item meta $order_items = apply_filters('woocommerce_subscriptions_renewal_order_items', $order_items, $original_order->id, $renewal_order_id, $product_id, $args['new_order_role']); if (true === $args['checkout_renewal']) { $cart_items = $woocommerce->cart->get_cart(); } foreach ($order_items as $item_index => $order_item) { if ('child' == $args['new_order_role']) { $renewal_order_item_name = sprintf(__('Renewal of "%s" purchased in Order %s', 'woocommerce-subscriptions'), $order_item['name'], $original_order->get_order_number()); } else { $renewal_order_item_name = $order_item['name']; } $renewal_order_item_name = apply_filters('woocommerce_subscriptions_renewal_order_item_name', $renewal_order_item_name, $order_item, $original_order); // Create order line item on the renewal order $recurring_item_id = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $renewal_order_item_name, 'order_item_type' => 'line_item')); if (true === $args['checkout_renewal']) { $cart_item = array(); foreach ($cart_items as $item) { if ($item['product_id'] == $order_item['product_id'] && (empty($order_item['variation_id']) || $item['variation_id'] == $order_item['variation_id'])) { $cart_item = $item; } } if (!empty($cart_item)) { woocommerce_update_order_item_meta($recurring_item_id, '_line_total', woocommerce_format_decimal($cart_item['line_total'])); woocommerce_update_order_item_meta($recurring_item_id, '_line_tax', woocommerce_format_decimal($cart_item['line_tax'])); woocommerce_update_order_item_meta($recurring_item_id, '_line_subtotal', woocommerce_format_decimal($cart_item['line_subtotal'])); woocommerce_update_order_item_meta($recurring_item_id, '_line_subtotal_tax', woocommerce_format_decimal($cart_item['line_subtotal_tax'])); if (is_object($cart_item['data'])) { woocommerce_update_order_item_meta($recurring_item_id, '_tax_class', $cart_item['data']->get_tax_class()); } } $cart_items = $woocommerce->cart->get_cart(); } $item_meta = new WC_Order_Item_Meta($order_item['item_meta']); // Remove recurring line items and set item totals based on recurring line totals foreach ($item_meta->meta as $meta_key => $meta) { // $meta is an array, so the item needs to be extracted from $meta[0] (just like order meta on a WC Order) $meta_value = $meta[0]; if (false === $args['checkout_renewal']) { // Already set earlier // Map line item totals based on recurring line totals switch ($meta_key) { case '_recurring_line_total': woocommerce_delete_order_item_meta($recurring_item_id, '_line_total'); woocommerce_update_order_item_meta($recurring_item_id, '_line_total', woocommerce_format_decimal($failed_payment_multiplier * $meta_value)); break; case '_recurring_line_tax': woocommerce_delete_order_item_meta($recurring_item_id, '_line_tax'); woocommerce_update_order_item_meta($recurring_item_id, '_line_tax', woocommerce_format_decimal($failed_payment_multiplier * $meta_value)); break; case '_recurring_line_subtotal': woocommerce_delete_order_item_meta($recurring_item_id, '_line_subtotal'); woocommerce_update_order_item_meta($recurring_item_id, '_line_subtotal', woocommerce_format_decimal($failed_payment_multiplier * $meta_value)); break; case '_recurring_line_subtotal_tax': woocommerce_delete_order_item_meta($recurring_item_id, '_line_subtotal_tax'); woocommerce_update_order_item_meta($recurring_item_id, '_line_subtotal_tax', woocommerce_format_decimal($failed_payment_multiplier * $meta_value)); break; default: break; } } // Copy over line item meta data, with some parent/child role based exceptions for recurring amounts $copy_to_renewal_item = true; switch ($meta_key) { case '_recurring_line_total': case '_recurring_line_tax': case '_recurring_line_subtotal': case '_recurring_line_subtotal_tax': case '_subscription_recurring_amount': case '_subscription_sign_up_fee': case '_subscription_period': case '_subscription_interval': case '_subscription_length': case '_subscription_trial_period': case '_subscription_end_date': case '_subscription_expiry_date': case '_subscription_start_date': case '_subscription_status': case '_subscription_completed_payments': if ('child' == $args['new_order_role']) { $copy_to_renewal_item = false; } break; case '_subscription_trial_length': // We never want to duplicate free trials on renewal orders $copy_to_renewal_item = false; break; case '_subscription_suspension_count': // We want to reset some values for the new order // We want to reset some values for the new order case '_subscription_trial_expiry_date': case '_subscription_failed_payments': $copy_to_renewal_item = false; $meta_value = 0; break; default: break; } // Copy existing item over to new recurring order item if ($copy_to_renewal_item) { woocommerce_add_order_item_meta($recurring_item_id, $meta_key, $meta_value); } } } if (false == $args['checkout_renewal']) { // Add fees foreach ($original_order->get_fees() as $item_id => $order_fee) { if (!isset($order_fee['recurring_line_total'])) { continue; } $item_id = woocommerce_add_order_item($renewal_order_id, array('order_item_name' => $order_fee['name'], 'order_item_type' => 'fee')); woocommerce_add_order_item_meta($item_id, '_tax_class', $order_fee['tax_class']); woocommerce_add_order_item_meta($item_id, '_line_total', WC_Subscriptions::format_total($order_fee['recurring_line_total'])); woocommerce_add_order_item_meta($item_id, '_line_tax', WC_Subscriptions::format_total($order_fee['recurring_line_tax'])); } } // Keep a record of the original order's ID on the renewal order update_post_meta($renewal_order_id, '_original_order', $original_order->id, true); $renewal_order = new WC_Order($renewal_order_id); if ('parent' == $args['new_order_role']) { WC_Subscriptions_Manager::process_subscriptions_on_checkout($renewal_order_id); $original_order->add_order_note(sprintf(__('Order superseded by Renewal Order %s.', 'woocommerce-subscriptions'), $renewal_order->get_order_number())); } do_action('woocommerce_subscriptions_renewal_order_created', $renewal_order, $original_order, $product_id, $args['new_order_role']); return apply_filters('woocommerce_subscriptions_renewal_order_id', $renewal_order_id, $original_order, $product_id, $args['new_order_role']); }
/** * Prompt the store manager to enter their PayPal API credentials if they are using * PayPal and have yet not entered their API credentials. * * @return void */ public static function maybe_show_admin_notice() { if (isset($_GET['wcs_disable_paypal_invalid_profile_id_notice'])) { update_option('wcs_paypal_invalid_profile_id', 'disabled'); } // Check if the API credentials are being saved - we can't do this on the 'woocommerce_update_options_payment_gateways_paypal' hook because it is triggered after 'admin_notices' if (isset($_POST['woocommerce_paypal_api_username']) || isset($_POST['woocommerce_paypal_api_password']) || isset($_POST['woocommerce_paypal_api_signature'])) { $current_options = self::get_wc_paypal_settings(); $credentials_updated = false; if (isset($_POST['woocommerce_paypal_api_username']) && $_POST['woocommerce_paypal_api_username'] != $current_options['api_username']) { $credentials_updated = true; } elseif (isset($_POST['woocommerce_paypal_api_password']) && $_POST['woocommerce_paypal_api_password'] != $current_options['api_password']) { $credentials_updated = true; } elseif (isset($_POST['woocommerce_paypal_api_signature']) && $_POST['woocommerce_paypal_api_signature'] != $current_options['api_signature']) { $credentials_updated = true; } if ($credentials_updated) { delete_option('wcs_paypal_credentials_error'); } } if (!in_array(get_woocommerce_currency(), apply_filters('woocommerce_paypal_supported_currencies', array('AUD', 'BRL', 'CAD', 'MXN', 'NZD', 'HKD', 'SGD', 'USD', 'EUR', 'JPY', 'TRY', 'NOK', 'CZK', 'DKK', 'HUF', 'ILS', 'MYR', 'PHP', 'PLN', 'SEK', 'CHF', 'TWD', 'THB', 'GBP', 'RMB')))) { $valid_for_use = false; } else { $valid_for_use = true; } if (WC_Subscriptions::is_woocommerce_pre_2_1()) { $payment_gateway_tab_url = admin_url('admin.php?page=woocommerce_settings&tab=payment_gateways§ion=WC_Gateway_Paypal'); } else { $payment_gateway_tab_url = admin_url('admin.php?page=wc-settings&tab=checkout§ion=wc_gateway_paypal'); } if (!self::are_credentials_set() && $valid_for_use && 'yes' == self::$paypal_settings['enabled'] && !has_action('admin_notices', 'WC_Subscriptions_Admin::admin_installed_notice') && current_user_can('manage_options')) { ?> <div id="message" class="updated error"> <p><?php printf(__('PayPal is inactive for subscription transactions. Please %sset up the PayPal IPN%s and %senter your API credentials%s to enable PayPal for Subscriptions.', 'woocommerce-subscriptions'), '<a href="http://docs.woothemes.com/document/subscriptions/store-manager-guide/#section-4" target="_blank">', '</a>', '<a href="' . $payment_gateway_tab_url . '">', '</a>'); ?> </p> </div> <?php } if (false !== get_option('wcs_paypal_credentials_error')) { ?> <div id="message" class="updated error"> <p><?php printf(__('There is a problem with PayPal. Your API credentials may be incorrect. Please update your %sAPI credentials%s. %sLearn more%s.', 'woocommerce-subscriptions'), '<a href="' . $payment_gateway_tab_url . '">', '</a>', '<a href="https://support.woothemes.com/hc/en-us/articles/202882473#paypal-credentials" target="_blank">', '</a>'); ?> </p> </div> <?php } if ('yes' == get_option('wcs_paypal_invalid_profile_id')) { ?> <div id="message" class="updated error"> <p><?php printf(__('There is a problem with PayPal. Your PayPal account is issuing out-of-date subscription IDs. %sLearn more%s. %sDismiss%s.', 'woocommerce-subscriptions'), '<a href="https://support.woothemes.com/hc/en-us/articles/202882473#old-paypal-account" target="_blank">', '</a>', '<a href="' . add_query_arg('wcs_disable_paypal_invalid_profile_id_notice', 'true') . '">', '</a>'); ?> </p> </div> <?php } }
/** * Display recurring order totals on the "Edit Order" page. * * @param int $post_id The post ID of the shop_order post object. * @since 1.2.4 * @return void */ public static function recurring_order_totals_meta_box_section($post_id) { global $woocommerce, $wpdb; $order = new WC_Order($post_id); $display_none = ' style="display: none"'; $contains_subscription = self::order_contains_subscription($order) ? true : false; $chosen_gateway = WC_Subscriptions_Payment_Gateways::get_payment_gateway(get_post_meta($post_id, '_recurring_payment_method', true)); $manual_renewal = self::requires_manual_renewal($post_id); $changes_supported = $chosen_gateway === false || $manual_renewal == 'true' || $chosen_gateway->supports('subscription_amount_changes') ? 'true' : 'false'; $data = get_post_meta($post_id); ?> <div class="clear"></div> </div> <div id="gateway_support"<?php if (!$contains_subscription) { echo $display_none; } ?> > <input type="hidden" name="gateway_supports_subscription_changes" value="<?php echo $changes_supported; ?> "> <div class="error"<?php if (!$contains_subscription || $changes_supported == 'true') { echo $display_none; } ?> > <p><?php printf(__('The %s payment gateway is used to charge automatic subscription payments for this order. This gateway <strong>does not</strong> support changing a subscription\'s details.', 'woocommerce-subscriptions'), get_post_meta($post_id, '_recurring_payment_method_title', true)); ?> </p> <p> <?php _e('It is strongly recommended you <strong>do not change</strong> any of the recurring totals or subscription item\'s details.', 'woocommerce-subscriptions'); ?> <a href="http://docs.woothemes.com/document/subscriptions/add-or-modify-a-subscription/#section-4"><?php _e('Learn More', 'woocommerce-subscriptions'); ?> »</a> </p> </div> </div> <div id="recurring_order_totals"<?php if (!$contains_subscription) { echo $display_none; } ?> > <h3><?php _e('Recurring Totals', 'woocommerce-subscriptions'); ?> </h3> <div class="totals_group"> <h4><span class="tax_total_display inline_total"></span><?php _e('Shipping for Renewal Orders', 'woocommerce-subscriptions'); ?> </h4> <div id="recurring_shipping_rows"> <?php if (!WC_Subscriptions::is_woocommerce_pre_2_1()) { if ($woocommerce->shipping()) { $shipping_methods = $woocommerce->shipping->load_shipping_methods(); } foreach (self::get_recurring_shipping_methods($order) as $item_id => $item) { $chosen_method = $item['method_id']; $shipping_title = $item['name']; $shipping_cost = $item['cost']; include plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/admin/post-types/writepanels/order-shipping-html.php'; } // Shipping created pre 2.1 if (isset($data['_recurring_shipping_method'])) { $item_id = 'old'; // so that when saving, we know to delete the data in the old form $chosen_method = !empty($data['_recurring_shipping_method'][0]) ? $data['_recurring_shipping_method'][0] : ''; $shipping_title = !empty($data['_recurring_shipping_method_title'][0]) ? $data['_recurring_shipping_method_title'][0] : ''; $shipping_cost = !empty($data['_order_recurring_shipping_total'][0]) ? $data['_order_recurring_shipping_total'][0] : '0.00'; include plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/admin/post-types/writepanels/order-shipping-html.php'; } ?> <?php } else { // WC < 2.1 ?> <ul class="totals"> <li class="wide"> <label><?php _e('Label:', 'woocommerce-subscriptions'); ?> </label> <input type="text" id="_recurring_shipping_method_title" name="_recurring_shipping_method_title" placeholder="<?php _e('The shipping title for renewal orders', 'woocommerce-subscriptions'); ?> " value="<?php echo $order->recurring_shipping_method_title; ?> " class="first" /> </li> <li class="left"> <label><?php _e('Cost:', 'woocommerce-subscriptions'); ?> </label> <input type="text" id="_order_recurring_shipping_total" name="_order_recurring_shipping_total" placeholder="0.00 <?php _e('(ex. tax)', 'woocommerce-subscriptions'); ?> " value="<?php echo self::get_recurring_shipping_total($order); ?> " class="first" /> </li> <li class="right"> <label><?php _e('Method:', 'woocommerce-subscriptions'); ?> </label> <select name="_recurring_shipping_method" id="_recurring_shipping_method" class="first"> <option value=""><?php _e('N/A', 'woocommerce-subscriptions'); ?> </option> <?php $chosen_shipping_method = $order->recurring_shipping_method; $found_method = false; if ($woocommerce->shipping()) { foreach ($woocommerce->shipping->load_shipping_methods() as $method) { if (strpos($chosen_shipping_method, $method->id) === 0) { $value = $chosen_shipping_method; } else { $value = $method->id; } echo '<option value="' . esc_attr($value) . '" ' . selected($chosen_shipping_method == $value, true, false) . '>' . esc_html($method->get_title()) . '</option>'; if ($chosen_shipping_method == $value) { $found_method = true; } } } if (!$found_method && !empty($chosen_shipping_method)) { echo '<option value="' . esc_attr($chosen_shipping_method) . '" selected="selected">' . __('Other', 'woocommerce-subscriptions') . '</option>'; } else { echo '<option value="other">' . __('Other', 'woocommerce-subscriptions') . '</option>'; } ?> </select> </li> </ul> <?php } // ! WC_Subscriptions::is_woocommerce_pre_2_1() ?> </div> <div class="clear"></div> </div> <?php if ('yes' == get_option('woocommerce_calc_taxes')) { ?> <div class="totals_group tax_rows_group"> <h4> <span class="tax_total_display inline_total"></span> <?php _e('Recurring Taxes', 'woocommerce-subscriptions'); ?> <a class="tips" data-tip="<?php _e('These rows contain taxes included in each recurring amount for this subscription. This allows you to display multiple or compound taxes rather than a single total on future subscription renewal orders.', 'woocommerce-subscriptions'); ?> " href="#">[?]</a> </h4> <div id="recurring_tax_rows" class="total_rows"> <?php $loop = 0; $taxes = self::get_recurring_taxes($order); if (is_array($taxes) && sizeof($taxes) > 0) { $rates = $wpdb->get_results("SELECT tax_rate_id, tax_rate_country, tax_rate_state, tax_rate_name, tax_rate_priority FROM {$wpdb->prefix}woocommerce_tax_rates ORDER BY tax_rate_name"); $tax_codes = array(); foreach ($rates as $rate) { $code = array(); $code[] = $rate->tax_rate_country; $code[] = $rate->tax_rate_state; $code[] = $rate->tax_rate_name ? sanitize_title($rate->tax_rate_name) : 'TAX'; $code[] = absint($rate->tax_rate_priority); $tax_codes[$rate->tax_rate_id] = strtoupper(implode('-', array_filter($code))); } foreach ($taxes as $item_id => $item) { include plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/admin/post-types/writepanels/order-tax-html.php'; $loop++; } } ?> </div> <h4 style="padding-bottom: 10px;"><a href="#" class="add_recurring_tax_row"><?php _e('+ Add tax row', 'woocommerce-subscriptions'); ?> </a></h4> <div class="clear"></div> </div> <?php if (WC_Subscriptions::is_woocommerce_pre_2_1()) { ?> <div class="totals_group"> <h4><span class="tax_total_display inline_total"></span><?php _e('Tax Totals', 'woocommerce-subscriptions'); ?> </h4> <ul class="totals"> <li class="left"> <label><?php _e('Recurring Sales Tax:', 'woocommerce-subscriptions'); ?> </label> <input type="number" step="any" min="0" id="_order_recurring_tax_total" name="_order_recurring_tax_total" placeholder="0.00" value="<?php echo self::get_recurring_total_tax($order); ?> " class="calculated" /> </li> <li class="right"> <label><?php _e('Shipping Tax:', 'woocommerce-subscriptions'); ?> </label> <input type="number" step="any" min="0" id="_order_recurring_shipping_tax_total" name="_order_recurring_shipping_tax_total" placeholder="0.00" value="<?php echo self::get_recurring_shipping_tax_total($order); ?> " class="calculated" /> </li> </ul> <div class="clear"></div> </div> <?php } // WC_Subscriptions::is_woocommerce_pre_2_1() ?> <?php } ?> <div class="totals_group"> <h4><label for="_order_recurring_discount_total"><?php _e('Recurring Order Discount', 'woocommerce-subscriptions'); ?> <a class="tips" data-tip="<?php _e('The discounts applied to each recurring payment charged in the future.', 'woocommerce-subscriptions'); ?> " href="#">[?]</a></label></h4> <input type="text" class="wc_input_price" id="_order_recurring_discount_total" name="_order_recurring_discount_total" placeholder="0.00" value="<?php echo self::get_recurring_discount_total($order); ?> " style="margin: 6px 0 10px;"/> </div> <div class="totals_group"> <h4><label for="_order_recurring_total"><?php _e('Recurring Order Total', 'woocommerce-subscriptions'); ?> <a class="tips" data-tip="<?php _e('The total amounts charged for each future recurring payment.', 'woocommerce-subscriptions'); ?> " href="#">[?]</a></label></h4> <input type="text" id="_order_recurring_total" name="_order_recurring_total" placeholder="0.00" value="<?php echo self::get_recurring_total($order); ?> " class="calculated" style="margin: 6px 0 10px;"/> </div> <div class="totals_group"> <h4><?php _e('Recurring Payment Method:', 'woocommerce-subscriptions'); ?> </h4> <div style="padding-top: 4px; font-style: italic; margin: 2px 0 10px;"><?php echo $manual_renewal || empty($order->recurring_payment_method_title) ? __('Manual', 'woocommerce-subscriptions') : $order->recurring_payment_method_title; ?> </div> </div> <?php }
/** * When a new order is inserted, add subscriptions related order meta. * * @since 1.0 */ public static function add_order_meta($order_id, $posted) { global $woocommerce; if (!WC_Subscriptions_Cart::cart_contains_subscription_renewal('child') && WC_Subscriptions_Order::order_contains_subscription($order_id)) { // This works because the 'woocommerce_add_order_item_meta' runs before the 'woocommerce_checkout_update_order_meta' hook // Set the recurring totals so totals display correctly on order page update_post_meta($order_id, '_order_recurring_discount_cart', WC_Subscriptions_Cart::get_recurring_discount_cart()); update_post_meta($order_id, '_order_recurring_discount_total', WC_Subscriptions_Cart::get_recurring_discount_total()); update_post_meta($order_id, '_order_recurring_shipping_tax_total', WC_Subscriptions_Cart::get_recurring_shipping_tax_total()); update_post_meta($order_id, '_order_recurring_shipping_total', WC_Subscriptions_Cart::get_recurring_shipping_total()); update_post_meta($order_id, '_order_recurring_tax_total', WC_Subscriptions_Cart::get_recurring_total_tax()); update_post_meta($order_id, '_order_recurring_total', WC_Subscriptions_Cart::get_recurring_total()); // Set the recurring payment method - it starts out the same as the original by may change later update_post_meta($order_id, '_recurring_payment_method', get_post_meta($order_id, '_payment_method', true)); update_post_meta($order_id, '_recurring_payment_method_title', get_post_meta($order_id, '_payment_method_title', true)); $order = new WC_Order($order_id); $order_fees = $order->get_fees(); // the fee order items have already been set, we just need to to add the recurring total meta $cart_fees = $woocommerce->cart->get_fees(); foreach ($order->get_fees() as $item_id => $order_fee) { // Find the matching fee in the cart foreach ($cart_fees as $fee_index => $cart_fee) { if (sanitize_title($order_fee['name']) == $cart_fee->id) { woocommerce_add_order_item_meta($item_id, '_recurring_line_total', wc_format_decimal($cart_fee->recurring_amount)); woocommerce_add_order_item_meta($item_id, '_recurring_line_tax', wc_format_decimal($cart_fee->recurring_tax)); unset($cart_fees[$fee_index]); break; } } } // Get recurring taxes into same format as _order_taxes $order_recurring_taxes = array(); foreach (WC_Subscriptions_Cart::get_recurring_taxes() as $tax_key => $tax_amount) { $item_id = woocommerce_add_order_item($order_id, array('order_item_name' => WC_Tax::get_rate_code($tax_key), 'order_item_type' => 'recurring_tax')); if ($item_id) { wc_add_order_item_meta($item_id, 'rate_id', $tax_key); wc_add_order_item_meta($item_id, 'label', WC_Tax::get_rate_label($tax_key)); wc_add_order_item_meta($item_id, 'compound', absint(WC_Tax::is_compound($tax_key) ? 1 : 0)); wc_add_order_item_meta($item_id, 'tax_amount', wc_format_decimal(isset(WC()->cart->recurring_taxes[$tax_key]) ? WC()->cart->recurring_taxes[$tax_key] : 0)); wc_add_order_item_meta($item_id, 'shipping_tax_amount', wc_format_decimal(isset(WC()->cart->recurring_shipping_taxes[$tax_key]) ? WC()->cart->recurring_shipping_taxes[$tax_key] : 0)); } } $payment_gateways = $woocommerce->payment_gateways->payment_gateways(); if ('yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) { update_post_meta($order_id, '_wcs_requires_manual_renewal', 'true'); } elseif (isset($payment_gateways[$posted['payment_method']]) && !$payment_gateways[$posted['payment_method']]->supports('subscriptions')) { update_post_meta($order_id, '_wcs_requires_manual_renewal', 'true'); } $cart_item = WC_Subscriptions_Cart::cart_contains_subscription_renewal(); if (isset($cart_item['subscription_renewal']) && 'parent' == $cart_item['subscription_renewal']['role']) { update_post_meta($order_id, '_original_order', $cart_item['subscription_renewal']['original_order']); } // WC 2.1+ if (!WC_Subscriptions::is_woocommerce_pre_2_1()) { // Recurring coupons if ($applied_coupons = $woocommerce->cart->get_coupons()) { foreach ($applied_coupons as $code => $coupon) { if (!isset($woocommerce->cart->recurring_coupon_discount_amounts[$code])) { continue; } $item_id = woocommerce_add_order_item($order_id, array('order_item_name' => $code, 'order_item_type' => 'recurring_coupon')); // Add line item meta if ($item_id) { woocommerce_add_order_item_meta($item_id, 'discount_amount', isset($woocommerce->cart->recurring_coupon_discount_amounts[$code]) ? $woocommerce->cart->recurring_coupon_discount_amounts[$code] : 0); } } } // Add recurring shipping order items if (WC_Subscriptions_Cart::cart_contains_subscriptions_needing_shipping()) { $packages = $woocommerce->shipping->get_packages(); $checkout = $woocommerce->checkout(); foreach ($packages as $i => $package) { if (isset($package['rates'][$checkout->shipping_methods[$i]])) { $method = $package['rates'][$checkout->shipping_methods[$i]]; $item_id = woocommerce_add_order_item($order_id, array('order_item_name' => $method->label, 'order_item_type' => 'recurring_shipping')); if ($item_id) { woocommerce_add_order_item_meta($item_id, 'method_id', $method->id); woocommerce_add_order_item_meta($item_id, 'cost', WC_Subscriptions::format_total($method->cost)); woocommerce_add_order_item_meta($item_id, 'taxes', array_map('wc_format_decimal', $method->taxes)); do_action('woocommerce_subscriptions_add_recurring_shipping_order_item', $order_id, $item_id, $i); } } } } // Remove shipping on original order if it was added but is not required if (!WC_Subscriptions_Cart::charge_shipping_up_front()) { foreach ($order->get_shipping_methods() as $order_item_id => $shipping_method) { woocommerce_update_order_item_meta($order_item_id, 'cost', WC_Subscriptions::format_total(0)); } } } else { update_post_meta($order_id, '_recurring_shipping_method', get_post_meta($order_id, '_shipping_method', true), true); update_post_meta($order_id, '_recurring_shipping_method_title', get_post_meta($order_id, '_shipping_method_title', true), true); } } }