/**
  * When a new order is inserted, add the subscriptions period to the order. 
  * 
  * It's important that the period is tied to the order so that changing the products
  * period does not change the past. 
  *
  * @since 1.0
  */
 public static function add_order_meta($order_id)
 {
     global $woocommerce;
     if (WC_Subscriptions_Order::order_contains_subscription($order_id)) {
         $order = new WC_Order($order_id);
         $order_subscription_periods = array();
         $order_subscription_intervals = array();
         $order_subscription_lengths = array();
         $order_subscription_trial_lengths = array();
         foreach ($order->get_items() as $item) {
             $period = WC_Subscriptions_Product::get_period($item['id']);
             if (!empty($period)) {
                 $order_subscription_periods[$item['id']] = $period;
             }
             $interval = WC_Subscriptions_Product::get_interval($item['id']);
             if (!empty($interval)) {
                 $order_subscription_intervals[$item['id']] = $interval;
             }
             $length = WC_Subscriptions_Product::get_length($item['id']);
             if (!empty($length)) {
                 $order_subscription_lengths[$item['id']] = $length;
             }
             $trial_length = WC_Subscriptions_Product::get_trial_length($item['id']);
             if (!empty($trial_length)) {
                 $order_subscription_trial_lengths[$item['id']] = $trial_length;
             }
         }
         update_post_meta($order_id, '_order_subscription_periods', $order_subscription_periods);
         update_post_meta($order_id, '_order_subscription_intervals', $order_subscription_intervals);
         update_post_meta($order_id, '_order_subscription_lengths', $order_subscription_lengths);
         update_post_meta($order_id, '_order_subscription_trial_lengths', $order_subscription_trial_lengths);
         // Store sign-up fee details
         foreach (WC_Subscriptions_Cart::get_sign_up_fee_fields() as $field_name) {
             update_post_meta($order_id, "_{$field_name}", $woocommerce->cart->{$field_name});
         }
         // Prepare sign up fee taxes to store in same format as order taxes
         $sign_up_fee_taxes = array();
         foreach (array_keys($woocommerce->cart->sign_up_fee_taxes) as $key) {
             $is_compound = $woocommerce->cart->tax->is_compound($key) ? 1 : 0;
             $sign_up_fee_taxes[] = array('label' => $woocommerce->cart->tax->get_rate_label($key), 'compound' => $is_compound, 'cart_tax' => number_format($woocommerce->cart->sign_up_fee_taxes[$key], 2, '.', ''));
         }
         update_post_meta($order_id, '_sign_up_fee_taxes', $sign_up_fee_taxes);
     }
 }
 /**
  * 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);
 }
 /**
  * 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;
 }
 /**
  * Returns the recurring price component of a subscription product.
  *
  * @param  WC_Product $product
  * @return string
  */
 public static function get_recurring_price_html_component($product)
 {
     $sync_date = $product->subscription_payment_sync_date;
     $product->subscription_payment_sync_date = 0;
     $sub_price_html = WC_Subscriptions_Product::get_price_string($product, array('price' => '%s', 'sign_up_fee' => false));
     $product->subscription_payment_sync_date = $sync_date;
     return $sub_price_html;
 }
 /**
  * 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;
 }
 /**
  * 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]));
         }
     }
 }
 /**
  * Return the sign-up fee for this product
  *
  * @return string
  */
 public function get_sign_up_fee()
 {
     return WC_Subscriptions_Product::get_sign_up_fee($this);
 }
 /**
  * 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;
 }
 /**
  * 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']));
             }
         }
     }
 }
 /**
  * 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;
 }
 /**
  * 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;
 }
 /**
  * Add subscription price string info to products with attached subscription schemes.
  *
  * @param  string     $price
  * @param  WC_Product $product
  * @return string
  */
 public static function filter_price_html($price, $product)
 {
     if (self::$bypass_price_html_filter) {
         return $price;
     }
     $subscription_schemes = WCS_ATT_Schemes::get_product_subscription_schemes($product);
     $has_product_level_schemes = empty($subscription_schemes) ? false : true;
     if ($has_product_level_schemes) {
         $force_subscription = get_post_meta($product->id, '_wcsatt_force_subscription', true);
         if ($force_subscription === 'yes') {
             $subscription_scheme = current($subscription_schemes);
             $overridden_prices = WCS_ATT_Schemes::get_subscription_scheme_prices($product, $subscription_scheme);
             $suffix = '';
             $_cloned = clone $product;
             $_cloned->is_converted_to_sub = 'yes';
             $_cloned->subscription_period = $subscription_scheme['subscription_period'];
             $_cloned->subscription_period_interval = $subscription_scheme['subscription_period_interval'];
             $_cloned->subscription_length = $subscription_scheme['subscription_length'];
             if (!empty($overridden_prices)) {
                 $_cloned->regular_price = $overridden_prices['regular_price'];
                 $_cloned->price = $overridden_prices['price'];
                 $_cloned->sale_price = $overridden_prices['sale_price'];
                 $_cloned->subscription_price = $overridden_prices['price'];
             }
             self::$bypass_price_html_filter = true;
             $price = $_cloned->get_price_html();
             self::$bypass_price_html_filter = false;
             $price = WC_Subscriptions_Product::get_price_string($_cloned, array('price' => $price));
             if (count($subscription_schemes) > 1 && false === strpos($price, $_cloned->get_price_html_from_text())) {
                 $price = sprintf(_x('%1$s%2$s', 'Price range: from', WCS_ATT::TEXT_DOMAIN), $_cloned->get_price_html_from_text(), $price);
             }
         } else {
             $price_overrides_exist = WCS_ATT_Schemes::subscription_price_overrides_exist($subscription_schemes);
             $lowest_scheme_price = $product->price;
             $lowest_scheme_sale_price = $product->sale_price;
             $lowest_scheme_regular_price = $product->regular_price;
             $lowest_scheme_price_html = '';
             $from_price = '';
             if ($price_overrides_exist) {
                 foreach ($subscription_schemes as $subscription_scheme) {
                     $overridden_prices = WCS_ATT_Schemes::get_subscription_scheme_prices($product, $subscription_scheme);
                     if (!empty($overridden_prices)) {
                         if ($overridden_prices['price'] < $lowest_scheme_price) {
                             $lowest_scheme_price = $overridden_prices['price'];
                             $lowest_scheme_sale_price = $overridden_prices['sale_price'];
                             $lowest_scheme_regular_price = $overridden_prices['regular_price'];
                         }
                     }
                 }
                 if ($lowest_scheme_price < $product->price) {
                     $_cloned = clone $product;
                     $_cloned->is_converted_to_sub = 'yes';
                     $_cloned->subscription_period = $subscription_scheme['subscription_period'];
                     $_cloned->subscription_period_interval = $subscription_scheme['subscription_period_interval'];
                     $_cloned->subscription_length = $subscription_scheme['subscription_length'];
                     $_cloned->price = $lowest_scheme_price;
                     $_cloned->sale_price = $lowest_scheme_price;
                     $_cloned->regular_price = $lowest_scheme_regular_price;
                     self::$bypass_price_html_filter = true;
                     $lowest_scheme_price_html = $_cloned->get_price_html();
                     $lowest_scheme_price_html = WC_Subscriptions_Product::get_price_string($_cloned, array('price' => $lowest_scheme_price_html));
                     self::$bypass_price_html_filter = false;
                     if (count($subscription_schemes) > 1) {
                         $from_price = sprintf(_x('%1$s%2$s', 'Price range: from', WCS_ATT::TEXT_DOMAIN), _x('<span class="from">from </span>', 'min-price: 1 plan available', WCS_ATT::TEXT_DOMAIN), $lowest_scheme_price_html);
                     } else {
                         $from_price = sprintf(_x('%1$s%2$s', 'Price range: from', WCS_ATT::TEXT_DOMAIN), _x('<span class="for">for </span>', 'min-price: multiple plans available', WCS_ATT::TEXT_DOMAIN), $lowest_scheme_price_html);
                     }
                 }
             }
             if ($price_overrides_exist) {
                 $suffix = ' <small class="wcsatt-sub-options">' . sprintf(_n('&ndash; or subscribe %s', '&ndash; or subscribe %s', count($subscription_schemes), WCS_ATT::TEXT_DOMAIN), $from_price) . '</small>';
             } else {
                 $suffix = ' <small class="wcsatt-sub-options">' . sprintf(_n('&ndash; subscription plan available', '&ndash; subscription plans available', count($subscription_schemes), WCS_ATT::TEXT_DOMAIN), $from_price) . '</small>';
             }
             $price = sprintf(__('%1$s%2$s', 'price html sub options suffix', WCS_ATT::TEXT_DOMAIN), $price, $suffix);
         }
     }
     return $price;
 }
 /**
  * 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);
 }
 /**
  * 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;
 }
 /**
  * Adjust the product ID that grants access to a membership plan on purchase
  *
  * Subscription products take priority over all other products
  *
  * @since 1.0.0
  * @param int $product_id Product ID
  * @param array $access_granting_product_ids Array of product IDs
  * @param WC_Memberships_Membership_Plan $plan
  * @return int Product ID, adjusted if necessary
  */
 public function adjust_access_granting_product_id($product_id, $access_granting_product_ids, WC_Memberships_Membership_Plan $plan)
 {
     // Check if more than one products may grant access, and if the plan even
     // allows access while subscription is active
     if (count($access_granting_product_ids) > 1 && $this->plan_grants_access_while_subscription_active($plan->get_id())) {
         // First, find all subscription products that grant access
         $access_granting_subscription_product_ids = array();
         foreach ($access_granting_product_ids as $_product_id) {
             $product = wc_get_product($_product_id);
             if ($product->is_type(array('subscription', 'subscription_variation', 'variable-subscription'))) {
                 $access_granting_subscription_product_ids[] = $product->id;
             }
         }
         // If there are any, decide which one actually gets to grant access
         if (!empty($access_granting_subscription_product_ids)) {
             // Only one subscription grants access, short-circuit it as the winner
             if (count($access_granting_subscription_product_ids) == 1) {
                 $product_id = $access_granting_subscription_product_ids[0];
             } else {
                 $longest_expiration_date = 0;
                 foreach ($access_granting_subscription_product_ids as $_subscription_product_id) {
                     $expiration_date = WC_Subscriptions_Product::get_expiration_date($_subscription_product_id);
                     // No expiration date? Ladies and gentlemen - we've got a winner!
                     if (!$expiration_date) {
                         $product_id = $_subscription_product_id;
                         break;
                     }
                     // This one beats the previous sub! Out of the way, you sub-optimal sucker, you!
                     if (strtotime($expiration_date) > $longest_expiration_date) {
                         $product_id = $_subscription_product_id;
                         $longest_expiration_date = strtotime($expiration_date);
                     }
                 }
             }
         }
     }
     return $product_id;
 }
 /**
  * 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;
 }
 /**
  * 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;
 }
 /**
  * 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;
 }
Exemplo n.º 19
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();
 }
 /**
  * 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();
 }
 /**
  * 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);
 }
 /**
  * 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);
                 }
             }
         }
     }
 }
Exemplo n.º 23
0
 private function processSubscriptions()
 {
     global $wpdb;
     // check wether subscriptions addon is activated
     if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($this->order)) {
         $products = $this->order->get_items();
         foreach ($products as $product) {
             if (is_array($product) && isset($product['product_id']) && intval($product['product_id']) > 0 && isset($product['subscription_period']) && $product['subscription_period'] != '') {
                 // product is a subscription?
                 $woo_sub_key = WC_Subscriptions_Manager::get_subscription_key($this->order_id, $product['product_id']);
                 // required vars
                 $amount = floatval(WC_Subscriptions_Order::get_recurring_total($this->order)) * 100;
                 $currency = get_woocommerce_currency();
                 $interval = intval($product['subscription_interval']);
                 $period = strtoupper($product['subscription_period']);
                 $length = strtoupper($product['subscription_length']);
                 if ($length > 0) {
                     $periodOfValidity = $length . ' ' . $period;
                 } else {
                     $periodOfValidity = false;
                 }
                 $trial_end = strtotime(WC_Subscriptions_Product::get_trial_expiration_date($product['product_id'], get_gmt_from_date($this->order->order_date)));
                 if ($trial_end === false) {
                     $trial_time = 0;
                 } else {
                     $datediff = $trial_end - time();
                     $trial_time = ceil($datediff / (60 * 60 * 24));
                 }
                 // md5 name
                 $woo_sub_md5 = md5($amount . $currency . $interval . $trial_time);
                 // get offer
                 $name = 'woo_' . $product['product_id'] . '_' . $woo_sub_md5;
                 $offer = $this->subscriptions->offerGetDetailByName($name);
                 // check wether offer exists in paymill
                 if ($offer === false) {
                     // offer does not exist in paymill yet, create it
                     $params = array('amount' => $amount, 'currency' => $currency, 'interval' => $interval . ' ' . $period, 'name' => $name, 'trial_period_days' => intval($trial_time));
                     $offer = $this->subscriptions->offerCreate($params);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                 }
                 // create user subscription
                 $user_sub = $this->subscriptions->create($this->clientClass->getCurrentClientID(), $offer, $this->paymentClass->getPaymentID(), isset($_POST['paymill_delivery_date']) ? $_POST['paymill_delivery_date'] : false, $periodOfValidity);
                 if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                     //maybe offer cache is outdated, recache and try again
                     $GLOBALS['paymill_loader']->paymill_errors->reset();
                     // reset error status
                     $this->subscriptions->offerGetList(true);
                     $params = array('amount' => $amount, 'currency' => $currency, 'interval' => $interval . ' ' . $period, 'name' => $name, 'trial_period_days' => intval($trial_time));
                     $offer = $this->subscriptions->offerCreate($params);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                     $user_sub = $this->subscriptions->create($this->clientClass->getCurrentClientID(), $offer, $this->paymentClass->getPaymentID(), isset($_POST['paymill_delivery_date']) ? $_POST['paymill_delivery_date'] : false, $periodOfValidity);
                     if ($GLOBALS['paymill_loader']->paymill_errors->status()) {
                         $GLOBALS['paymill_loader']->paymill_errors->getErrors();
                         return false;
                     }
                 }
                 $wpdb->query($wpdb->prepare('INSERT INTO ' . $wpdb->prefix . 'paymill_subscriptions (paymill_sub_id, woo_user_id, woo_offer_id) VALUES (%s, %s, %s)', array($user_sub, get_current_user_id(), $woo_sub_key)));
                 // subscription successful
                 do_action('paymill_woocommerce_subscription_created', array('product_id' => $product['product_id'], 'offer_id' => $offer));
                 return true;
             }
         }
     } else {
         return true;
     }
 }
 /**
  * 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>';
 }
     * @since 1.0
     * @deprecated 1.5.18
     */
    public static function get_price_html($price, $product)
    {
        _deprecated_function(__METHOD__, '1.5.18', __CLASS__ . '::get_price_string()');
        if (self::is_subscription($product)) {
            $price = self::get_price_string($product, array('price' => $price));
        }
        return $price;
    }
    /**
     * Deprecated in favour of native get_price_html() method on the Subscription Product classes (e.g. WC_Product_Subscription)
     *
     * Set the subscription string for products which have a $0 recurring fee, but a sign-up fee
     *
     * @since 1.3.4
     * @deprecated 1.5.18
     */
    public static function get_free_price_html($price, $product)
    {
        _deprecated_function(__METHOD__, '1.5.18', __CLASS__ . '::get_price_string()');
        // Check if it has a sign-up fee (we already know it has no recurring fee)
        if (self::is_subscription($product) && self::get_sign_up_fee($product) > 0) {
            $price = self::get_price_string($product, array('price' => $price));
        }
        return $price;
    }
}
WC_Subscriptions_Product::init();
 /**
  * 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]));
         }
     }
 }
 /**
  * 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;
             }
         }
     }
 }
 /**
  * Checks if the store manager has requested the current product be limited to one purchase
  * per customer, and if so, checks whether the customer already has an active subscription to
  * the product.
  *
  * @access public
  * @return bool
  */
 function is_purchasable()
 {
     $purchasable = parent::is_purchasable();
     if (true === $purchasable && false === WC_Subscriptions_Product::is_purchasable($purchasable, $this)) {
         $purchasable = false;
     }
     return apply_filters('woocommerce_subscription_is_purchasable', $purchasable, $this);
 }
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);
 }
 /**
  * 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);
 }