/** * Check whether the cart needs payment even if the order total is $0 * * @param bool $needs_payment The existing flag for whether the cart needs payment or not. * @param WC_Cart $cart The WooCommerce cart object. * @return bool */ public static function cart_needs_payment($needs_payment, $cart) { if (false === $needs_payment && self::cart_contains_subscription() && $cart->total == 0 && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) { $recurring_total = 0; $is_one_period = true; $is_synced = false; foreach (WC()->cart->recurring_carts as $cart) { $recurring_total += $cart->total; $cart_length = wcs_cart_pluck($cart, 'subscription_length'); if (0 == $cart_length || wcs_cart_pluck($cart, 'subscription_period_interval') != $cart_length) { $is_one_period = false; } $is_synced = $is_synced || false != WC_Subscriptions_Synchroniser::cart_contains_synced_subscription($cart) ? true : false; } $has_trial = self::cart_contains_free_trial(); if ($recurring_total > 0 && (false === $is_one_period || true === $has_trial || false !== $is_synced && false == WC_Subscriptions_Synchroniser::is_today(WC_Subscriptions_Synchroniser::calculate_first_payment_date($is_synced['data'], 'timestamp')))) { $needs_payment = true; } } return $needs_payment; }
/** * Return a formatted price string for a given cart object * * @access public * @return void */ function wcs_cart_price_string($recurring_amount, $cart) { return wcs_price_string(apply_filters('woocommerce_cart_subscription_string_details', array('recurring_amount' => $recurring_amount, 'subscription_interval' => wcs_cart_pluck($cart, 'subscription_period_interval'), 'subscription_period' => wcs_cart_pluck($cart, 'subscription_period', ''), 'subscription_length' => wcs_cart_pluck($cart, 'subscription_length')))); }
/** * Create a new subscription from a cart item on checkout. * * The function doesn't validate whether the cart item is a subscription product, meaning it can be used for any cart item, * but the item will need a `subscription_period` and `subscription_period_interval` value set on it, at a minimum. * * @param WC_Order $order * @param WC_Cart $cart * @since 2.0 */ public static function create_subscription($order, $cart) { global $wpdb; try { // Start transaction if available $wpdb->query('START TRANSACTION'); // Set the recurring line totals on the subscription $variation_id = wcs_cart_pluck($cart, 'variation_id'); $product_id = empty($variation_id) ? wcs_cart_pluck($cart, 'product_id') : $variation_id; // We need to use the $order->order_date value because the post_date_gmt isn't always set $order_date_gmt = get_gmt_from_date($order->order_date); $subscription = wcs_create_subscription(array('start_date' => $cart->start_date, 'order_id' => $order->id, 'customer_id' => $order->get_user_id(), 'billing_period' => wcs_cart_pluck($cart, 'subscription_period'), 'billing_interval' => wcs_cart_pluck($cart, 'subscription_period_interval'), 'customer_note' => $order->customer_note)); if (is_wp_error($subscription)) { throw new Exception($subscription->get_error_message()); } // Set the subscription's billing and shipping address $subscription = wcs_copy_order_address($order, $subscription); $subscription->update_dates(array('trial_end' => $cart->trial_end_date, 'next_payment' => $cart->next_payment_date, 'end' => $cart->end_date)); // Store trial period for PayPal if (wcs_cart_pluck($cart, 'subscription_trial_length') > 0) { update_post_meta($subscription->id, '_trial_period', wcs_cart_pluck($cart, 'subscription_trial_period')); } // Set the payment method on the subscription $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); if ($cart->needs_payment() && isset($available_gateways[$order->payment_method])) { $subscription->set_payment_method($available_gateways[$order->payment_method]); } if (!$cart->needs_payment() || 'yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) { $subscription->update_manual('true'); } elseif (!isset($available_gateways[$order->payment_method]) || !$available_gateways[$order->payment_method]->supports('subscriptions')) { $subscription->update_manual('true'); } wcs_copy_order_meta($order, $subscription, 'subscription'); // Store the line items foreach ($cart->get_cart() as $cart_item_key => $cart_item) { $item_id = self::add_cart_item($subscription, $cart_item, $cart_item_key); } // Store fees (although no fees recur by default, extensions may add them) foreach ($cart->get_fees() as $fee_key => $fee) { $item_id = $subscription->add_fee($fee); if (!$item_id) { // translators: placeholder is an internal error number throw new Exception(sprintf(__('Error %d: Unable to create subscription. Please try again.', 'woocommerce-subscriptions'), 403)); } // Allow plugins to add order item meta to fees do_action('woocommerce_add_order_fee_meta', $order->id, $item_id, $fee, $fee_key); } self::add_shipping($subscription, $cart); // Store tax rows foreach (array_keys($cart->taxes + $cart->shipping_taxes) as $tax_rate_id) { if ($tax_rate_id && !$subscription->add_tax($tax_rate_id, $cart->get_tax_amount($tax_rate_id), $cart->get_shipping_tax_amount($tax_rate_id)) && apply_filters('woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated') !== $tax_rate_id) { // translators: placeholder is an internal error number throw new Exception(sprintf(__('Error %d: Unable to add tax to subscription. Please try again.', 'woocommerce-subscriptions'), 405)); } } // Store coupons foreach ($cart->get_coupons() as $code => $coupon) { if (!$subscription->add_coupon($code, $cart->get_coupon_discount_amount($code), $cart->get_coupon_discount_tax_amount($code))) { // translators: placeholder is an internal error number throw new Exception(sprintf(__('Error %d: Unable to create order. Please try again.', 'woocommerce-subscriptions'), 406)); } } // Set the recurring totals on the subscription $subscription->set_total($cart->shipping_total, 'shipping'); $subscription->set_total($cart->get_cart_discount_total(), 'cart_discount'); $subscription->set_total($cart->get_cart_discount_tax_total(), 'cart_discount_tax'); $subscription->set_total($cart->tax_total, 'tax'); $subscription->set_total($cart->shipping_tax_total, 'shipping_tax'); $subscription->set_total($cart->total); // If we got here, the subscription was created without problems $wpdb->query('COMMIT'); } catch (Exception $e) { // There was an error adding the subscription $wpdb->query('ROLLBACK'); return new WP_Error('checkout-error', $e->getMessage()); } return $subscription; }