/** * 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); } }
/** * Removes a couple of notifications that are less relevant for Subscription orders. * * @since 1.0 */ public static function maybe_remove_customer_processing_order($order_id) { if (WC_Subscriptions_Order::order_contains_subscription($order_id)) { remove_action('woocommerce_order_status_pending_to_processing_notification', array(self::$woocommerce_email, 'customer_processing_order')); remove_action('woocommerce_order_status_pending_to_on-hold_notification', array(self::$woocommerce_email, 'customer_processing_order')); } }
/** * 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, $posted) { global $woocommerce; if (WC_Subscriptions_Order::order_contains_subscription($order_id)) { // This works because the 'new_order_item' runs before the 'woocommerce_checkout_update_order_meta' hook // Set the recurring totals so totals display correctly on order page update_post_meta($order_id, '_order_recurring_discount_cart', WC_Subscriptions_Cart::get_recurring_discount_cart()); update_post_meta($order_id, '_order_recurring_discount_total', WC_Subscriptions_Cart::get_recurring_discount_total()); update_post_meta($order_id, '_order_recurring_shipping_tax_total', WC_Subscriptions_Cart::get_recurring_shipping_tax_total()); update_post_meta($order_id, '_order_recurring_tax_total', WC_Subscriptions_Cart::get_recurring_total_tax()); update_post_meta($order_id, '_order_recurring_total', WC_Subscriptions_Cart::get_recurring_total()); // Get recurring taxes into same format as _order_taxes $order_recurring_taxes = array(); foreach (WC_Subscriptions_Cart::get_recurring_taxes() as $tax_key => $tax_amount) { $is_compound = $woocommerce->cart->tax->is_compound($tax_key) ? 1 : 0; if (isset($woocommerce->cart->taxes[$tax_key])) { $cart_tax = $tax_amount; $shipping_tax = 0; } else { $cart_tax = 0; $shipping_tax = $tax_amount; } $order_recurring_taxes[] = array('label' => $woocommerce->cart->tax->get_rate_label($tax_key), 'compound' => $is_compound, 'cart_tax' => woocommerce_format_total($cart_tax), 'shipping_tax' => woocommerce_format_total($shipping_tax)); } update_post_meta($order_id, '_order_recurring_taxes', $order_recurring_taxes); $payment_gateways = $woocommerce->payment_gateways->payment_gateways(); if (!$payment_gateways[$posted['payment_method']]->supports('subscriptions')) { update_post_meta($order_id, '_wcs_requires_manual_renewal', 'true'); } } }
/** * Process the payment */ function process_payment($order_id) { global $woocommerce; if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($order_id)) { $order = new WC_Order($order_id); $stripe_token = isset($_POST['stripe_token']) ? woocommerce_clean($_POST['stripe_token']) : ''; // Use Stripe CURL API for payment try { $post_data = array(); $customer_id = 0; // Check if paying via customer ID if (isset($_POST['stripe_customer_id']) && $_POST['stripe_customer_id'] !== 'new' && is_user_logged_in()) { $customer_ids = get_user_meta(get_current_user_id(), '_stripe_customer_id', false); if (isset($customer_ids[$_POST['stripe_customer_id']]['customer_id'])) { $customer_id = $customer_ids[$_POST['stripe_customer_id']]['customer_id']; } else { throw new Exception(__('Invalid card.', 'wc_stripe')); } } elseif (empty($stripe_token)) { throw new Exception(__('Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'wc_stripe')); } if (method_exists('WC_Subscriptions_Order', 'get_total_initial_payment')) { $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order); } else { $initial_payment = WC_Subscriptions_Order::get_sign_up_fee($order) + WC_Subscriptions_Order::get_price_per_period($order); } $customer_response = $this->add_customer_to_order($order, $customer_id, $stripe_token); if ($initial_payment > 0) { $payment_response = $this->process_subscription_payment($order, $initial_payment); } if (is_wp_error($customer_response)) { throw new Exception($customer_response->get_error_message()); } else { if (isset($payment_response) && is_wp_error($payment_response)) { throw new Exception($payment_response->get_error_message()); } else { // Payment complete $order->payment_complete(); // Remove cart $woocommerce->cart->empty_cart(); // Activate subscriptions WC_Subscriptions_Manager::activate_subscriptions_for_order($order); // Store token if ($stripe_token) { update_post_meta($order->id, '_stripe_token', $stripe_token); } // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } } catch (Exception $e) { $woocommerce->add_error(__('Error:', 'wc_stripe') . ' "' . $e->getMessage() . '"'); return; } } else { return parent::process_payment($order_id); } }
/** * Get the string key for a subscription used in Subscriptions prior to 2.0. * * Previously, a subscription key was made up of the ID of the order used to purchase the subscription, and * the product to which the subscription relates; however, in Subscriptions 2.0, subscriptions can actually * relate to multiple products (because they can contain multiple line items) and they also no longer need * to have an original order associated with them, to make manually adding subscriptions more accurate. * * Therefore, although the return value of this method is a string matching the key form used inSubscriptions * prior to 2.0, the actual value represented is not a perfect analogue. Specifically, * - if the subscription contains more than one product, only the ID of the first line item will be used in the ID * - if the subscription does not contain any products, the key still be missing that component of the * - if the subscription does not have an initial order, then the order ID used will be the WC_Subscription object's ID * * @param WC_Subscription $subscription An instance of WC_Subscription * @return string $subscription_key A subscription key in the deprecated form previously created by @see self::get_subscription_key() * @since 2.0 */ function wcs_get_old_subscription_key(WC_Subscription $subscription) { // Get an ID to use as the order ID $order_id = isset($subscription->order->id) ? $subscription->order->id : $subscription->id; // Get an ID to use as the product ID $subscription_items = $subscription->get_items(); $first_item = reset($subscription_items); return $order_id . '_' . WC_Subscriptions_Order::get_items_product_id($first_item); }
/** * Process the payment * * @param int $order_id * @return array */ public function process_payment($order_id, $retry = true) { // Processing subscription if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($order_id)) { return $this->process_subscription($order_id, $retry); // Processing pre-order or standard ordre } else { return parent::process_payment($order_id, $retry); } }
/** * For versions of WooCommerce prior to the existence of the woocommerce_available_gateways, * hide available gateways with JavaScript. * * @since 1.0 */ public static function gateway_scheduled_subscription_payment($user_id, $subscription_key) { $subscription = WC_Subscriptions_Manager::get_users_subscription($user_id, $subscription_key); $order = new WC_Order($subscription['order_id']); $amount_to_charge = WC_Subscriptions_Order::get_price_per_period($order, $subscription['product_id']); $outstanding_payments = WC_Subscriptions_Order::get_outstanding_balance($order, $subscription['product_id']); if ($outstanding_payments > 0) { $amount_to_charge += $outstanding_payments; } do_action('scheduled_subscription_payment_' . $order->payment_method, $amount_to_charge, $order, $subscription['product_id']); }
/** * Change the status of a subscription and show a notice to the * user to say when the next payment will now be made on. * * @since 1.0.0 * @access public * @static * @param $subscription * @param $order_id * @param $product_id * @uses WC_Subscriptions::add_notice */ public static function change_users_subscription($subscription, $order_id, $product_id) { $subscription = !is_object($subscription) ? wcs_get_subscription($subscription) : $subscription; $current_next_subscription_payment = WC_Subscriptions_Order::get_next_payment_date($order_id, $product_id, $from_date = ''); // Get the date of the current next subscription. $next_subscription_payment = WC_Subscriptions_Order::calculate_next_payment_date($order_id, $product_id, $type = 'mysql', $current_next_subscription_payment); WCSO_Subscriptions_Order::update_next_payment($order_id, $next_subscription_payment); // Update the next payment on the subscriptions order. $subscription->add_order_note(__('Subscription was skipped by the subscriber from their subscription page.', 'woocommerce-skip-one')); // translators: placeholder is next subscription payment WC_Subscriptions::add_notice(sprintf(__('You next payment subscription will now be on the %s.', 'woocommerce-skip-one'), $next_subscription_payment), 'success'); }
public function init() { global $wpdb; $subscriptions_meta_key = $wpdb->get_blog_prefix() . 'woocommerce_subscriptions'; $order_items_table = $wpdb->get_blog_prefix() . 'woocommerce_order_items'; $order_item_meta_table = $wpdb->get_blog_prefix() . 'woocommerce_order_itemmeta'; // Get the IDs of all users who have a subscription $users_to_upgrade = get_users(array('meta_key' => $subscriptions_meta_key, 'fields' => 'ID', 'orderby' => 'ID')); $users_to_upgrade = array_filter($users_to_upgrade, __CLASS__ . '::is_user_upgraded'); foreach ($users_to_upgrade as $user_to_upgrade) { // Can't use WC_Subscriptions_Manager::get_users_subscriptions() because it relies on the new structure $users_old_subscriptions = get_user_option($subscriptions_meta_key, $user_to_upgrade); foreach ($users_old_subscriptions as $subscription_key => $subscription) { if (!isset($subscription['order_id'])) { // Subscription created incorrectly with v1.1.2 continue; } $order_item_id = WC_Subscriptions_Order::get_item_id_by_subscription_key($subscription_key); if (empty($order_item_id)) { // Subscription created incorrectly with v1.1.2 continue; } if (!isset($subscription['trial_expiry_date'])) { $subscription['trial_expiry_date'] = ''; } // Set defaults $failed_payments = isset($subscription['failed_payments']) ? $subscription['failed_payments'] : 0; $completed_payments = isset($subscription['completed_payments']) ? $subscription['completed_payments'] : array(); $suspension_count = isset($subscription['suspension_count']) ? $subscription['suspension_count'] : 0; $trial_expiry_date = isset($subscription['trial_expiry_date']) ? $subscription['trial_expiry_date'] : ''; $wpdb->query($wpdb->prepare("INSERT INTO {$order_item_meta_table} (order_item_id, meta_key, meta_value)\n\t\t\t\t\t\tVALUES\n\t\t\t\t\t\t(%d,%s,%s),\n\t\t\t\t\t\t(%d,%s,%s),\n\t\t\t\t\t\t(%d,%s,%s),\n\t\t\t\t\t\t(%d,%s,%s),\n\t\t\t\t\t\t(%d,%s,%s),\n\t\t\t\t\t\t(%d,%s,%s),\n\t\t\t\t\t\t(%d,%s,%s),\n\t\t\t\t\t\t(%d,%s,%s)", $order_item_id, '_subscription_status', $subscription['status'], $order_item_id, '_subscription_start_date', $subscription['start_date'], $order_item_id, '_subscription_expiry_date', $subscription['expiry_date'], $order_item_id, '_subscription_end_date', $subscription['end_date'], $order_item_id, '_subscription_trial_expiry_date', $trial_expiry_date, $order_item_id, '_subscription_failed_payments', $failed_payments, $order_item_id, '_subscription_completed_payments', serialize($completed_payments), $order_item_id, '_subscription_suspension_count', $suspension_count)); } update_option('wcs_1_4_last_upgraded_user_id', $user_to_upgrade); self::$last_upgraded_user_id = $user_to_upgrade; } // Add an underscore prefix to usermeta key to deprecate, but not delete, subscriptions in user meta $wpdb->update($wpdb->usermeta, array('meta_key' => '_' . $subscriptions_meta_key), array('meta_key' => $subscriptions_meta_key)); // Now set the recurring shipping & payment method on all subscription orders $wpdb->query("INSERT INTO {$wpdb->postmeta} (`post_id`, `meta_key`, `meta_value`)\n\t\t\tSELECT `post_id`, CONCAT('_recurring',`meta_key`), `meta_value`\n\t\t\tFROM {$wpdb->postmeta}\n\t\t\tWHERE `meta_key` IN ('_shipping_method','_shipping_method_title','_payment_method','_payment_method_title')\n\t\t\tAND `post_id` IN (\n\t\t\t\tSELECT `post_id` FROM {$wpdb->postmeta} WHERE `meta_key` = '_order_recurring_total'\n\t\t\t)"); // Set the recurring shipping total on all subscription orders $wpdb->query("INSERT INTO {$wpdb->postmeta} (`post_id`, `meta_key`, `meta_value`)\n\t\t\tSELECT `post_id`, '_order_recurring_shipping_total', `meta_value`\n\t\t\tFROM {$wpdb->postmeta}\n\t\t\tWHERE `meta_key` = '_order_shipping'\n\t\t\tAND `post_id` IN (\n\t\t\t\tSELECT `post_id` FROM {$wpdb->postmeta} WHERE `meta_key` = '_order_recurring_total'\n\t\t\t)"); // Get the ID of all orders for a subscription with a free trial and no sign-up fee $order_ids = $wpdb->get_col("SELECT order_items.order_id FROM {$order_items_table} AS order_items\n\t\t\t\tLEFT JOIN {$order_item_meta_table} AS itemmeta USING (order_item_id)\n\t\t\t\tLEFT JOIN {$order_item_meta_table} AS itemmeta2 USING (order_item_id)\n\t\t\tWHERE itemmeta.meta_key = '_subscription_trial_length'\n\t\t\tAND itemmeta.meta_value > 0\n\t\t\tAND itemmeta2.meta_key = '_subscription_sign_up_fee'\n\t\t\tAND itemmeta2.meta_value > 0"); $order_ids = implode(',', array_map('absint', array_unique($order_ids))); // Now set the order totals to $0 (can't use $wpdb->update as it only allows joining WHERE clauses with AND) if (!empty($order_ids)) { $wpdb->query("UPDATE {$wpdb->postmeta}\n\t\t\t\tSET `meta_value` = 0\n\t\t\t\tWHERE `meta_key` IN ( '_order_total', '_order_tax', '_order_shipping_tax', '_order_shipping', '_order_discount', '_cart_discount' )\n\t\t\t\tAND `post_id` IN ( {$order_ids} )"); // Now set the line totals to $0 $wpdb->query("UPDATE {$order_item_meta_table}\n\t\t\t\t SET `meta_value` = 0\n\t\t\t\t WHERE `meta_key` IN ( '_line_subtotal', '_line_subtotal_tax', '_line_total', '_line_tax', 'tax_amount', 'shipping_tax_amount' )\n\t\t\t\t AND `order_item_id` IN (\n\t\t\t\t\tSELECT `order_item_id` FROM {$order_items_table}\n\t\t\t\t\tWHERE `order_item_type` IN ('tax','line_item')\n\t\t\t\t\tAND `order_id` IN ( {$order_ids} )\n\t\t\t\t)"); } update_option('wcs_1_4_upgraded_order_ids', explode(',', $order_ids)); }
/** * Process the subscription. * * @param WC_Order $order * * @return array */ protected function process_subscription($order_id) { try { $order = new WC_Order($order_id); if (!isset($_POST['iugu_token'])) { if ('yes' == $this->debug) { $this->log->add($this->id, 'Error doing the subscription for order ' . $order->get_order_number() . ': Missing the "iugu_token".'); } $error_msg = __('Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'iugu-woocommerce'); throw new Exception($error_msg); } // Create customer payment method. $payment_method_id = $this->api->create_customer_payment_method($order, $_POST['iugu_token']); if (!$payment_method_id) { if ('yes' == $this->debug) { $this->log->add($this->id, 'Invalid customer method ID for order ' . $order->get_order_number()); } $error_msg = __('An error occurred while trying to save your data. Please contact us for get help.', 'iugu-woocommerce'); throw new Exception($error_msg); } // Save the payment method ID in order data. update_post_meta($order->id, '_iugu_customer_payment_method_id', $payment_method_id); // Try to do an initial payment. $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order); if ($initial_payment > 0) { $payment_response = $this->process_subscription_payment($order, $initial_payment); } if (isset($payment_response) && is_wp_error($payment_response)) { throw new Exception($payment_response->get_error_message()); } else { // Remove cart $this->api->empty_card(); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } catch (Exception $e) { $this->api->add_error('<strong>' . esc_attr($this->title) . '</strong>: ' . $e->getMessage()); return array('result' => 'fail', 'redirect' => ''); } }
/** * Process the subscription. * * @param WC_Order $order * * @return array */ protected function process_subscription($order_id) { try { $order = new WC_Order($order_id); // Try to do an initial payment. $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order); if ($initial_payment > 0) { $payment_response = $this->process_subscription_payment($order, $initial_payment); } if (isset($payment_response) && is_wp_error($payment_response)) { throw new Exception($payment_response->get_error_message()); } else { // Remove cart $this->api->empty_card(); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } catch (Exception $e) { $this->api->add_error('<strong>' . esc_attr($this->title) . '</strong>: ' . $e->getMessage()); return array('result' => 'fail', 'redirect' => ''); } }
public function request_access_code($order, $method = 'ProcessPayment', $trx_type = 'Purchase') { $customer_ip = get_post_meta($order->id, '_customer_ip_address', true); // Check if order is for a subscription, if it is check for fee and charge that if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($order->id)) { if (0 == WC_Subscriptions_Order::get_total_initial_payment($order)) { $method = 'CreateTokenCustomer'; } else { $method = 'TokenPayment'; } $trx_type = 'Recurring'; $order_total = WC_Subscriptions_Order::get_total_initial_payment($order) * 100; } else { $order_total = $order->get_total() * 100.0; } // set up request object $request = array('Method' => $method, 'TransactionType' => $trx_type, 'RedirectUrl' => str_replace('https:', 'http:', add_query_arg(array('wc-api' => 'WC_Gateway_EWAY', 'order_id' => $order->id, 'order_key' => $order->order_key, 'sig_key' => md5($order->order_key . 'WOO' . $order->id)), home_url('/'))), 'IPAddress' => $customer_ip, 'DeviceID' => '0b38ae7c3c5b466f8b234a8955f62bdd', 'PartnerID' => '0b38ae7c3c5b466f8b234a8955f62bdd', 'Payment' => array('TotalAmount' => $order_total, 'CurrencyCode' => get_woocommerce_currency(), 'InvoiceDescription' => apply_filters('woocommerce_eway_description', '', $order), 'InvoiceNumber' => ltrim($order->get_order_number(), _x('#', 'hash before order number', 'woocommerce')), 'InvoiceReference' => $order->id), 'Customer' => array('FirstName' => $order->billing_first_name, 'LastName' => $order->billing_last_name, 'CompanyName' => substr($order->billing_company, 0, 50), 'Street1' => $order->billing_address_1, 'Street2' => $order->billing_address_2, 'City' => $order->billing_city, 'State' => $order->billing_state, 'PostalCode' => $order->billing_postcode, 'Country' => $order->billing_country, 'Email' => $order->billing_email, 'Phone' => $order->billing_phone)); // Add customer ID if logged in if (is_user_logged_in()) { $request['Options'][] = array('customerID' => get_current_user_id()); } return $this->perform_request('/CreateAccessCode.json', json_encode($request)); }
/** * Set the subscription prices to be used in calculating totals by @see WC_Subscriptions_Cart::calculate_subscription_totals() * * @since 1.4 */ public static function maybe_set_apporitioned_totals($total) { global $woocommerce; if (false === self::cart_contains_subscription_switch()) { return $total; } // Maybe charge an initial amount to account for upgrading from a cheaper subscription $apportion_recurring_price = get_option(WC_Subscriptions_Admin::$option_prefix . '_apportion_recurring_price', 'no'); $apportion_sign_up_fee = get_option(WC_Subscriptions_Admin::$option_prefix . '_apportion_sign_up_fee', 'no'); $apportion_length = get_option(WC_Subscriptions_Admin::$option_prefix . '_apportion_length', 'no'); foreach ($woocommerce->cart->get_cart() as $cart_item_key => $cart_item) { if (!isset($cart_item['subscription_switch']['subscription_key'])) { continue; } $old_subscription_key = $cart_item['subscription_switch']['subscription_key']; $item_data = $cart_item['data']; $product_id = empty($cart_item['variation_id']) ? $cart_item['product_id'] : $cart_item['variation_id']; $product = get_product($product_id); // Set the date on which the first payment for the new subscription should be charged $woocommerce->cart->cart_contents[$cart_item_key]['subscription_switch']['first_payment_timestamp'] = $cart_item['subscription_switch']['next_payment_timestamp']; $is_virtual_product = 'no' != $item_data->virtual ? true : false; // Add any extra sign up fees required to switch to the new subscription if ('yes' == $apportion_sign_up_fee) { $old_subscription = WC_Subscriptions_Manager::get_subscription($old_subscription_key); $sign_up_fee_due = $product->subscription_sign_up_fee; if (self::order_contains_subscription_switch($old_subscription['order_id'])) { $old_order = new WC_Order($old_subscription['order_id']); $sign_up_fee_paid = $old_order->get_total(); } else { $sign_up_fee_paid = WC_Subscriptions_Order::get_item_sign_up_fee($old_subscription['order_id'], $old_subscription['product_id']); } $woocommerce->cart->cart_contents[$cart_item_key]['data']->subscription_sign_up_fee = max($sign_up_fee_due - $sign_up_fee_paid, 0); } elseif ('no' == $apportion_sign_up_fee) { // $0 the initial sign-up fee $woocommerce->cart->cart_contents[$cart_item_key]['data']->subscription_sign_up_fee = 0; } // Now lets see if we should add an apportioned amount to the sign-up fee (for upgrades) or extend the next payment date (for downgrades) if ('yes' == $apportion_recurring_price || 'virtual' == $apportion_recurring_price && $is_virtual_product) { // Get the current subscription $old_subscription = isset($old_subscription) ? $old_subscription : WC_Subscriptions_Manager::get_subscription($old_subscription_key); // Get the current subscription's original order $old_order = isset($old_order) ? $old_order : new WC_Order($old_subscription['order_id']); // Get the current subscription's last payment date $last_payment_timestamp = WC_Subscriptions_Manager::get_last_payment_date($old_subscription_key, get_current_user_id(), 'timestamp'); $days_since_last_payment = round((gmdate('U') - $last_payment_timestamp) / (60 * 60 * 24)); // Get the current subscription's next payment date $next_payment_timestamp = $cart_item['subscription_switch']['next_payment_timestamp']; $days_until_next_payment = round(($next_payment_timestamp - gmdate('U')) / (60 * 60 * 24)); // Find the number of days between the two $days_in_old_cycle = $days_until_next_payment + $days_since_last_payment; // Find the $price per day for the old subscription's recurring total $old_recurring_total = WC_Subscriptions_Order::get_item_recurring_amount($old_subscription['order_id'], $old_subscription['product_id']); $old_price_per_day = $old_recurring_total / $days_in_old_cycle; // Find the price per day for the new subscription's recurring total // If the subscription uses the same billing interval & cycle as the old subscription, if ($item_data->subscription_period == $old_subscription['period'] && $item_data->subscription_period_interval == $old_subscription['interval']) { $days_in_new_cycle = $days_in_old_cycle; // Use $days_in_old_cycle to make sure they're consistent $new_price_per_day = $product->subscription_price / $days_in_old_cycle; } else { // We need to figure out the price per day for the new subscription based on its billing schedule switch ($item_data->subscription_period) { case 'day': $days_in_new_cycle = $item_data->subscription_period_interval; break; case 'week': $days_in_new_cycle = $item_data->subscription_period_interval * 7; break; case 'month': $days_in_new_cycle = $item_data->subscription_period_interval * 30.4375; // Average days per month over 4 year period break; case 'year': $days_in_new_cycle = $item_data->subscription_period_interval * 365.25; // Average days per year over 4 year period break; } $new_price_per_day = $product->subscription_price / $days_in_new_cycle; } // If the customer is upgrading, we may need to add a gap payment to the sign-up fee or to reduce the pre-paid period (or both) if ($old_price_per_day < $new_price_per_day) { // The new subscription may be more expensive, but it's also on a shorter billing cycle, so reduce the next pre-paid term if ($days_in_old_cycle > $days_in_new_cycle) { // Find out how many days at the new price per day the customer would receive for the total amount already paid // (e.g. if the customer paid $10 / month previously, and was switching to a $5 / week subscription, she has pre-paid 14 days at the new price) $pre_paid_days = 0; do { $pre_paid_days++; $new_total_paid = $pre_paid_days * $new_price_per_day; } while ($new_total_paid < $old_recurring_total); // If the total amount the customer has paid entitles her to more days at the new price than she has received, there is no gap payment, just shorten the pre-paid term the appropriate number of days if ($days_since_last_payment < $pre_paid_days) { $woocommerce->cart->cart_contents[$cart_item_key]['subscription_switch']['first_payment_timestamp'] = $last_payment_timestamp + $pre_paid_days * 60 * 60 * 24; // If the total amount the customer has paid entitles her to the same or less days at the new price then start the new subscription from today } else { $woocommerce->cart->cart_contents[$cart_item_key]['subscription_switch']['first_payment_timestamp'] = 0; } } else { $extra_to_pay = $days_until_next_payment * ($new_price_per_day - $old_price_per_day); $woocommerce->cart->cart_contents[$cart_item_key]['data']->subscription_sign_up_fee += round($extra_to_pay, 2); } $woocommerce->cart->cart_contents[$cart_item_key]['subscription_switch']['upgraded_or_downgraded'] = 'upgraded'; // If the customer is downgrading, we need to extend the next payment date for n more days } elseif ($old_price_per_day > $new_price_per_day && $new_price_per_day > 0) { $old_total_paid = $old_price_per_day * $days_until_next_payment; $new_total_paid = $new_price_per_day; // Find how many more days at the new lower price it takes to exceed the amount already paid for ($days_to_add = 1; $new_total_paid <= $old_total_paid; $days_to_add++) { $new_total_paid = $days_to_add * $new_price_per_day; } $days_to_add -= $days_until_next_payment; $woocommerce->cart->cart_contents[$cart_item_key]['subscription_switch']['first_payment_timestamp'] = $next_payment_timestamp + $days_to_add * 60 * 60 * 24; $woocommerce->cart->cart_contents[$cart_item_key]['subscription_switch']['upgraded_or_downgraded'] = 'downgraded'; } // The old price per day == the new price per day, no need to change anything } // Finally, if we need to make sure the initial total doesn't include any recurring amount, we can by spoofing a free trial if (0 != $woocommerce->cart->cart_contents[$cart_item_key]['subscription_switch']['first_payment_timestamp']) { $woocommerce->cart->cart_contents[$cart_item_key]['data']->subscription_trial_length = 1; } if ('yes' == $apportion_length || 'virtual' == $apportion_length && $is_virtual_product) { // Maybe charge an initial amount to account for upgrading from a cheaper subscription $base_length = WC_Subscriptions_Product::get_length($product_id); $completed_payments = WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($old_subscription_key); $length_remaining = $base_length - $completed_payments; // Default to the base length if more payments have already been made than this subscription requires if ($length_remaining < 0) { $length_remaining = $base_length; } $woocommerce->cart->cart_contents[$cart_item_key]['data']->subscription_length = $length_remaining; } } return $total; }
/** * Callback for the [subscriptions] shortcode that displays subscription names for a particular user. * * @param array $attributes Shortcode attributes. * @return string */ public static function do_subscriptions_shortcode($attributes) { $attributes = wp_parse_args($attributes, array('user_id' => 0, 'status' => 'active')); $status = $attributes['status']; $subscriptions = WC_Subscriptions_Manager::get_users_subscriptions($attributes['user_id']); if (empty($subscriptions)) { return '<ul class="user-subscriptions no-user-subscriptions"> <li>No subscriptions found.</li> </ul>'; } $list = '<ul class="user-subscriptions">'; foreach ($subscriptions as $subscription) { if ($subscription['status'] == $status || $status == 'all') { $list .= sprintf('<li>%s</li>', WC_Subscriptions_Order::get_item_name($subscription['order_id'], $subscription['product_id'])); } } $list .= '</ul>'; return $list; }
/** * If a gateway doesn't manage payment schedules, then we should suspend the subscription until it is paid (i.e. for manual payments * or token gateways like Stripe). If the gateway does manage the scheduling, then we shouldn't suspend the subscription because a * gateway may use batch processing on the time payments are charged and a subscription could end up being incorrectly suspended. * * @param $user_id int The id of the user whose subscription should be put on-hold. * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key() * @since 1.2.5 */ public static function maybe_put_subscription_on_hold($user_id, $subscription_key) { global $woocommerce; $subscription = self::get_users_subscription($user_id, $subscription_key); if (empty($subscription) || $subscription['status'] == 'on-hold') { return false; } $order = new WC_Order($subscription['order_id']); $payment_gateways = $woocommerce->payment_gateways->payment_gateways(); $order_uses_manual_payments = WC_Subscriptions_Order::requires_manual_renewal($order) ? true : false; // If the subscription is using manual payments, the gateway isn't active or it manages scheduled payments if ($order_uses_manual_payments || !isset($payment_gateways[$order->payment_method]) || !$payment_gateways[$order->payment_method]->supports('gateway_scheduled_payments')) { self::put_subscription_on_hold($user_id, $subscription_key); } }
"> <?php } ?> <?php echo WC_Subscriptions_Order::get_item_name($subscription_details['order_id'], $subscription_details['product_id']); ?> <?php if (false !== $product) { ?> </a> <?php } ?> <?php $order_item = WC_Subscriptions_Order::get_item_by_product_id($order, $subscription_details['product_id']); ?> <?php if (WC_Subscriptions::is_woocommerce_pre('2.4')) { ?> <?php $item_meta = new WC_Order_Item_Meta($order_item['item_meta'], $product); ?> <?php } else { ?> <?php $item_meta = new WC_Order_Item_Meta($order_item, $product); ?> <?php }
/** * If requesting a payment method change, replace the woocommerce_pay_shortcode() with a change payment form. * * @since 1.4 */ public static function maybe_replace_pay_shortcode() { global $woocommerce; if (!self::$is_request_to_change_payment) { return; } ob_clean(); do_action('before_woocommerce_pay'); echo '<div class="woocommerce">'; if (!empty(self::$woocommerce_errors)) { foreach (self::$woocommerce_errors as $error) { $woocommerce->add_error($error); } } if (!empty(self::$woocommerce_messages)) { foreach (self::$woocommerce_messages as $message) { $woocommerce->add_message($message); } } $subscription_key = $_GET['change_payment_method']; $subscription = WC_Subscriptions_Manager::get_subscription($subscription_key); if (wp_verify_nonce($_GET['_wpnonce'], __FILE__) === false) { $woocommerce->add_error(__('There was an error with your request. Please try again.', WC_Subscriptions::$text_domain)); $woocommerce->show_messages(); } elseif (!WC_Subscriptions_Manager::user_owns_subscription($subscription_key)) { $woocommerce->add_error(__('That doesn\'t appear to be one of your subscriptions.', WC_Subscriptions::$text_domain)); $woocommerce->show_messages(); } elseif (empty($subscription)) { $woocommerce->add_error(__('Invalid subscription.', WC_Subscriptions::$text_domain)); $woocommerce->show_messages(); } elseif (!WC_Subscriptions_Manager::can_subscription_be_changed_to('new-payment-method', $subscription_key, get_current_user_id())) { $woocommerce->add_error(__('The payment method can not be changed for that subscription.', WC_Subscriptions::$text_domain)); $woocommerce->show_messages(); } else { $order = new WC_Order($subscription['order_id']); $order_id = absint($_GET['order_id']); $order_key = urldecode($_GET['order']); $product_id = $subscription['product_id']; $next_payment_timestamp = WC_Subscriptions_Order::get_next_payment_timestamp($order, $product_id); if (!empty($next_payment_timestamp)) { $next_payment_string = sprintf(__(' Next payment is due %s.', WC_Subscriptions::$text_domain), date_i18n(woocommerce_date_format(), $next_payment_timestamp)); } else { $next_payment_string = ''; } $woocommerce->add_message(sprintf(__('Choose a new payment method.%s', WC_Subscriptions::$text_domain), $next_payment_string)); $woocommerce->show_messages(); if ($order->order_key == $order_key) { // Set customer location to order location if ($order->billing_country) { $woocommerce->customer->set_country($order->billing_country); } if ($order->billing_state) { $woocommerce->customer->set_state($order->billing_state); } if ($order->billing_postcode) { $woocommerce->customer->set_postcode($order->billing_postcode); } // Show form WC_Subscriptions_Order::$recurring_only_price_strings = true; woocommerce_get_template('checkout/form-change-payment-method.php', array('order' => $order, 'subscription_key' => $subscription_key), '', plugin_dir_path(WC_Subscriptions::$plugin_file) . 'templates/'); WC_Subscriptions_Order::$recurring_only_price_strings = false; } else { $woocommerce->add_error(__('Invalid order.', WC_Subscriptions::$text_domain)); $woocommerce->show_messages(); } } }
/** * Output a hidden element in the order status of the orders list table to provide information about whether * the order displayed in that row contains a subscription or not. * * @param $column String The string of the current column. * @since 1.1 */ public static function contains_subscription_hidden_field($order_id) { $has_subscription = WC_Subscriptions_Order::order_contains_subscription($order_id) ? 'true' : 'false'; echo '<input type="hidden" name="contains_subscription" value="' . $has_subscription . '">'; }
/** * Checks if a subscription requires manual payment because the payment gateway used to purchase the subscription * did not support automatic payments at the time of the subscription sign up. * * @param $subscription_key string A subscription key of the form created by @see self::get_subscription_key() * @param $user_id int The ID of the user who owns the subscriptions. Although this parameter is optional, if you have the User ID you should pass it to improve performance. * @return bool | null True if the subscription exists and requires manual payments, false if the subscription uses automatic payments, null if the subscription doesn't exist. * @since 1.2 */ public static function requires_manual_renewal($subscription_key, $user_id = '') { $subscription = self::get_subscription($subscription_key, $user_id); if (isset($subscription['order_id'])) { $requires_manual_renewals = WC_Subscriptions_Order::requires_manual_renewal($subscription['order_id']); } else { $requires_manual_renewals = null; } return $requires_manual_renewals; }
public function process_payment($order_id) { global $woocommerce, $wpdb; $this->client = $this->getCurrentClient(); // retrieve client $this->order_id = $order_id; $this->order_desc = $_SERVER['HTTP_HOST'] . ': ' . __('Order #', 'paymill') . $this->order_id . __(', Customer-ID #', 'paymill') . get_current_user_id(); $this->order = new WC_Order($this->order_id); // load subscription class $this->subscriptions = new paymill_subscriptions('woocommerce'); $this->offers = $this->subscriptions->offerGetList(); // get the totals for pre authorization $this->getTotals(); /* $GLOBALS['paymill_loader']->paymill_errors->setError($this->totalProducts,'paymill'); $GLOBALS['paymill_loader']->paymill_errors->setError($this->totalSub,'paymill'); if($GLOBALS['paymill_loader']->paymill_errors->status()){ $GLOBALS['paymill_loader']->paymill_errors->getErrors(); return false; } die('end'); */ // create payment object and preauthorization require_once PAYMILL_DIR . 'lib/integration/payment.inc.php'; $this->paymentClass = new paymill_payment($this->clientClass->getCurrentClientID(), $this->totalProducts + $this->totalSub, get_woocommerce_currency()); // create payment object, as it should be used for next processing instead of the token. if ($GLOBALS['paymill_loader']->paymill_errors->status()) { $GLOBALS['paymill_loader']->paymill_errors->getErrors(); return false; } // process subscriptions & products if ($this->processSubscriptions() && $this->processProducts()) { // success if (method_exists($this->order, 'payment_complete')) { // if order contains subscription, mark payment complete later when webhook triggers succeeded payment if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($this->order)) { $this->order->update_status('on-hold', __('Awaiting payment confirmation from Paymill.', 'paymill')); } else { $this->order->payment_complete(); } } // Reduce stock levels /*if(method_exists($this->order, 'reduce_order_stock')){ $this->order->reduce_order_stock(); }*/ // Remove cart $woocommerce->cart->empty_cart(); // Return thankyou redirect return array('result' => 'success', 'redirect' => $this->get_return_url($this->order)); } else { if ($GLOBALS['paymill_loader']->paymill_errors->status()) { $GLOBALS['paymill_loader']->paymill_errors->getErrors(); } return false; } }
function wc_subs_exporter_create_csv($export) { global $wc_subs_exporter; if (!$export->status) { return false; } if (empty($export->subscriptions)) { return false; } $subscription_statuses = wc_subs_exporter_get_subscription_statuses(); $fields = array(__('Order Id', 'wc-subs-exporter'), __('Order Status', 'wc-subs-exporter'), __('Subscription Status', 'wc-subs-exporter'), __('Subscription Description', 'wc-subs-exporter'), __('Subscription Start Date', 'wc-subs-exporter'), __('Subscription Expiration Date', 'wc-subs-exporter'), __('Subscription Last Payment', 'wc-subs-exporter'), __('Email', 'wc-subs-exporter'), __('Billing First Name', 'wc-subs-exporter'), __('Billing Last Name', 'wc-subs-exporter'), __('Billing Address 1', 'wc-subs-exporter'), __('Billing Address 2', 'wc-subs-exporter'), __('Billing City', 'wc-subs-exporter'), __('Billing State', 'wc-subs-exporter'), __('Billing Zip', 'wc-subs-exporter'), __('Billing Country', 'wc-subs-exporter'), __('Shipping First Name', 'wc-subs-exporter'), __('Shipping Last Name', 'wc-subs-exporter'), __('Shipping Address 1', 'wc-subs-exporter'), __('Shipping Address 2', 'wc-subs-exporter'), __('Shipping City', 'wc-subs-exporter'), __('Shipping State', 'wc-subs-exporter'), __('Shipping Zip', 'wc-subs-exporter'), __('Shipping Country', 'wc-subs-exporter'), __('Product SKU', 'wc-subs-exporter'), __('Product Description', 'wc-subs-exporter'), __('Quantity', 'wc-subs-exporter'), __('Date Ordered', 'wc-subs-exporter'), __('Coupon Code Used', 'wc-subs-exporter')); $csv = ''; if ($export->bom) { $csv .= chr(239) . chr(187) . chr(191) . ''; } foreach ($fields as $field) { $csv .= wc_subs_exporter_escape_csv_value($field, $export->delimiter, $export->escape_formatting) . $export->delimiter; } $csv = substr($csv, 0, -strlen($export->delimiter)) . "\n"; $processed_rows = 0; foreach ($export->subscriptions as $user => $user_subscriptions) { foreach ($user_subscriptions as $key => $subscription) { $order = new WC_Order($subscription['order_id']); $order_item = WC_Subscriptions_Order::get_item_by_product_id($order, $subscription['product_id']); $product = $order->get_product_from_item($order_item); if (empty($product)) { continue; } $product_sku = $product->get_sku(); $product_title = WC_Subscriptions_Order::get_item_name($subscription['order_id'], $subscription['product_id']); if (isset($product->variation_data)) { $product_description = woocommerce_get_formatted_variation($product->variation_data, true); } else { $product_description = $product_title; } $coupon_code_used = ''; $coupons = $order->get_items(array('coupon')); foreach ($coupons as $item_id => $item) { $coupon_code_used .= $item['name'] . ' '; } $start_date = substr($subscription['start_date'], 0, 10); if ($subscription['expiry_date']) { $end_date = substr($subscription['expiry_date'], 0, 10); } else { $end_date = '0000-00-00'; } if ($order->user_id > 0) { $user_info = get_userdata($order->user_id); } if (array_key_exists('completed_payments', $subscription) && is_array($subscription['completed_payments'])) { $recent_payment = substr(end($subscription['completed_payments']), 0, 10); } else { $recent_payment = ''; } $order_date = substr($order->completed_date, 0, 10); $csv .= wc_subs_exporter_escape_csv_value($order->id, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->status, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($subscription_statuses[$subscription['status']], $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($product_title, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($start_date, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($end_date, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($recent_payment, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($user_info->user_email, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_first_name, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_last_name, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_address_1, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_address_2, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_city, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_state, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_postcode, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->billing_country, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_first_name, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_last_name, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_address_1, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_address_2, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_city, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_state, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_postcode, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order->shipping_country, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($product_sku, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($product_description, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value(1, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value($order_date, $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= wc_subs_exporter_escape_csv_value(trim($coupon_code_used), $export->delimiter, $export->escape_formatting) . $export->delimiter; $csv .= "\n"; } } if (!$csv) { return false; } else { if (isset($wc_subs_exporter['debug']) && $wc_subs_exporter['debug']) { $wc_subs_exporter['debug_log'] = $csv; } else { return $csv; } } }
/** * When a subscription payment hook is fired, reschedule the hook to run again on the * time/date of the next payment (if any). * * WP-Cron's built in wp_schedule_event() function can not be used because the recurrence * must be a timestamp, which creates inaccurate schedules for month and year billing periods. * * @since 1.0 */ public static function reschedule_subscription_payment($user_id, $subscription_key) { $subscription = self::get_users_subscription($user_id, $subscription_key); // Don't reschedule for cancelled or expired subscriptions if (!in_array($subscription['status'], array('expired', 'cancelled', 'failed', 'suspended'))) { $next_billing_timestamp = strtotime(WC_Subscriptions_Order::get_next_payment_date($subscription['order_id'], $subscription['product_id'])); // If the next billing date is before the expiration date, reschedule the 'scheduled_subscription_payment' hook if ($subscription['expiry_date'] == 0 || $next_billing_timestamp < strtotime($subscription['expiry_date'])) { wp_schedule_single_event($next_billing_timestamp, 'scheduled_subscription_payment', array('user_id' => (int) $user_id, 'subscription_key' => $subscription_key)); do_action('rescheduled_subscription_payment', $user_id, $subscription_key); } } }
/** * Keep a record of an order's dates if we're marking it as completed during a request to change the payment method. * * @since 1.4 */ public static function store_original_order_dates($new_order_status, $order_id) { if (self::$is_request_to_change_payment) { $order = new WC_Order($order_id); $post = get_post($order_id); self::$original_order_dates = array('_paid_date' => WC_Subscriptions_Order::get_meta($order, 'paid_date'), '_completed_date' => WC_Subscriptions_Order::get_meta($order, 'completed_date'), 'post_date' => $order->order_date, 'post_date_gmt' => $post->post_date_gmt); } return $new_order_status; }
/** * Process an initial subscription payment if the order contains a * subscription, otherwise use the parent::process_payment() method * * @since 1.4 * @param int $order_id the order identifier * @return array */ public function process_payment($order_id) { require_once 'class-wc-realex-api.php'; // processing subscription (which means we are ineligible for 3DSecure for now) if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0() ? wcs_order_contains_subscription($order_id) : WC_Subscriptions_Order::order_contains_subscription($order_id)) { $order = wc_get_order($order_id); // redirect to payment page for payment if 3D secure is enabled if ($this->get_threedsecure()->is_3dsecure_available() && !SV_WC_Helper::get_post('woocommerce_pay_page')) { // empty cart before redirecting from Checkout page WC()->cart->empty_cart(); // redirect to payment page to continue payment return array('result' => 'success', 'redirect' => $order->get_checkout_payment_url(true)); } $order->payment_total = SV_WC_Helper::number_format(SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0() ? $order->get_total() : WC_Subscriptions_Order::get_total_initial_payment($order)); // create the realex api client $realex_client = new Realex_API($this->get_endpoint_url(), $this->get_realvault_endpoint_url(), $this->get_shared_secret()); // create the customer/cc tokens, and authorize the initial payment amount, if any $result = $this->authorize($realex_client, $order); // subscription with initial payment, everything is now taken care of if (is_array($result)) { // for Subscriptions 2.0.x, save payment token to subscription object if (SV_WC_Plugin_Compatibility::is_wc_subscriptions_version_gte_2_0()) { // a single order can contain multiple subscriptions foreach (wcs_get_subscriptions_for_order($order->id) as $subscription) { // payment token update_post_meta($subscription->id, '_realex_cardref', get_post_meta($order->id, '_realex_cardref', true)); } } return $result; } // otherwise there was no initial payment, so we mark the order as complete, etc if ($order->payment_total == 0) { // mark order as having received payment $order->payment_complete(); WC()->cart->empty_cart(); return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } else { // processing regular product return parent::process_payment($order_id); } }
/** * Process the payment * * If order contains subscriptions, use this class's process_subscription. If not, use the main class's process_payment function * * @param int $order_id * * @return array * * @since 0.6.0 */ public function process_payment($order_id) { // Processing subscription if (class_exists('WC_Subscriptions_Order') && WC_Subscriptions_Order::order_contains_subscription($order_id)) { return $this->process_subscription($order_id); // Processing regular product } else { return parent::process_payment($order_id); } }
/** * Get, sort and filter subscriptions for display. * * @uses $this->_column_headers * @uses $this->items * @uses $this->get_columns() * @uses $this->get_sortable_columns() * @uses $this->get_pagenum() * @uses $this->set_pagination_args() * @since 1.0 */ function prepare_items() { $screen = get_current_screen(); $per_page = $this->get_items_per_page($screen->get_option('per_page', 'option'), 10); $this->get_column_info(); $this->process_actions(); if (isset($_REQUEST['s'])) { $subscriptions_grouped_by_user = WC_Subscriptions_Manager::search_subscriptions($_REQUEST['s']); } elseif (isset($_GET['_customer_user']) || isset($_GET['_product_id'])) { if (isset($_GET['_customer_user']) && !empty($_GET['_customer_user'])) { $subscriptions_grouped_by_user = array($_GET['_customer_user'] => WC_Subscriptions_Manager::get_users_subscriptions($_GET['_customer_user'])); } else { $subscriptions_grouped_by_user = WC_Subscriptions_Manager::get_all_users_subscriptions(); } if (isset($_GET['_product_id']) && !empty($_GET['_product_id'])) { foreach ($subscriptions_grouped_by_user as $user_id => $subscriptions) { foreach ($subscriptions as $subscription_key => $subscription) { if ($subscription['product_id'] == intval($_GET['_product_id'])) { continue; } $order_item = WC_Subscriptions_Order::get_item_by_product_id($subscription['order_id'], $subscription['product_id']); if (isset($order_item['variation_id']) && $order_item['variation_id'] == intval($_GET['_product_id'])) { continue; } unset($subscriptions_grouped_by_user[$user_id][$subscription_key]); } } } } else { $subscriptions_grouped_by_user = WC_Subscriptions_Manager::get_all_users_subscriptions(); } $status_to_show = isset($_GET['status']) ? $_GET['status'] : 'all'; // Reformat the subscriptions grouped by user to be usable by each row $subscriptions = array(); $this->statuses = array(); foreach ($subscriptions_grouped_by_user as $user_id => $users_subscriptions) { foreach ($users_subscriptions as $subscription_key => $subscription) { $this->statuses[$subscription['status']] = isset($this->statuses[$subscription['status']]) ? $this->statuses[$subscription['status']] + 1 : 1; $all_subscriptions[$subscription_key] = $subscription + array('user_id' => $user_id, 'subscription_key' => $subscription_key); if ($status_to_show == $subscription['status'] || $status_to_show == 'all' && $subscription['status'] != 'trash') { $subscriptions[$subscription_key] = $subscription + array('user_id' => $user_id, 'subscription_key' => $subscription_key); } } } // If we have a request for a status that does not exist, default to all subscriptions if (!isset($this->statuses[$status_to_show])) { if ($status_to_show != 'all') { $status_to_show = $_GET['status'] = 'all'; foreach ($all_subscriptions as $subscription_key => $subscription) { if ($all_subscriptions[$subscription_key]['status'] != 'trash') { $subscriptions = $subscriptions + array($subscription_key => $subscription); } } } else { $_GET['status'] = 'all'; } } ksort($this->statuses); $this->statuses = array('all' => array_sum($this->statuses)) + $this->statuses; if (isset($this->statuses['trash'])) { $this->statuses['all'] = $this->statuses['all'] - $this->statuses['trash']; } usort($subscriptions, array(&$this, 'sort_subscriptions')); // Add sorted & sliced data to the items property to be used by the rest of the class $this->items = array_slice($subscriptions, ($this->get_pagenum() - 1) * $per_page, $per_page); $total_items = count($subscriptions); $this->set_pagination_args(array('total_items' => $total_items, 'per_page' => $per_page, 'total_pages' => ceil($total_items / $per_page))); }
/** * For subscription renewal via cart, preivously adjust item price by original order discount * * No longer required as of 1.3.5 as totals are calculated correctly internally. * * @since 1.3 */ public static function get_discounted_price_for_renewal($price, $values, $cart) { $cart_item = self::cart_contains_subscription_renewal(); if ($cart_item) { $original_order_id = $cart_item['subscription_renewal']['original_order']; $price -= WC_Subscriptions_Order::get_meta($original_order_id, '_order_recurring_discount_cart', 0); } return $price; }
?> </th> <th scope="col" style="text-align:left; border: 1px solid #eee;"><?php _e('Start Date', 'woocommerce-subscriptions'); ?> </th> <th scope="col" style="text-align:left; border: 1px solid #eee;"><?php _e('End Date', 'woocommerce-subscriptions'); ?> </th> </tr> </thead> <tbody> <?php foreach ($order->get_items() as $item) { if (WC_Subscriptions_Order::is_item_subscription($order, $item)) { ?> <tr> <td scope="row" style="text-align:left; border: 1px solid #eee;"><?php echo $item['name']; ?> </td> <td scope="row" style="text-align:left; border: 1px solid #eee;"><?php echo date_i18n(woocommerce_date_format(), strtotime($item['subscription_start_date'])); ?> </td> <td scope="row" style="text-align:left; border: 1px solid #eee;"><?php echo !empty($item['subscription_expiry_date']) ? date_i18n(woocommerce_date_format(), strtotime($item['subscription_expiry_date'])) : __('When Cancelled', 'woocommerce-subscriptions'); ?> </tr> <?php
_e('Subscription', 'woocommerce-subscriptions'); ?> </th> <th scope="col" style="text-align:left; border: 1px solid #eee;"><?php _e('Start Date', 'woocommerce-subscriptions'); ?> </th> <th scope="col" style="text-align:left; border: 1px solid #eee;"><?php _e('End Date', 'woocommerce-subscriptions'); ?> </th> </tr> </thead> <tbody> <?php foreach (WC_Subscriptions_Order::get_recurring_items($order) as $item) { ?> <tr> <td scope="row" style="text-align:left; border: 1px solid #eee;"><?php echo $item['name']; ?> </td> <td scope="row" style="text-align:left; border: 1px solid #eee;"><?php echo date_i18n(woocommerce_date_format(), strtotime($item['subscription_start_date'])); ?> </td> <td scope="row" style="text-align:left; border: 1px solid #eee;"><?php echo !empty($item['subscription_expiry_date']) ? date_i18n(woocommerce_date_format(), strtotime($item['subscription_expiry_date'])) : __('When Cancelled', 'woocommerce-subscriptions'); ?> </tr> <?php
function wpcomm_renewal_meta_update($order_meta, $order_id) { global $wpdb, $woocommerce; // Send me an email if this hook works error_log("woocommerce_subscriptions_renewal_order_created hook fired", 1, "*****@*****.**", "Subject: woocommerce_subscriptions_renewal_order_created"); if (!is_object($order)) { $order = new WC_Order($order); } // Get the values we need from the WC_Order object $order_id = $order->id; $item = $order->get_items(); $product_id = WC_Subscriptions_Order::get_items_product_id($item[0]); // These arrays contain the details for each possible product, in order. They // are used to change the order to the correct values $quarterly_product_ids = array(2949, 2945, 2767, 2793, 2795, 2796, 2798, 2799, 2800, 2805, 2806, 2815, 2816, 2817); $quarterly_product_names = array("One Day Renewal for Testing No Virtual Downloadable", "One Day Renewal for Testing", "0-3 MONTHS ELEPHANT (QUARTERLY)", "3-6 MONTHS HIPPO (QUARTERLY)", "6-9 MONTHS GIRAFFE (QUARTERLY)", "9-12 MONTHS PANDA (QUARTERLY)", "12-15 MONTHS ZEBRA (QUARTERLY)", "15-18 MONTHS RABBIT (QUARTERLY)", "18-21 MONTHS MONKEY (QUARTERLY)", "21-24 MONTHS FROG (QUARTERLY)", "24-27 MONTHS KANGAROO (QUARTERLY)", "27-30 MONTHS BEAR (QUARTERLY)", "30-33 MONTHS TIGER (QUARTERLY)", "33-36 MONTHS CROCODILE (QUARTERLY)"); // Not sure yet if SKUs are needed $quarterly_product_skus = array("test sku one", "test sku two", "0-3-elephant-q", "3-6-hippo-q", "6-9-giraffe-q", "9-12-panda-q", "12-15-zebra-q", "15-18-rabbit-q", "18-21-monkey-q", "21-24-frog-q", "24-24-kangaroo-q", "27-30-bear-q", "30-33-tiger-q", "33-36-crocodile-q"); $yearly_product_names = array(); $yearly_product_ids = array(); // Get the position of the current id, and then assign the next product // to $incremented_item_id and $incremented_item_name $product_id_index = array_search($product_id, $quarterly_product_ids); if ($product_id_index === False) { $product_id_index = array_search($product_id, $yearly_product_ids); } $incremented_item_id = $quarterly_product_ids[$product_id_index + 1]; $incremented_item_name = $quarterly_product_names[$product_id_index + 1]; $incremented_item_sku = $quarterly_product_skus[$product_id_index + 1]; // Apply the updates to the order $order_meta["_product_id"] = $incremented_item_id; $order_meta["_product_name"] = $incremented_item_name; $order_meta["_sku"] = $incremented_item_sku; return $order_meta; }