/**
  * Apply sign up fee or recurring fee discount before tax is calculated
  *
  *
  * @since 1.2
  */
 public static function apply_subscription_discount_before_tax($original_price, $product, $cart)
 {
     global $woocommerce;
     if (!WC_Subscriptions_Product::is_subscription($product['product_id'])) {
         return $original_price;
     }
     $price = $original_price;
     if (!empty($cart->applied_coupons)) {
         foreach ($cart->applied_coupons as $code) {
             $coupon = new WC_Coupon($code);
             if ($coupon->apply_before_tax() && $coupon->is_valid()) {
                 // Sign up fee discount
                 if ('sign_up_fee' == WC_Subscriptions_Cart::get_recalculation_type() && 'sign_up_fee' == $coupon->type || 'base_recurring_fee' == WC_Subscriptions_Cart::get_recalculation_type() && 'recurring_fee' == $coupon->type || 0 == WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee() && 'recurring_fee' == $coupon->type) {
                     if ($original_price < $coupon->amount) {
                         $discount_amount = $original_price;
                     } else {
                         $discount_amount = $coupon->amount;
                     }
                     $price = $original_price - $coupon->amount;
                     if ($price < 0) {
                         $price = 0;
                     }
                     // add to discount totals
                     $woocommerce->cart->discount_cart = $woocommerce->cart->discount_cart + $discount_amount * $product['quantity'];
                 }
             }
         }
     }
     return $price;
 }
 /**
  * Tells if a product is a subscription, provided that Subs is installed.
  *
  * @param  mixed    $product_id   product or id to check
  * @return boolean                true if Subs exists and product is a Sub
  */
 public function is_subscription($product_id)
 {
     if (!class_exists('WC_Subscriptions')) {
         return false;
     }
     return WC_Subscriptions_Product::is_subscription($product_id);
 }
 /**
  * Determine the maximum monthly payment required for subscriptions currently in cart.
  * This is an approximation based on 31 day months.
  *
  * @return float
  */
 protected function calculate_potential_monthly_maximum_payment_in_cart()
 {
     $potential_monthly_max = 0;
     foreach (WC()->cart->cart_contents as $cart_item) {
         $product_subscription = $cart_item['data'];
         $item_quantity = absint($cart_item['quantity']);
         if (WC_Subscriptions_Product::is_subscription($product_subscription)) {
             $subscription_price = (double) $product_subscription->subscription_price;
             $subscription_interval = (double) $product_subscription->subscription_period_interval;
             $subscription_monthly_max = $item_quantity * $subscription_price;
             if ('day' === $product_subscription->subscription_period) {
                 $subscription_monthly_max = $subscription_price * (31 / $subscription_interval);
             } else {
                 if ('week' === $product_subscription->subscription_period) {
                     $subscription_monthly_max = $subscription_price * ceil(4 / $subscription_interval);
                 }
             }
             $potential_monthly_max += $subscription_monthly_max;
         }
     }
     return $potential_monthly_max;
 }
 /**
  * Add each subscription product's details to an order so that the state of the subscription persists even when a product is changed
  *
  * @since 1.2
  */
 public static function add_order_item_meta($order_item)
 {
     global $woocommerce;
     if (WC_Subscriptions_Product::is_subscription($order_item['id'])) {
         // Make sure existing meta persists
         $item_meta = new WC_Order_Item_Meta($order_item['item_meta']);
         // Add subscription details so order state persists even when a product is changed
         $item_meta->add('_subscription_period', WC_Subscriptions_Product::get_period($order_item['id']));
         $item_meta->add('_subscription_interval', WC_Subscriptions_Product::get_interval($order_item['id']));
         $item_meta->add('_subscription_length', WC_Subscriptions_Product::get_length($order_item['id']));
         $item_meta->add('_subscription_trial_length', WC_Subscriptions_Product::get_trial_length($order_item['id']));
         $item_meta->add('_subscription_trial_period', WC_Subscriptions_Product::get_trial_period($order_item['id']));
         $item_meta->add('_subscription_recurring_amount', $woocommerce->cart->base_recurring_prices[$order_item['id']]);
         // WC_Subscriptions_Product::get_price() would return a price without filters applied
         $item_meta->add('_subscription_sign_up_fee', WC_Subscriptions_Product::get_sign_up_fee($order_item['id']));
         // Calculated recurring amounts for the item
         $item_meta->add('_recurring_line_total', $woocommerce->cart->recurring_cart_contents[$order_item['id']]['recurring_line_total']);
         $item_meta->add('_recurring_line_tax', $woocommerce->cart->recurring_cart_contents[$order_item['id']]['recurring_line_tax']);
         $item_meta->add('_recurring_line_subtotal', $woocommerce->cart->recurring_cart_contents[$order_item['id']]['recurring_line_subtotal']);
         $item_meta->add('_recurring_line_subtotal_tax', $woocommerce->cart->recurring_cart_contents[$order_item['id']]['recurring_line_subtotal_tax']);
         $order_item['item_meta'] = $item_meta->meta;
     }
     return $order_item;
 }
 /**
  * Save subscription details when edit product page is submitted for a subscription product type
  * or the bulk edit product is saved.
  * 
  * The $_REQUEST global is used to account for both $_GET submission from Bulk Edit page and 
  * $_POST submission from Edit Product page.
  * 
  * @param array Array of Product types & their labels, excluding the Subscription product type.
  * @return array Array of Product types & their labels, including the Subscription product type.
  * @since 1.0
  */
 public static function save_subscription_meta($post_id)
 {
     if (!WC_Subscriptions_Product::is_subscription($post_id)) {
         return;
     }
     if (isset($_REQUEST['_subscription_price'])) {
         update_post_meta($post_id, '_subscription_price', stripslashes($_REQUEST['_subscription_price']));
         update_post_meta($post_id, '_price', stripslashes($_REQUEST['_subscription_price']));
     } else {
         // Handle bulk edit, where _subscription_price field is not available
         if (isset($_REQUEST['_regular_price']) && !empty($_REQUEST['_regular_price'])) {
             update_post_meta($post_id, '_subscription_price', stripslashes($_REQUEST['_regular_price']));
             update_post_meta($post_id, '_price', stripslashes($_REQUEST['_regular_price']));
         } elseif (isset($_REQUEST['_sale_price']) && !empty($_REQUEST['_sale_price'])) {
             update_post_meta($post_id, '_subscription_price', stripslashes($_REQUEST['_sale_price']));
             update_post_meta($post_id, '_price', stripslashes($_REQUEST['_sale_price']));
         }
     }
     $subscription_fields = array('_subscription_sign_up_fee', '_subscription_period', '_subscription_period_interval', '_subscription_length', '_subscription_trial_length');
     foreach ($subscription_fields as $field_name) {
         if (isset($_REQUEST[$field_name])) {
             update_post_meta($post_id, $field_name, stripslashes($_REQUEST[$field_name]));
         }
     }
 }
 /**
  * Subscriptions are individual items so override the WC_Product is_sold_individually function
  * to reflect this.
  *
  * @since 1.0
  */
 public static function is_sold_individually($is_individual, $product)
 {
     // Sold individually if downloadable, virtual, and the option is enabled
     if (WC_Subscriptions_Product::is_subscription($product)) {
         $is_individual = true;
     }
     return $is_individual;
 }
 /**
  * Gets the subscription sign up fee for the cart and returns it
  *
  * Currently short-circuits to return just the sign-up fee of the first subscription, because only
  * one subscription can be purchased at a time. 
  *
  * @since 1.0
  */
 public static function get_cart_subscription_sign_up_fee()
 {
     global $woocommerce;
     $sign_up_fee = 0;
     if (!self::cart_contains_subscription_renewal()) {
         foreach ($woocommerce->cart->cart_contents as $cart_item) {
             $item_id = empty($cart_item['variation_id']) ? $cart_item['product_id'] : $cart_item['variation_id'];
             if (isset($cart_item['data']->subscription_sign_up_fee)) {
                 $sign_up_fee = $cart_item['data']->subscription_sign_up_fee;
                 break;
             } elseif (WC_Subscriptions_Product::is_subscription($item_id)) {
                 $sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee($item_id);
                 break;
             }
         }
     }
     return apply_filters('woocommerce_subscriptions_cart_sign_up_fee', $sign_up_fee);
 }
Exemplo n.º 8
0
 /**
  * Save a variable subscription's details when the edit product page is submitted for a variable
  * subscription product type (or the bulk edit product is saved).
  *
  * @param $post_id int ID of the parent WC_Product_Variable_Subscription
  * @return null
  * @since 1.3
  */
 public static function process_product_meta_variable_subscription($post_id)
 {
     if (!WC_Subscriptions_Product::is_subscription($post_id)) {
         return;
     }
     // Make sure WooCommerce calculates correct prices
     $_POST['variable_regular_price'] = $_POST['variable_subscription_price'];
     // Run WooCommerce core saving routine
     process_product_meta_variable($post_id);
     if (!isset($_REQUEST['_subscription_limit'])) {
         $_REQUEST['_subscription_limit'] = 'no';
     }
     update_post_meta($post_id, '_subscription_limit', stripslashes($_REQUEST['_subscription_limit']));
     if (!isset($_REQUEST['variable_post_id'])) {
         return;
     }
     $variable_post_ids = $_POST['variable_post_id'];
     $max_loop = max(array_keys($variable_post_ids));
     // Save each variations details
     for ($i = 0; $i <= $max_loop; $i++) {
         if (!isset($variable_post_ids[$i])) {
             continue;
         }
         $variation_id = absint($variable_post_ids[$i]);
         if (isset($_POST['variable_subscription_price']) && is_array($_POST['variable_subscription_price'])) {
             $subscription_price = self::clean_number(woocommerce_clean($_POST['variable_subscription_price'][$i]));
             update_post_meta($variation_id, '_subscription_price', $subscription_price);
             update_post_meta($variation_id, '_regular_price', $subscription_price);
         }
         // Make sure trial period is within allowable range
         $subscription_ranges = WC_Subscriptions_Manager::get_subscription_ranges();
         $max_trial_length = count($subscription_ranges[$_POST['variable_subscription_trial_period'][$i]]) - 1;
         $_POST['variable_subscription_trial_length'][$i] = absint($_POST['variable_subscription_trial_length'][$i]);
         if ($_POST['variable_subscription_trial_length'][$i] > $max_trial_length) {
             $_POST['variable_subscription_trial_length'][$i] = $max_trial_length;
         }
         $subscription_fields = array('_subscription_sign_up_fee', '_subscription_period', '_subscription_period_interval', '_subscription_length', '_subscription_trial_period', '_subscription_trial_length');
         foreach ($subscription_fields as $field_name) {
             if (isset($_POST['variable' . $field_name][$i])) {
                 update_post_meta($variation_id, $field_name, woocommerce_clean($_POST['variable' . $field_name][$i]));
             }
         }
     }
     // Now that all the varation's meta is saved, sync the min variation price
     $variable_subscription = get_product($post_id);
     $variable_subscription->variable_product_sync();
 }
 /**
  * If a product is being marked as not purchasable because it is limited and the customer has a subscription,
  * but the current request is to switch the subscription, then mark it as purchasable.
  *
  * @since 1.4.4
  * @return bool
  */
 public static function is_purchasable($is_purchasable, $product)
 {
     global $woocommerce;
     if (false === $is_purchasable && WC_Subscriptions_Product::is_subscription($product->id) && 'yes' === $product->limit_subscriptions && WC_Subscriptions_Manager::user_has_subscription(0, $product->id, 'active')) {
         // Adding to cart from the product page
         if (isset($_GET['switch-subscription'])) {
             $is_purchasable = true;
             // Validating when restring cart from session
         } elseif (self::cart_contains_subscription_switch()) {
             $is_purchasable = true;
             // Restoring cart from session, so need to check the cart in the session (self::cart_contains_subscription_switch() only checks the cart)
         } elseif (isset($woocommerce->session->cart)) {
             foreach ($woocommerce->session->cart as $cart_item_key => $cart_item) {
                 if (isset($cart_item['subscription_switch'])) {
                     $is_purchasable = true;
                     break;
                 }
             }
         }
     }
     return $is_purchasable;
 }
 /**
  * Uses the details of an order to create a pending subscription on the customers account
  * for a subscription product, as specified with $product_id.
  *
  * @param int|WC_Order $order The order ID or WC_Order object to create the subscription from.
  * @param int $product_id The ID of the subscription product on the order, if a variation, it must be the variation's ID.
  * @param array $args An array of name => value pairs to customise the details of the subscription, including:
  * 			'start_date' A MySQL formatted date/time string on which the subscription should start, in UTC timezone
  * 			'expiry_date' A MySQL formatted date/time string on which the subscription should expire, in UTC timezone
  * @since 1.1
  */
 public static function create_pending_subscription_for_order($order, $product_id, $args = array())
 {
     _deprecated_function(__METHOD__, '2.0', 'wcs_create_subscription()');
     if (!is_object($order)) {
         $order = new WC_Order($order);
     }
     if (!WC_Subscriptions_Product::is_subscription($product_id)) {
         return;
     }
     $args = wp_parse_args($args, array('start_date' => get_gmt_from_date($order->order_date), 'expiry_date' => ''));
     $billing_period = WC_Subscriptions_Product::get_period($product_id);
     $billing_interval = WC_Subscriptions_Product::get_interval($product_id);
     // Support passing timestamps
     $args['start_date'] = is_numeric($args['start_date']) ? date('Y-m-d H:i:s', $args['start_date']) : $args['start_date'];
     $product = wc_get_product($product_id);
     // Check if there is already a subscription for this product and order
     $subscriptions = wcs_get_subscriptions(array('order_id' => $order->id, 'product_id' => $product_id));
     if (!empty($subscriptions)) {
         $subscription = array_pop($subscriptions);
         // Make sure the subscription is pending and start date is set correctly
         wp_update_post(array('ID' => $subscription->id, 'post_status' => 'wc-' . apply_filters('woocommerce_default_subscription_status', 'pending'), 'post_date' => get_date_from_gmt($args['start_date'])));
     } else {
         $subscription = wcs_create_subscription(array('start_date' => get_date_from_gmt($args['start_date']), 'order_id' => $order->id, 'customer_id' => $order->get_user_id(), 'billing_period' => $billing_period, 'billing_interval' => $billing_interval, 'customer_note' => $order->customer_note));
         if (is_wp_error($subscription)) {
             throw new Exception(__('Error: Unable to create subscription. Please try again.', 'woocommerce-subscriptions'));
         }
         $item_id = $subscription->add_product($product, 1, array('variation' => method_exists($product, 'get_variation_attributes') ? $product->get_variation_attributes() : array(), 'totals' => array('subtotal' => $product->get_price(), 'subtotal_tax' => 0, 'total' => $product->get_price(), 'tax' => 0, 'tax_data' => array('subtotal' => array(), 'total' => array()))));
         if (!$item_id) {
             throw new Exception(__('Error: Unable to add product to created subscription. Please try again.', 'woocommerce-subscriptions'));
         }
     }
     // Make sure some of the meta is copied form the order rather than the store's defaults
     update_post_meta($subscription->id, '_order_currency', $order->order_currency);
     update_post_meta($subscription->id, '_prices_include_tax', $order->prices_include_tax);
     // Adding a new subscription so set the expiry date/time from the order date
     if (!empty($args['expiry_date'])) {
         if (is_numeric($args['expiry_date'])) {
             $args['expiry_date'] = date('Y-m-d H:i:s', $args['expiry_date']);
         }
         $expiration = $args['expiry_date'];
     } else {
         $expiration = WC_Subscriptions_Product::get_expiration_date($product_id, $args['start_date']);
     }
     // Adding a new subscription so set the expiry date/time from the order date
     $trial_expiration = WC_Subscriptions_Product::get_trial_expiration_date($product_id, $args['start_date']);
     $dates_to_update = array();
     if ($trial_expiration > 0) {
         $dates_to_update['trial_end'] = $trial_expiration;
     }
     if ($expiration > 0) {
         $dates_to_update['end'] = $expiration;
     }
     if (!empty($dates_to_update)) {
         $subscription->update_dates($dates_to_update);
     }
     // Set the recurring totals on the subscription
     $subscription->set_total(0, 'tax');
     $subscription->set_total($product->get_price(), 'total');
     $subscription->add_order_note(__('Pending subscription created.', 'woocommerce-subscriptions'));
     do_action('pending_subscription_created_for_order', $order, $product_id);
 }
 /**
  * Let other functions know shipping should not be charged on the initial order when
  * the cart contains a synchronised subscription and no other items which need shipping.
  *
  * @since 1.5.8
  * @deprecated 2.0
  */
 public static function charge_shipping_up_front($charge_shipping_up_front)
 {
     _deprecated_function(__METHOD__, '2.0');
     // the cart contains only the synchronised subscription
     if (true === $charge_shipping_up_front && self::cart_contains_synced_subscription()) {
         // the cart contains only a subscription, see if the payment date is today and if not, then it doesn't need shipping
         if (1 == count(WC()->cart->cart_contents)) {
             foreach (WC()->cart->get_cart() as $cart_item_key => $cart_item) {
                 if (self::is_product_synced($cart_item['data']) && !self::is_product_prorated($cart_item['data']) && !self::is_today(self::calculate_first_payment_date($cart_item['data'], 'timestamp'))) {
                     $charge_shipping_up_front = false;
                     break;
                 }
             }
             // cart contains other items, see if any require shipping
         } else {
             $other_items_need_shipping = false;
             foreach (WC()->cart->cart_contents as $cart_item_key => $cart_item) {
                 if ((!WC_Subscriptions_Product::is_subscription($cart_item['data']) || self::is_product_prorated($cart_item['data'])) && $cart_item['data']->needs_shipping()) {
                     $other_items_need_shipping = true;
                 }
             }
             if (false === $other_items_need_shipping) {
                 $charge_shipping_up_front = false;
             }
         }
     }
     return $charge_shipping_up_front;
 }
 /**
  * Add each subscription product's details to an order so that the state of the subscription persists even when a product is changed
  *
  * @since 1.2.5
  */
 public static function add_order_item_meta($item_id, $values)
 {
     global $woocommerce;
     if (!WC_Subscriptions_Cart::cart_contains_subscription_renewal('child') && WC_Subscriptions_Product::is_subscription($values['product_id'])) {
         $cart_item = $values['data'];
         $product_id = empty($values['variation_id']) ? $values['product_id'] : $values['variation_id'];
         // Add subscription details so order state persists even when a product is changed
         $period = isset($cart_item->subscription_period) ? $cart_item->subscription_period : WC_Subscriptions_Product::get_period($product_id);
         $interval = isset($cart_item->subscription_period_interval) ? $cart_item->subscription_period_interval : WC_Subscriptions_Product::get_interval($product_id);
         $length = isset($cart_item->subscription_length) ? $cart_item->subscription_length : WC_Subscriptions_Product::get_length($product_id);
         $trial_length = isset($cart_item->subscription_trial_length) ? $cart_item->subscription_trial_length : WC_Subscriptions_Product::get_trial_length($product_id);
         $trial_period = isset($cart_item->subscription_trial_period) ? $cart_item->subscription_trial_period : WC_Subscriptions_Product::get_trial_period($product_id);
         $sign_up_fee = isset($cart_item->subscription_sign_up_fee) ? $cart_item->subscription_sign_up_fee : WC_Subscriptions_Product::get_sign_up_fee($product_id);
         woocommerce_add_order_item_meta($item_id, '_subscription_period', $period);
         woocommerce_add_order_item_meta($item_id, '_subscription_interval', $interval);
         woocommerce_add_order_item_meta($item_id, '_subscription_length', $length);
         woocommerce_add_order_item_meta($item_id, '_subscription_trial_length', $trial_length);
         woocommerce_add_order_item_meta($item_id, '_subscription_trial_period', $trial_period);
         woocommerce_add_order_item_meta($item_id, '_subscription_recurring_amount', $woocommerce->cart->base_recurring_prices[$product_id]);
         // WC_Subscriptions_Product::get_price() would return a price without filters applied
         woocommerce_add_order_item_meta($item_id, '_subscription_sign_up_fee', $sign_up_fee);
         // Calculated recurring amounts for the item
         woocommerce_add_order_item_meta($item_id, '_recurring_line_total', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_total']);
         woocommerce_add_order_item_meta($item_id, '_recurring_line_tax', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_tax']);
         woocommerce_add_order_item_meta($item_id, '_recurring_line_subtotal', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal']);
         woocommerce_add_order_item_meta($item_id, '_recurring_line_subtotal_tax', $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_subtotal_tax']);
         // Add recurring line tax data (for WC 2.2+)
         $raw_tax_data = $woocommerce->cart->recurring_cart_contents[$values['product_id']]['recurring_line_tax_data'];
         $recurring_tax_data = array();
         $recurring_tax_data['total'] = array_map('wc_format_decimal', $raw_tax_data['total']);
         $recurring_tax_data['subtotal'] = array_map('wc_format_decimal', $raw_tax_data['subtotal']);
         woocommerce_add_order_item_meta($item_id, '_recurring_line_tax_data', $recurring_tax_data);
     }
 }
 /**
  * Renders group selections for variations.
  * 
  * @param int $loop
  * @param array $variation_data
  * @param WP_Post $variation
  */
 public static function woocommerce_product_after_variable_attributes($loop, $variation_data, $variation)
 {
     global $post, $wpdb;
     $output = '';
     $output .= '<tr><td><div>';
     $variation_groups = get_post_meta($variation->ID, '_groups_variation_groups', false);
     $variation_groups_remove = get_post_meta($variation->ID, '_groups_variation_groups_remove', false);
     $groups_table = _groups_get_tablename('group');
     if ($groups = $wpdb->get_results("SELECT * FROM {$groups_table} ORDER BY name")) {
         // text style
         $output .= '<style type="text/css">';
         $output .= '.groups-woocommerce .selectize-input { font-size: inherit; }';
         $output .= '</style>';
         // add to groups
         $output .= '<label>';
         $output .= __('Add to Groups', GROUPS_WS_PLUGIN_DOMAIN);
         $output .= ' ';
         $output .= sprintf('<select id="variation-groups-%d" class="groups-woocommerce" name="_groups_variation_groups[%d][]" multiple="multiple" placeholder="%s" data-placeholder="%s">', esc_attr($variation->ID), esc_attr($variation->ID), esc_attr(__('Choose groups &hellip;', GROUPS_WS_PLUGIN_DOMAIN)), esc_attr(__('Choose groups &hellip;', GROUPS_WS_PLUGIN_DOMAIN)));
         foreach ($groups as $group) {
             $selected = is_array($variation_groups) && in_array($group->group_id, $variation_groups);
             $output .= sprintf('<option value="%d" %s>%s</option>', Groups_Utility::id($group->group_id), $selected ? ' selected="selected" ' : '', wp_filter_nohtml_kses($group->name));
         }
         $output .= '</select>';
         $output .= '</label>';
         $output .= Groups_UIE::render_select('#variation-groups-' . esc_attr($variation->ID));
         $output .= '<p class="description">' . __('Add the customer to these groups when purchasing this variation.', GROUPS_WS_PLUGIN_DOMAIN) . '</p>';
         // remove from groups
         $output .= '<label>';
         $output .= __('Remove from Groups', GROUPS_WS_PLUGIN_DOMAIN);
         $output .= ' ';
         $output .= sprintf('<select id="variation-groups-remove-%d" class="groups-woocommerce" name="_groups_variation_groups_remove[%d][]" multiple="multiple" placeholder="%s" data-placeholder="%s">', esc_attr($variation->ID), esc_attr($variation->ID), esc_attr(__('Choose groups &hellip;', GROUPS_WS_PLUGIN_DOMAIN)), esc_attr(__('Choose groups &hellip;', GROUPS_WS_PLUGIN_DOMAIN)));
         foreach ($groups as $group) {
             $selected = is_array($variation_groups_remove) && in_array($group->group_id, $variation_groups_remove);
             $output .= sprintf('<option value="%d" %s>%s</option>', Groups_Utility::id($group->group_id), $selected ? ' selected="selected" ' : '', wp_filter_nohtml_kses($group->name));
         }
         $output .= '</select>';
         $output .= '</label>';
         $output .= Groups_UIE::render_select('#variation-groups-remove-' . esc_attr($variation->ID));
         $output .= '<p class="description">' . __('Remove the customer from these groups when purchasing this variation.', GROUPS_WS_PLUGIN_DOMAIN) . '</p>';
         $is_subscription = isset($post->ID) && class_exists('WC_Subscriptions_Product') && WC_Subscriptions_Product::is_subscription($post->ID);
         $output .= sprintf('<div class="groups-panel-item-simple" style="%s">', $is_subscription ? 'display:none;' : '');
         $output .= '<p>' . __('If set, the duration limitations in the <em>Groups</em> settings of the variable product apply.', GROUPS_WS_PLUGIN_DOMAIN) . '</p>';
         $output .= '</div>';
     }
     $output .= '</div></td></tr>';
     echo $output;
 }
Exemplo n.º 14
0
 /**
  * Gets the subscription trial period from the cart and returns it as an array (eg. array( 'month', 'day' ) )
  *
  * Deprecated because a cart can now contain multiple subscription products, so there is no single trial period for the entire cart.
  *
  * @since 1.2
  * @deprecated 2.0
  */
 public static function get_cart_subscription_trial_period()
 {
     _deprecated_function(__METHOD__, '2.0', 'values from WC()->cart->recurring_carts');
     $trial_period = '';
     // Get the original trial period
     if (self::cart_contains_subscription()) {
         foreach (WC()->cart->cart_contents as $cart_item) {
             if (isset($cart_item['data']->subscription_trial_period)) {
                 $trial_period = $cart_item['data']->subscription_trial_period;
                 break;
             } elseif (WC_Subscriptions_Product::is_subscription($cart_item['data'])) {
                 $trial_period = WC_Subscriptions_Product::get_trial_period($cart_item['data']);
                 break;
             }
         }
     }
     return apply_filters('woocommerce_subscriptions_cart_trial_period', $trial_period);
 }
Exemplo n.º 15
0
 /**
  * Search for products and return a JSON-encoded string of results
  * using $_GET['term'] as the search term
  */
 public static function wc_json_search_subscription_products()
 {
     check_ajax_referer('search-products', 'security');
     header('Content-Type: application/json; charset=utf-8');
     $term = (string) wc_clean(stripslashes($_GET['term']));
     $post_types = array('product', 'product_variation');
     if (empty($term)) {
         die;
     }
     if (is_numeric($term)) {
         $args = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'post__in' => array(0, $term), 'fields' => 'ids');
         $args2 = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'post_parent' => $term, 'fields' => 'ids');
         $args3 = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => array(array('key' => '_sku', 'value' => $term, 'compare' => 'LIKE')), 'fields' => 'ids');
         $posts = array_unique(array_merge(get_posts($args), get_posts($args2), get_posts($args3)));
     } else {
         $args = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 's' => $term, 'fields' => 'ids');
         $args2 = array('post_type' => $post_types, 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => array(array('key' => '_sku', 'value' => $term, 'compare' => 'LIKE')), 'fields' => 'ids');
         $posts = array_unique(array_merge(get_posts($args), get_posts($args2)));
     }
     $found_products = array();
     if ($posts) {
         foreach ($posts as $post) {
             $product = get_product($post);
             if (WC_Subscriptions_Product::is_subscription($product)) {
                 $found_products[$post] = $product->get_formatted_name();
             }
         }
     }
     $found_products = apply_filters('woocommerce_json_search_found_products', $found_products);
     echo json_encode($found_products);
     die;
 }
 /**
  * Groups tab content.
  */
 public static function product_write_panels()
 {
     global $post, $wpdb, $woocommerce;
     echo '<div id="woocommerce_groups" class="panel woocommerce_options_panel" style="padding: 1em;">';
     if (class_exists('WC_Subscriptions_Product') && WC_Subscriptions_Product::is_subscription($post->ID)) {
         echo '<p>' . __('The customer will be a member of the selected groups as long as the subscription is active. The customer will be removed from the selected groups once the subscription is active.', GROUPS_WS_PLUGIN_DOMAIN) . '</p>';
     } else {
         echo '<p>' . __('The customer will be added to or removed from the selected groups when purchasing this product.', GROUPS_WS_PLUGIN_DOMAIN) . '</p>';
     }
     $product_groups = get_post_meta($post->ID, '_groups_groups', false);
     $product_groups_remove = get_post_meta($post->ID, '_groups_groups_remove', false);
     $group_table = _groups_get_tablename("group");
     $groups = $wpdb->get_results("SELECT * FROM {$group_table} ORDER BY name");
     $n = 0;
     if (count($groups) > 0) {
         echo '<table class="widefat" style="width:50%">';
         echo '<thead>';
         echo '<tr>';
         echo '<th style="width:50%">' . __('Group', GROUPS_WS_PLUGIN_DOMAIN) . '</th>';
         echo '<th style="width:25%">' . __('Add', GROUPS_WS_PLUGIN_DOMAIN) . '</th>';
         echo '<th style="width:25%">' . __('Remove', GROUPS_WS_PLUGIN_DOMAIN) . '</th>';
         echo '</tr>';
         echo '</thead>';
         echo '<tbody>';
         foreach ($groups as $group) {
             if ($group->name !== Groups_Registered::REGISTERED_GROUP_NAME) {
                 echo '<tr>';
                 echo '<th>' . wp_filter_nohtml_kses($group->name) . '</th>';
                 echo '<td>';
                 woocommerce_wp_checkbox(array('id' => '_groups_groups-' . esc_attr($group->group_id), 'label' => '', 'value' => in_array($group->group_id, $product_groups) ? 'yes' : ''));
                 echo '</td>';
                 echo '<td>';
                 woocommerce_wp_checkbox(array('id' => '_groups_groups_remove-' . esc_attr($group->group_id), 'label' => '', 'value' => in_array($group->group_id, $product_groups_remove) ? 'yes' : ''));
                 echo '</td>';
                 echo '</tr>';
                 $n++;
             }
         }
         echo '</tbody>';
         echo '</table>';
         if (!class_exists('WC_Subscriptions_Product') || !WC_Subscriptions_Product::is_subscription($post->ID)) {
             $duration = get_post_meta($post->ID, '_groups_duration', true);
             $duration_uom = get_post_meta($post->ID, '_groups_duration_uom', true);
             if (empty($duration_uom)) {
                 $duration_uom = 'month';
             }
             switch ($duration_uom) {
                 case 'second':
                     $duration_uom_label = _n('Second', 'Seconds', $duration, GROUPS_WS_PLUGIN_DOMAIN);
                     break;
                 case 'minute':
                     $duration_uom_label = _n('Minute', 'Minutes', $duration, GROUPS_WS_PLUGIN_DOMAIN);
                     break;
                 case 'hour':
                     $duration_uom_label = _n('Hour', 'Hours', $duration, GROUPS_WS_PLUGIN_DOMAIN);
                     break;
                 case 'day':
                     $duration_uom_label = _n('Day', 'Days', $duration, GROUPS_WS_PLUGIN_DOMAIN);
                     break;
                 case 'week':
                     $duration_uom_label = _n('Week', 'Weeks', $duration, GROUPS_WS_PLUGIN_DOMAIN);
                     break;
                 case 'year':
                     $duration_uom_label = _n('Year', 'Years', $duration, GROUPS_WS_PLUGIN_DOMAIN);
                     break;
                 default:
                     $duration_uom_label = _n('Month', 'Months', $duration, GROUPS_WS_PLUGIN_DOMAIN);
                     break;
             }
             $duration_help = __('Leave the duration empty unless you want memberships to end after a certain amount of time.', GROUPS_WS_PLUGIN_DOMAIN) . ' ' . __('If the duration is empty, the customer will remain a member of the selected groups forever, unless removed explicitly.', GROUPS_WS_PLUGIN_DOMAIN) . ' ' . __('If the duration is set, the customer will only belong to the selected groups during the specified time, based on the <em>Duration</em> and the <em>Time unit</em>.', GROUPS_WS_PLUGIN_DOMAIN);
             $duration_help_icon = '<img class="help_tip" data-tip="' . esc_attr($duration_help) . '" src="' . $woocommerce->plugin_url() . '/assets/images/help.png" />';
             woocommerce_wp_text_input(array('id' => '_groups_duration', 'label' => sprintf(__('Duration %s', GROUPS_WS_PLUGIN_DOMAIN), $duration_help_icon), 'value' => $duration, 'description' => sprintf(__('%s (as chosen under <em>Time unit</em>)', GROUPS_WS_PLUGIN_DOMAIN), $duration_uom_label), 'placeholder' => __('unlimited', GROUPS_WS_PLUGIN_DOMAIN)));
             woocommerce_wp_select(array('id' => '_groups_duration_uom', 'label' => __('Time unit', GROUPS_WS_PLUGIN_DOMAIN), 'value' => $duration_uom, 'options' => array('second' => __('Seconds', GROUPS_WS_PLUGIN_DOMAIN), 'minute' => __('Minutes', GROUPS_WS_PLUGIN_DOMAIN), 'hour' => __('Hours', GROUPS_WS_PLUGIN_DOMAIN), 'day' => __('Days', GROUPS_WS_PLUGIN_DOMAIN), 'week' => __('Weeks', GROUPS_WS_PLUGIN_DOMAIN), 'month' => __('Months', GROUPS_WS_PLUGIN_DOMAIN), 'year' => __('Years', GROUPS_WS_PLUGIN_DOMAIN))));
             echo '<noscript>' . '<p>' . $duration_help . '</p>' . '</noscript>';
         }
     }
     if ($n == 0) {
         echo '<p>' . __('There are no groups available to select. At least one group (other than <em>Registered</em>) must be created.', GROUPS_WS_PLUGIN_DOMAIN) . '</p>';
     }
     echo '<p>' . __('Note that all users belong to the <em>Registered</em> group automatically.', GROUPS_WS_PLUGIN_DOMAIN) . '</p>';
     echo '<br/>';
     echo '</div>';
 }
 /**
  * Save subscription details when edit product page is submitted for a subscription product type
  * or the bulk edit product is saved.
  * 
  * The $_REQUEST global is used to account for both $_GET submission from Bulk Edit page and 
  * $_POST submission from Edit Product page.
  * 
  * @param array Array of Product types & their labels, excluding the Subscription product type.
  * @return array Array of Product types & their labels, including the Subscription product type.
  * @since 1.0
  */
 public static function save_subscription_meta($post_id)
 {
     if (!WC_Subscriptions_Product::is_subscription($post_id)) {
         return;
     }
     if (isset($_REQUEST['_subscription_price'])) {
         update_post_meta($post_id, '_subscription_price', stripslashes($_REQUEST['_subscription_price']));
         // Set sale details - these are ignored by WC core for the subscription product type
         update_post_meta($post_id, '_regular_price', stripslashes($_POST['_subscription_price']));
         update_post_meta($post_id, '_sale_price', stripslashes($_POST['_sale_price']));
         $date_from = isset($_POST['_sale_price_dates_from']) ? strtotime($_POST['_sale_price_dates_from']) : '';
         $date_to = isset($_POST['_sale_price_dates_to']) ? strtotime($_POST['_sale_price_dates_to']) : '';
         $now = strtotime('NOW', current_time('timestamp'));
         if (!empty($date_to) && empty($date_from)) {
             $date_from = $now;
         }
         update_post_meta($post_id, '_sale_price_dates_from', $date_from);
         update_post_meta($post_id, '_sale_price_dates_to', $date_to);
         // Update price if on sale
         if (!empty($_POST['_sale_price']) && (empty($date_to) && empty($date_from) || $date_from < $now && (empty($date_to) || $date_to > $now))) {
             $price = $_POST['_sale_price'];
         } else {
             $price = $_POST['_subscription_price'];
         }
         update_post_meta($post_id, '_price', stripslashes($price));
         // Make sure trial period is within allowable range
         $subscription_ranges = WC_Subscriptions_Manager::get_subscription_ranges();
         $max_trial_length = count($subscription_ranges[$_POST['_subscription_trial_period']]) - 1;
         $_POST['_subscription_trial_length'] = absint($_POST['_subscription_trial_length']);
         if ($_POST['_subscription_trial_length'] > $max_trial_length) {
             $_POST['_subscription_trial_length'] = $max_trial_length;
         }
         update_post_meta($post_id, '_subscription_trial_length', $_POST['_subscription_trial_length']);
     } else {
         // Handle bulk edit, where _subscription_price field is not available
         if (isset($_REQUEST['_regular_price']) && !empty($_REQUEST['_regular_price'])) {
             update_post_meta($post_id, '_subscription_price', stripslashes($_REQUEST['_regular_price']));
             update_post_meta($post_id, '_price', stripslashes($_REQUEST['_regular_price']));
         }
     }
     $subscription_fields = array('_subscription_sign_up_fee', '_subscription_period', '_subscription_period_interval', '_subscription_length', '_subscription_trial_period');
     foreach ($subscription_fields as $field_name) {
         if (isset($_REQUEST[$field_name])) {
             update_post_meta($post_id, $field_name, stripslashes($_REQUEST[$field_name]));
         }
     }
 }
 /**
  * If a product is being marked as not purchasable because it is limited and the customer has a subscription,
  * but the current request is to switch the subscription, then mark it as purchasable.
  *
  * @since 1.4.4
  * @return bool
  */
 public static function is_purchasable($is_purchasable, $product)
 {
     $product_key = !empty($product->variation_id) ? $product->variation_id : $product->id;
     if (!isset(self::$is_purchasable_cache[$product_key])) {
         if (false === $is_purchasable && wcs_is_product_switchable_type($product) && WC_Subscriptions_Product::is_subscription($product->id) && 'no' != $product->limit_subscriptions && is_user_logged_in() && wcs_user_has_subscription(0, $product->id, $product->limit_subscriptions)) {
             // Adding to cart from the product page
             if (isset($_GET['switch-subscription'])) {
                 $is_purchasable = true;
                 // Validating when restring cart from session
             } elseif (self::cart_contains_switches()) {
                 $is_purchasable = true;
                 // Restoring cart from session, so need to check the cart in the session (self::cart_contains_subscription_switch() only checks the cart)
             } elseif (isset(WC()->session->cart)) {
                 foreach (WC()->session->cart as $cart_item_key => $cart_item) {
                     if ($product->id == $cart_item['product_id'] && isset($cart_item['subscription_switch'])) {
                         $is_purchasable = true;
                         break;
                     }
                 }
             }
         }
         self::$is_purchasable_cache[$product_key] = $is_purchasable;
     }
     return self::$is_purchasable_cache[$product_key];
 }
 /**
  * Removes the "set_subscription_prices_for_calculation" filter from the WC Product's woocommerce_get_price hook once
  *
  * @since 1.5.10
  */
 public static function set_prorated_price_for_calculation($price, $product)
 {
     if (WC_Subscriptions_Product::is_subscription($product) && self::is_product_prorated($product) && in_array(WC_Subscriptions_Cart::get_calculation_type(), array('combined_total', 'none'))) {
         $next_payment_date = self::calculate_first_payment_date($product, 'timestamp');
         if (self::is_today($next_payment_date)) {
             return $price;
         }
         switch ($product->subscription_period) {
             case 'week':
                 $days_in_cycle = 7 * $product->subscription_period_interval;
                 break;
             case 'month':
                 $days_in_cycle = date('t') * $product->subscription_period_interval;
                 break;
             case 'year':
                 $days_in_cycle = (365 + date('L')) * $product->subscription_period_interval;
                 break;
         }
         $days_until_next_payment = ceil(($next_payment_date - gmdate('U')) / (60 * 60 * 24));
         if ('combined_total' == WC_Subscriptions_Cart::get_calculation_type()) {
             $sign_up_fee = WC_Subscriptions_Product::get_sign_up_fee($product);
             if ($sign_up_fee > 0 && 0 == WC_Subscriptions_Product::get_trial_length($product)) {
                 $price = $sign_up_fee + $days_until_next_payment * (($price - $sign_up_fee) / $days_in_cycle);
             }
         } elseif ('none' == WC_Subscriptions_Cart::get_calculation_type()) {
             $price = $days_until_next_payment * ($price / $days_in_cycle);
         }
     }
     return $price;
 }
 /**
  * True if a cart item can be converted from a one-shot purchase to a subscription and vice-versa.
  * Subscription product types can't be converted to non-sub items.
  *
  * @param  array  $cart_item
  * @return boolean
  */
 public static function is_convertible_to_sub($cart_item)
 {
     $product_id = $cart_item['product_id'];
     $is_convertible = true;
     if (WC_Subscriptions_Product::is_subscription($product_id)) {
         $is_convertible = false;
     }
     return $is_convertible;
 }
 /**
  * Returns subscription schemes for cart-level options.
  * Cart-level options will be displayed only if no cart-item is found with its own product-level subscription scheme.
  * This means that subscription options defined at product-level and "legacy" subscription-type products will "block" the display of cart-level options.
  *
  * In this case, cart-level options will be displayed at cart-item level.
  *
  * Must be called after all cart session data has been loaded.
  *
  * @return array|boolean
  */
 public static function get_cart_subscription_schemes()
 {
     $wcs_prefix = WC_Subscriptions_Admin::$option_prefix;
     $cart_level_subs_active = get_option($wcs_prefix . '_enable_cart_subscriptions', 'no');
     $cart_level_schemes = array();
     $cart_level_schemes_keys = array();
     if ($cart_level_subs_active === 'yes') {
         $cart_level_schemes = get_option($wcs_prefix . '_subscribe_to_cart_schemes', array());
     }
     if (empty($cart_level_schemes)) {
         return false;
     }
     foreach ($cart_level_schemes as $cart_level_scheme) {
         $cart_level_schemes_keys[] = $cart_level_scheme['id'];
     }
     foreach (WC()->cart->cart_contents as $cart_item) {
         if (!WCS_ATT_Cart::is_supported_product_type($cart_item)) {
             return false;
         }
         if ($cart_item_level_schemes = self::get_subscription_schemes($cart_item, 'cart-item')) {
             return false;
         }
         if (WC_Subscriptions_Product::is_subscription($cart_item['product_id'])) {
             return false;
         }
     }
     return $cart_level_schemes;
 }
 /**
  * Calculate recurring line taxes when a store manager clicks the "Calc Line Tax" button on the "Edit Order" page.
  *
  * Based on the @see woocommerce_calc_line_taxes() function.
  * @since 1.2.4
  * @return void
  */
 public static function calculate_recurring_line_taxes()
 {
     global $woocommerce, $wpdb;
     check_ajax_referer('woocommerce-subscriptions', 'security');
     $tax = new WC_Tax();
     $taxes = $tax_rows = $item_taxes = $shipping_taxes = $return = array();
     $item_tax = 0;
     $order_id = absint($_POST['order_id']);
     $country = strtoupper(esc_attr($_POST['country']));
     $state = strtoupper(esc_attr($_POST['state']));
     $postcode = strtoupper(esc_attr($_POST['postcode']));
     $tax_class = esc_attr($_POST['tax_class']);
     if (isset($_POST['city'])) {
         $city = sanitize_title(esc_attr($_POST['city']));
     }
     $shipping = $_POST['shipping'];
     $line_subtotal = isset($_POST['line_subtotal']) ? esc_attr($_POST['line_subtotal']) : 0;
     $line_total = isset($_POST['line_total']) ? esc_attr($_POST['line_total']) : 0;
     $product_id = '';
     if (isset($_POST['order_item_id'])) {
         $product_id = woocommerce_get_order_item_meta($_POST['order_item_id'], '_product_id');
     } elseif (isset($_POST['product_id'])) {
         $product_id = esc_attr($_POST['product_id']);
     }
     if (!empty($product_id) && WC_Subscriptions_Product::is_subscription($product_id)) {
         // Get product details
         $product = WC_Subscriptions::get_product($product_id);
         $item_tax_status = $product->get_tax_status();
         if ($item_tax_status == 'taxable') {
             $tax_rates = $tax->find_rates(array('country' => $country, 'state' => $state, 'postcode' => $postcode, 'city' => $city, 'tax_class' => $tax_class));
             $line_subtotal_taxes = $tax->calc_tax($line_subtotal, $tax_rates, false);
             $line_taxes = $tax->calc_tax($line_total, $tax_rates, false);
             $line_subtotal_tax = $tax->round(array_sum($line_subtotal_taxes));
             $line_tax = $tax->round(array_sum($line_taxes));
             if ($line_subtotal_tax < 0) {
                 $line_subtotal_tax = 0;
             }
             if ($line_tax < 0) {
                 $line_tax = 0;
             }
             $return = array('recurring_line_subtotal_tax' => $line_subtotal_tax, 'recurring_line_tax' => $line_tax);
             // Sum the item taxes
             foreach (array_keys($taxes + $line_taxes) as $key) {
                 $taxes[$key] = (isset($line_taxes[$key]) ? $line_taxes[$key] : 0) + (isset($taxes[$key]) ? $taxes[$key] : 0);
             }
         }
         // Now calculate shipping tax
         $matched_tax_rates = array();
         $tax_rates = $tax->find_rates(array('country' => $country, 'state' => $state, 'postcode' => $postcode, 'city' => $city, 'tax_class' => ''));
         if ($tax_rates) {
             foreach ($tax_rates as $key => $rate) {
                 if (isset($rate['shipping']) && $rate['shipping'] == 'yes') {
                     $matched_tax_rates[$key] = $rate;
                 }
             }
         }
         $shipping_taxes = $tax->calc_shipping_tax($shipping, $matched_tax_rates);
         $shipping_tax = $tax->round(array_sum($shipping_taxes));
         $return['recurring_shipping_tax'] = $shipping_tax;
         // Remove old tax rows
         $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 AND order_item_type = 'recurring_tax' )", $order_id));
         $wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}woocommerce_order_items WHERE order_id = %d AND order_item_type = 'recurring_tax'", $order_id));
         // Get tax rates
         $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)));
         }
         // Now merge to keep tax rows
         ob_start();
         foreach (array_keys($taxes + $shipping_taxes) as $key) {
             $item = array();
             $item['rate_id'] = $key;
             $item['name'] = $tax_codes[$key];
             $item['label'] = $tax->get_rate_label($key);
             $item['compound'] = $tax->is_compound($key) ? 1 : 0;
             $item['tax_amount'] = $tax->round(isset($taxes[$key]) ? $taxes[$key] : 0);
             $item['shipping_tax_amount'] = $tax->round(isset($shipping_taxes[$key]) ? $shipping_taxes[$key] : 0);
             if (!$item['label']) {
                 $item['label'] = $woocommerce->countries->tax_or_vat();
             }
             // Add line item
             $item_id = woocommerce_add_order_item($order_id, array('order_item_name' => $item['name'], 'order_item_type' => 'recurring_tax'));
             // Add line item meta
             if ($item_id) {
                 woocommerce_add_order_item_meta($item_id, 'rate_id', $item['rate_id']);
                 woocommerce_add_order_item_meta($item_id, 'label', $item['label']);
                 woocommerce_add_order_item_meta($item_id, 'compound', $item['compound']);
                 woocommerce_add_order_item_meta($item_id, 'tax_amount', $item['tax_amount']);
                 woocommerce_add_order_item_meta($item_id, 'shipping_tax_amount', $item['shipping_tax_amount']);
             }
             include plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/admin/post-types/writepanels/order-tax-html.php';
         }
         $return['tax_row_html'] = ob_get_clean();
         echo json_encode($return);
     }
     die;
 }
 /**
  * Override the WooCommerce "Add to Cart" text with "Sign Up Now"
  *
  * @since 1.0
  */
 public static function add_to_cart_text($button_text)
 {
     global $product;
     if (WC_Subscriptions_Product::is_subscription($product)) {
         $button_text = get_option(WC_Subscriptions_Admin::$option_prefix . '_add_to_cart_button_text', __('Sign Up Now', self::$text_domain));
     }
     return $button_text;
 }
 /**
  * Uses the details of an order to create a pending subscription on the customers account
  * for a subscription product, as specified with $product_id.
  *
  * @param int|WC_Order $order The order ID or WC_Order object to create the subscription from.
  * @param int $product_id The ID of the subscription product on the order.
  * @param array $args An array of name => value pairs to customise the details of the subscription, including:
  * 			'start_date' A MySQL formatted date/time string on which the subscription should start, in UTC timezone
  * 			'expiry_date' A MySQL formatted date/time string on which the subscription should expire, in UTC timezone
  * @since 1.1
  */
 public static function create_pending_subscription_for_order($order, $product_id, $args = array())
 {
     if (!is_object($order)) {
         $order = new WC_Order($order);
     }
     if (!WC_Subscriptions_Product::is_subscription($product_id)) {
         return;
     }
     $args = wp_parse_args($args, array('start_date' => '', 'expiry_date' => ''));
     $subscription_key = self::get_subscription_key($order->id, $product_id);
     // In case the subscription exists already
     $subscription = self::get_subscription($subscription_key);
     if (!empty($subscription['variation_id'])) {
         $product_id = $subscription['variation_id'];
     } elseif (!empty($subscription['product_id'])) {
         $product_id = $subscription['product_id'];
     }
     // Adding a new subscription so set the start date/time to now
     if (!empty($args['start_date'])) {
         if (is_numeric($args['start_date'])) {
             $args['start_date'] = date('Y-m-d H:i:s', $args['start_date']);
         }
         $start_date = $args['start_date'];
     } else {
         $start_date = !empty($subscription['start_date']) ? $subscription['start_date'] : gmdate('Y-m-d H:i:s');
     }
     // Adding a new subscription so set the expiry date/time from the order date
     if (!empty($args['expiry_date'])) {
         if (is_numeric($args['expiry_date'])) {
             $args['expiry_date'] = date('Y-m-d H:i:s', $args['expiry_date']);
         }
         $expiration = $args['expiry_date'];
     } else {
         $expiration = !empty($subscription['expiry_date']) ? $subscription['expiry_date'] : WC_Subscriptions_Product::get_expiration_date($product_id, $start_date);
     }
     // Adding a new subscription so set the expiry date/time from the order date
     $trial_expiration = !empty($subscription['trial_expiry_date']) ? $subscription['trial_expiry_date'] : WC_Subscriptions_Product::get_trial_expiration_date($product_id, $start_date);
     $failed_payments = !empty($subscription['failed_payments']) ? $subscription['failed_payments'] : 0;
     $completed_payments = !empty($subscription['completed_payments']) ? $subscription['completed_payments'] : array();
     $order_item_id = WC_Subscriptions_Order::get_item_id_by_subscription_key($subscription_key);
     // Store the subscription details in item meta
     woocommerce_add_order_item_meta($order_item_id, '_subscription_start_date', $start_date, true);
     woocommerce_add_order_item_meta($order_item_id, '_subscription_expiry_date', $expiration, true);
     woocommerce_add_order_item_meta($order_item_id, '_subscription_trial_expiry_date', $trial_expiration, true);
     woocommerce_add_order_item_meta($order_item_id, '_subscription_failed_payments', $failed_payments, true);
     woocommerce_add_order_item_meta($order_item_id, '_subscription_completed_payments', $completed_payments, true);
     woocommerce_add_order_item_meta($order_item_id, '_subscription_status', 'pending', true);
     woocommerce_add_order_item_meta($order_item_id, '_subscription_end_date', 0, true);
     woocommerce_add_order_item_meta($order_item_id, '_subscription_suspension_count', 0, true);
     $product = WC_Subscriptions::get_product($product_id);
     // Set subscription status to active and log activation
     $order->add_order_note(sprintf(__('Pending subscription created for "%s".', 'woocommerce-subscriptions'), $product->get_title()));
     do_action('pending_subscription_created_for_order', $order, $product_id);
 }
 /**
  * Clear all subscriptions from a user's account for a given order.
  *
  * @param $order WC_Order The order for which subscriptions should be cleared.
  * @since 1.0
  */
 public static function maybe_trash_subscription($order)
 {
     if (!is_object($order)) {
         $order = new WC_Order($order);
     }
     if (WC_Subscriptions_Order::order_contains_subscription($order)) {
         foreach ($order->get_items() as $order_item) {
             if (WC_Subscriptions_Product::is_subscription($order_item['id'])) {
                 self::trash_subscription($order->customer_user, self::get_subscription_key($order->id, $order_item['id']));
             }
         }
     }
 }
 /**
  * Apply sign up fee or recurring fee discount
  *
  * @since 1.2
  */
 public static function apply_subscription_discount($original_price, $cart_item, $cart)
 {
     $product_id = $cart_item['data']->is_type(array('subscription_variation')) ? $cart_item['data']->variation_id : $cart_item['data']->id;
     if (!WC_Subscriptions_Product::is_subscription($product_id)) {
         return $original_price;
     }
     $price = $calculation_price = $original_price;
     $calculation_type = WC_Subscriptions_Cart::get_calculation_type();
     if (!empty($cart->applied_coupons)) {
         foreach ($cart->applied_coupons as $code) {
             $coupon = new WC_Coupon($code);
             if ($coupon->apply_before_tax() && $coupon->is_valid()) {
                 $apply_recurring_coupon = $apply_recurring_percent_coupon = $apply_initial_coupon = $apply_initial_percent_coupon = false;
                 // Apply recurring fee discounts to recurring total calculations
                 if ('recurring_total' == $calculation_type) {
                     $apply_recurring_coupon = 'recurring_fee' == $coupon->type ? true : false;
                     $apply_recurring_percent_coupon = 'recurring_percent' == $coupon->type ? true : false;
                 }
                 if ('none' == $calculation_type) {
                     // If all items have a free trial we don't need to apply recurring coupons to the initial total
                     if (!WC_Subscriptions_Cart::all_cart_items_have_free_trial()) {
                         if ('recurring_fee' == $coupon->type) {
                             $apply_initial_coupon = true;
                         }
                         if ('recurring_percent' == $coupon->type) {
                             $apply_initial_percent_coupon = true;
                         }
                     }
                     // Apply sign-up discounts to initial total
                     if (!empty($cart_item['data']->subscription_sign_up_fee)) {
                         if ('sign_up_fee' == $coupon->type) {
                             $apply_initial_coupon = true;
                         }
                         if ('sign_up_fee_percent' == $coupon->type) {
                             $apply_initial_percent_coupon = true;
                         }
                         $calculation_price = $cart_item['data']->subscription_sign_up_fee;
                     }
                 }
                 if ($apply_recurring_coupon || $apply_initial_coupon) {
                     $discount_amount = $calculation_price < $coupon->amount ? $calculation_price : $coupon->amount;
                     // Recurring coupons only apply when there is no free trial (carts can have a mix of free trial and non free trial items)
                     if ($apply_initial_coupon && 'recurring_fee' == $coupon->type && !empty($cart_item['data']->subscription_trial_length)) {
                         $discount_amount = 0;
                     }
                     $cart->discount_cart = $cart->discount_cart + $discount_amount * $cart_item['quantity'];
                     $cart = self::increase_coupon_discount_amount($cart, $coupon->code, $discount_amount * $cart_item['quantity']);
                     $price = $price - $discount_amount;
                 } elseif ($apply_recurring_percent_coupon) {
                     $discount_amount = round($calculation_price / 100 * $coupon->amount, WC()->cart->dp);
                     $cart->discount_cart = $cart->discount_cart + $discount_amount * $cart_item['quantity'];
                     $cart = self::increase_coupon_discount_amount($cart, $coupon->code, $discount_amount * $cart_item['quantity']);
                     $price = $price - $discount_amount;
                 } elseif ($apply_initial_percent_coupon) {
                     // Recurring coupons only apply when there is no free trial (carts can have a mix of free trial and non free trial items)
                     if ('recurring_percent' == $coupon->type && empty($cart_item['data']->subscription_trial_length)) {
                         $amount_to_discount = $cart_item['data']->subscription_price;
                     } else {
                         $amount_to_discount = 0;
                     }
                     // Sign up fee coupons only apply to sign up fees
                     if ('sign_up_fee_percent' == $coupon->type) {
                         $amount_to_discount = $cart_item['data']->subscription_sign_up_fee;
                     }
                     $discount_amount = round($amount_to_discount / 100 * $coupon->amount, WC()->cart->dp);
                     $cart->discount_cart = $cart->discount_cart + $discount_amount * $cart_item['quantity'];
                     $cart = self::increase_coupon_discount_amount($cart, $coupon->code, $discount_amount * $cart_item['quantity']);
                     $price = $price - $discount_amount;
                 }
             }
         }
         if ($price < 0) {
             $price = 0;
         }
     }
     return $price;
 }
 /**
  * When an order is added or updated from the admin interface, check if a new subscription product
  * has been manually added to the order, and if one has, create a new subscription. 
  * 
  * @param $post_id int The ID of the post which is the WC_Order object.
  * @param $post Object The post object of the order.
  * @since 1.1
  */
 public static function maybe_manually_change_subscriptions($post_id, $post)
 {
     $order = new WC_Order($post_id);
     // Check if all the subscription products on the order have associated subscriptions on the user's account, and if not, add a new one
     foreach ($_POST['item_id'] as $item_id) {
         if (!WC_Subscriptions_Product::is_subscription($item_id)) {
             continue;
         }
         $subscription_key = WC_Subscriptions_Manager::get_subscription_key($post_id, $item_id);
         $subscription = array();
         // If order customer changed, move the subscription from the old customer's account to the new customer
         if (!empty($order->customer_user) && $order->customer_user != (int) $_POST['customer_user']) {
             $subscription = WC_Subscriptions_Manager::remove_users_subscription($order->customer_user, $subscription_key);
             $subscriptions = WC_Subscriptions_Manager::get_users_subscriptions((int) $_POST['customer_user']);
             if (!empty($subscription)) {
                 $subscriptions[$subscription_key] = $subscription;
                 WC_Subscriptions_Manager::update_users_subscriptions((int) $_POST['customer_user'], $subscriptions);
             }
         }
         // In case it's a new order or the customer has changed
         $order->customer_user = $order->user_id = (int) $_POST['customer_user'];
         $subscription = WC_Subscriptions_Manager::get_users_subscription($order->customer_user, $subscription_key);
         if (empty($subscription)) {
             // Add a new subscription
             // The order doesn't may not exist yet, so we need to set a few things ourselves
             $order->order_key = uniqid('order_');
             add_post_meta($post_id, '_order_key', $order->order_key, true);
             WC_Subscriptions_Manager::create_pending_subscription_for_order($order, $item_id);
             // Add the subscription meta for this item to the order
             $functions_and_meta = array('get_period' => '_order_subscription_periods', 'get_interval' => '_order_subscription_intervals', 'get_length' => '_order_subscription_lengths');
             foreach ($functions_and_meta as $function_name => $meta_key) {
                 $subscription_meta = self::get_meta($order, $meta_key, array());
                 $subscription_meta[$item_id] = WC_Subscriptions_Product::$function_name($item_id);
                 update_post_meta($order->id, $meta_key, $subscription_meta);
             }
             // Set the subscription's status if it should be something other than pending
             switch ($order->status) {
                 case 'completed':
                 case 'processing':
                     WC_Subscriptions_Manager::activate_subscription($order->customer_user, $subscription_key);
                     break;
                 case 'refunded':
                 case 'cancelled':
                     WC_Subscriptions_Manager::cancel_subscription($order->customer_user, $subscription_key);
                     break;
                 case 'failed':
                     WC_Subscriptions_Manager::failed_subscription_signup($order->customer_user, $subscription_key);
                     break;
             }
         }
     }
 }
 /**
  * Save a variable subscription's details when the edit product page is submitted for a variable
  * subscription product type (or the bulk edit product is saved).
  *
  * @param int $post_id ID of the parent WC_Product_Variable_Subscription
  * @return null
  * @since 1.3
  */
 public static function process_product_meta_variable_subscription($post_id)
 {
     if (!WC_Subscriptions_Product::is_subscription($post_id) || empty($_POST['_wcsnonce_save_variations']) || !wp_verify_nonce($_POST['_wcsnonce_save_variations'], 'wcs_subscription_variations')) {
         return;
     }
     // Make sure WooCommerce calculates correct prices
     $_POST['variable_regular_price'] = isset($_POST['variable_subscription_price']) ? $_POST['variable_subscription_price'] : 0;
     // Run WooCommerce core saving routine for WC < 2.4
     if (!is_ajax()) {
         WC_Meta_Box_Product_Data::save_variations($post_id, get_post($post_id));
     }
     if (!isset($_REQUEST['variable_post_id'])) {
         return;
     }
     $variable_post_ids = $_POST['variable_post_id'];
     $max_loop = max(array_keys($variable_post_ids));
     // Save each variations details
     for ($i = 0; $i <= $max_loop; $i++) {
         if (!isset($variable_post_ids[$i])) {
             continue;
         }
         $variation_id = absint($variable_post_ids[$i]);
         if (isset($_POST['variable_subscription_price']) && is_array($_POST['variable_subscription_price'])) {
             $subscription_price = wc_format_decimal($_POST['variable_subscription_price'][$i]);
             update_post_meta($variation_id, '_subscription_price', $subscription_price);
             update_post_meta($variation_id, '_regular_price', $subscription_price);
         }
         // Make sure trial period is within allowable range
         $subscription_ranges = wcs_get_subscription_ranges();
         $max_trial_length = count($subscription_ranges[$_POST['variable_subscription_trial_period'][$i]]) - 1;
         $_POST['variable_subscription_trial_length'][$i] = absint($_POST['variable_subscription_trial_length'][$i]);
         if ($_POST['variable_subscription_trial_length'][$i] > $max_trial_length) {
             $_POST['variable_subscription_trial_length'][$i] = $max_trial_length;
         }
         // Work around a WPML bug which means 'variable_subscription_trial_period' is not set when using "Edit Product" as the product translation interface
         if ($_POST['variable_subscription_trial_length'][$i] < 0) {
             $_POST['variable_subscription_trial_length'][$i] = 0;
         }
         $subscription_fields = array('_subscription_sign_up_fee', '_subscription_period', '_subscription_period_interval', '_subscription_length', '_subscription_trial_period', '_subscription_trial_length');
         foreach ($subscription_fields as $field_name) {
             if (isset($_POST['variable' . $field_name][$i])) {
                 update_post_meta($variation_id, $field_name, wc_clean($_POST['variable' . $field_name][$i]));
             }
         }
     }
     // Now that all the variation's meta is saved, sync the min variation price
     $variable_subscription = wc_get_product($post_id);
     $variable_subscription->variable_product_sync();
 }
Exemplo n.º 29
0
 /**
  * Uses the details of an order to create a pending subscription on the customers account
  * for a subscription product, as specified with $product_id.
  *
  * @param $order mixed int | WC_Order The order ID or WC_Order object to create the subscription from.
  * @param $product_id int The ID of the subscription product on the order.
  * @param $args array An array of name => value pairs to customise the details of the subscription, including:
  * 			'start_date' A MySQL formatted date/time string on which the subscription should start, in UTC timezone
  * 			'expiry_date' A MySQL formatted date/time string on which the subscription should expire, in UTC timezone
  * @since 1.1
  */
 public static function create_pending_subscription_for_order($order, $product_id, $args = array())
 {
     if (!is_object($order)) {
         $order = new WC_Order($order);
     }
     if (!WC_Subscriptions_Product::is_subscription($product_id)) {
         return;
     }
     $args = wp_parse_args($args, array('start_date' => '', 'expiry_date' => ''));
     $subscription_key = self::get_subscription_key($order->id, $product_id);
     // In case the subscription exists already
     $subscription = self::get_users_subscription($order->customer_user, $subscription_key);
     // Adding a new subscription so set the start date/time to now
     if (!empty($args['start_date'])) {
         if (is_numeric($args['start_date'])) {
             $args['start_date'] = date('Y-m-d H:i:s', $args['start_date']);
         }
         $start_date = $args['start_date'];
     } else {
         $start_date = isset($subscription['start_date']) ? $subscription['start_date'] : gmdate('Y-m-d H:i:s');
     }
     // Adding a new subscription so set the expiry date/time from the order date
     if (!empty($args['expiry_date'])) {
         if (is_numeric($args['expiry_date'])) {
             $args['expiry_date'] = date('Y-m-d H:i:s', $args['expiry_date']);
         }
         $expiration = $args['expiry_date'];
     } else {
         $expiration = isset($subscription['expiry_date']) ? $subscription['expiry_date'] : WC_Subscriptions_Product::get_expiration_date($product_id, $start_date);
     }
     // Adding a new subscription so set the expiry date/time from the order date
     $trial_expiration = isset($subscription['trial_expiry_date']) ? $subscription['trial_expiry_date'] : WC_Subscriptions_Product::get_trial_expiration_date($product_id, $start_date);
     $failed_payments = isset($subscription['failed_payments']) ? $subscription['failed_payments'] : 0;
     $completed_payments = isset($subscription['completed_payments']) ? $subscription['completed_payments'] : array();
     $subscriptions[$subscription_key] = array('product_id' => $product_id, 'order_key' => $order->order_key, 'order_id' => $order->id, 'start_date' => $start_date, 'expiry_date' => $expiration, 'end_date' => 0, 'status' => 'pending', 'trial_expiry_date' => $trial_expiration, 'failed_payments' => $failed_payments, 'completed_payments' => $completed_payments);
     self::update_users_subscriptions($order->customer_user, $subscriptions);
     $product = WC_Subscriptions::get_product($product_id);
     // Set subscription status to active and log activation
     $order->add_order_note(sprintf(__('Pending subscription created for "%s".', WC_Subscriptions::$text_domain), $product->get_title()));
     do_action('pending_subscription_created_for_order', $order, $product_id);
 }
 /**
  * Apply sign up fee or recurring fee discount after tax is calculated
  *
  * @since 1.2
  * @version 1.3.6
  */
 public static function apply_subscription_discount_after_tax($coupon, $cart_item, $price)
 {
     global $woocommerce;
     $calculation_type = WC_Subscriptions_Cart::get_calculation_type();
     if (sizeof($woocommerce->cart->cart_contents) > 0) {
         foreach ($woocommerce->cart->cart_contents as $cart_item_key => $cart_item) {
             if (!WC_Subscriptions_Product::is_subscription($cart_item['product_id'])) {
                 continue;
             }
             if (!$coupon->apply_before_tax() && $coupon->is_valid() && self::is_subscription_discountable($cart_item, $coupon)) {
                 $apply_sign_up_coupon = $apply_sign_up_percent_coupon = $apply_recurring_coupon = $apply_recurring_percent_coupon = $apply_initial_coupon = $apply_initial_percent_coupon = false;
                 if ('sign_up_fee_total' == $calculation_type) {
                     $apply_sign_up_coupon = 'sign_up_fee' == $coupon->type ? true : false;
                     $apply_sign_up_percent_coupon = 'sign_up_fee_percent' == $coupon->type ? true : false;
                 } elseif ('recurring_total' == $calculation_type) {
                     $apply_recurring_coupon = 'recurring_fee' == $coupon->type ? true : false;
                     $apply_recurring_percent_coupon = 'recurring_percent' == $coupon->type ? true : false;
                 }
                 if (in_array($calculation_type, array('combined_total', 'none'))) {
                     if (!WC_Subscriptions_Cart::cart_contains_free_trial()) {
                         // Apply recurring discounts to initial total
                         if ('recurring_fee' == $coupon->type) {
                             $apply_initial_coupon = true;
                         }
                         if ('recurring_percent' == $coupon->type) {
                             $apply_initial_percent_coupon = true;
                         }
                     }
                     if (WC_Subscriptions_Cart::get_cart_subscription_sign_up_fee() > 0) {
                         // Apply sign-up discounts to initial total
                         if ('sign_up_fee' == $coupon->type) {
                             $apply_initial_coupon = true;
                         }
                         if ('sign_up_fee_percent' == $coupon->type) {
                             $apply_initial_percent_coupon = true;
                         }
                     }
                 }
                 // Deduct coupon amounts
                 if ($apply_sign_up_coupon || $apply_recurring_coupon || $apply_initial_coupon) {
                     if ($price < $coupon->amount) {
                         $discount_amount = $price;
                     } else {
                         $discount_amount = $coupon->amount;
                     }
                     $woocommerce->cart->discount_total = $woocommerce->cart->discount_total + $discount_amount * $cart_item['quantity'];
                     WC_Subscriptions_Cart::increase_coupon_discount_amount($coupon->code, $discount_amount * $cart_item['quantity']);
                     // Deduct coupon % discounts from relevant total
                 } elseif ($apply_sign_up_percent_coupon || $apply_recurring_percent_coupon) {
                     $woocommerce->cart->discount_total = $woocommerce->cart->discount_total + round($price / 100 * $coupon->amount, $woocommerce->cart->dp);
                     WC_Subscriptions_Cart::increase_coupon_discount_amount($coupon->code, round($price / 100 * $coupon->amount, $woocommerce->cart->dp));
                     // Deduct coupon % discounts from combined total (we need to calculate percent from base price)
                 } elseif ($apply_initial_percent_coupon) {
                     $product_id = $cart_item['data']->is_type(array('subscription_variation')) ? $cart_item['data']->variation_id : $cart_item['data']->id;
                     // We need to calculate the right amount to discount when the price is the combined sign-up fee and recurring amount
                     if ('combined_total' == $calculation_type && !WC_Subscriptions_Cart::cart_contains_free_trial() && isset($woocommerce->cart->base_sign_up_fees[$product_id]) && $woocommerce->cart->base_sign_up_fees[$product_id] > 0) {
                         $base_total = $woocommerce->cart->base_sign_up_fees[$product_id] + $woocommerce->cart->base_recurring_prices[$product_id];
                         if ('recurring_percent' == $coupon->type) {
                             $portion_of_total = $woocommerce->cart->base_recurring_prices[$product_id] / $base_total;
                         }
                         if ('sign_up_fee_percent' == $coupon->type) {
                             $portion_of_total = $woocommerce->cart->base_sign_up_fees[$product_id] / $base_total;
                         }
                         $amount_to_discount = WC_Subscriptions_Manager::get_amount_from_proportion($price, $portion_of_total);
                     } else {
                         $amount_to_discount = $price;
                     }
                     $discount_amount = round($amount_to_discount / 100 * $coupon->amount, $woocommerce->cart->dp);
                     $woocommerce->cart->discount_total = $woocommerce->cart->discount_total + $discount_amount;
                     WC_Subscriptions_Cart::increase_coupon_discount_amount($coupon->code, $discount_amount);
                 }
             }
         }
     }
 }