/** * 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')); } }
/** * Process payment for an order: * 1) If the order contains a subscription, process the initial subscription payment (could be $0 if a free trial exists) * 2) If the order contains a pre-order, process the pre-order total (could be $0 if the pre-order is charged upon release) * 3) Otherwise use the parent::process_payment() method for regular product purchases * * @since 2.0 * @param int $order_id * @return array */ public function process_payment($order_id) { global $wc_braintree; $order = $this->get_order($order_id); try { /* processing subscription */ if ($wc_braintree->is_subscriptions_active() && WC_Subscriptions_Order::order_contains_subscription($order_id)) { return $this->process_subscription_payment($order); /* processing pre-order */ } elseif ($wc_braintree->is_pre_orders_active() && WC_Pre_Orders_Order::order_contains_pre_order($order_id)) { return $this->process_pre_order_payment($order); /* processing regular product */ } else { return parent::process_payment($order_id); } } catch (WC_Gateway_Braintree_Exception $e) { // mark order as failed, which adds an order note for the admin and displays a generic "payment error" to the customer $this->mark_order_as_failed($order, $e->getMessage()); // add detailed debugging information $this->add_debug_message($e->getErrors()); } catch (Braintree_Exception_Authorization $e) { $this->mark_order_as_failed($order, __('Authorization failed, ensure that your API key is correct and has permissions to create transactions.', WC_Braintree::TEXT_DOMAIN)); } catch (Exception $e) { $this->mark_order_as_failed($order, sprintf(__('Error Type %s', WC_Braintree::TEXT_DOMAIN), get_class($e))); } }
/** * 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); } }
/** * 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); } }
/** * Only displays the gateways which support subscriptions. * * @since 1.0 */ public static function get_available_payment_gateways($available_gateways) { if (WC_Subscriptions_Cart::cart_contains_subscription() || isset($_GET['order_id']) && WC_Subscriptions_Order::order_contains_subscription($_GET['order_id'])) { // || WC_Subscriptions_Order::order_contains_subscription( $order_id ) foreach ($available_gateways as $gateway_id => $gateway) { if (!method_exists($gateway, 'supports') || $gateway->supports('subscriptions') !== true) { unset($available_gateways[$gateway_id]); } } } return $available_gateways; }
/** * Only display the gateways which support subscriptions if manual payments are not allowed. * * @since 1.0 */ public static function get_available_payment_gateways($available_gateways) { $accept_manual_payment = get_option(WC_Subscriptions_Admin::$option_prefix . '_accept_manual_renewals', 'no'); if ('no' == $accept_manual_payment && (WC_Subscriptions_Cart::cart_contains_subscription() || isset($_GET['order_id']) && WC_Subscriptions_Order::order_contains_subscription($_GET['order_id']))) { foreach ($available_gateways as $gateway_id => $gateway) { if (!method_exists($gateway, 'supports') || $gateway->supports('subscriptions') !== true) { unset($available_gateways[$gateway_id]); } } } return $available_gateways; }
/** * Process the payment and return the result * * @access public * @param int $order_id * @return array */ public function process_payment($order_id) { if (WC_Subscriptions_Order::order_contains_subscription($order_id)) { if ($this->send_to_stripe($order_id)) { $this->order_complete(); WC_Subscriptions_Manager::activate_subscriptions_for_order($this->order); $result = array('result' => 'success', 'redirect' => $this->get_return_url($this->order)); return $result; } else { $this->payment_failed(); // Add a generic error message if we don't currently have any others if (wc_notice_count('error') == 0) { wc_add_notice(__('Transaction Error: Could not complete your subscription payment.', 'stripe-for-woocommerce'), 'error'); } } } else { return parent::process_payment($order_id); } }
/** * 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); } }
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)); }
public function set_expiration_reminder($user_id, $subs_key) { global $wpdb; $parts = explode('_', $subs_key); $order_id = $parts[0]; $order = new WC_Order($order_id); if (WC_Subscriptions_Order::order_contains_subscription($order)) { // look for renewal emails $emails = $wpdb->get_results("SELECT * FROM {$wpdb->prefix}followup_emails WHERE `interval_type` = 'subs_before_expire' AND status = 1"); if (count($emails) > 0) { $subs = WC_Subscriptions_Manager::get_subscription($subs_key); $expiry = WC_Subscriptions_Manager::get_subscription_expiration_date($subs_key, $user_id, 'timestamp'); if (0 == $expiry) { return; } foreach ($emails as $email) { // add this email to the queue $interval = (int) $email->interval_num; $add = FUE::get_time_to_add($interval, $email->interval_duration); $send_on = $expiry - $add; $insert = array('user_id' => $user_id, 'send_on' => $send_on, 'email_id' => $email->id, 'product_id' => 0, 'order_id' => $order_id); if ($subs_key) { $insert['meta']['subs_key'] = $subs_key; } FUE::insert_email_order($insert); } } } }
/** * Registers the "Renewal Orders" meta box for the "Edit Order" page. */ public static function add_related_orders_meta_box() { global $current_screen, $post_id; // Only display the meta box if an order relates to a subscription if ('shop_order' == $current_screen->id && (WC_Subscriptions_Renewal_Order::is_renewal($post_id, array('order_role' => 'child')) || WC_Subscriptions_Order::order_contains_subscription($post_id))) { add_meta_box('subscription_renewal_orders', __('Related Subscription Orders', WC_Subscriptions::$text_domain), __CLASS__ . '::related_orders_meta_box', 'shop_order'); } }
/** * Adjust renew membership URL for subscription-based memberships * * @since 1.0.0 * @param string $url Renew membership URL * @param WC_Memberships_User_Membership $user_membership * @return string Modified renew URL */ public function renew_membership_url($url, WC_Memberships_User_Membership $user_membership) { if ($this->has_membership_plan_subscription($user_membership->get_plan_id())) { // note that we must also check if order contains a subscription since users // can be manually-assigned to memberships and not have an associated subscription // 2.0 onwards if ($this->is_subscriptions_gte_2_0()) { if (wcs_order_contains_subscription($user_membership->get_order())) { $url = wcs_get_users_resubscribe_link($this->get_user_membership_subscription_id($user_membership->get_id())); } } else { if (WC_Subscriptions_Order::order_contains_subscription($user_membership->get_order())) { $subscription_key = $this->get_user_membership_subscription_key($user_membership->get_id()); $url = WC_Subscriptions_Renewal_Order::get_users_renewal_link($subscription_key); } } } return $url; }
/** * Creates a new order for renewing a subscription product based on the details of a previous order. * * No trial periods or sign up fees are applied to the renewal order. However, if the order has failed * payments and the store manager has set failed payments to be added to renewal orders, then the * orders totals will be set to include the outstanding balance. * * If the $new_order_role flag is set to 'parent', then the renewal order will supersede the existing * order. The existing order and subscription associated with it will be cancelled. A new order and * subscription will be created. * * If the $new_order_role flag is 'child', the $original_order will remain the master order for the * subscription and the new order is just for accepting a recurring payment on the subscription. * * Renewal orders have the same meta data as the original order. If the renewal order is set to be a 'child' * then any subscription related meta data will not be stored on the new order. This is to keep subscription * meta data associated only with the one master order for the subscription. * * @param $order WC_Order | int The WC_Order object or ID of the order for which the a new order should be created. * @param $product_id string The ID of the subscription product in the order which needs to be added to the new order. * @param $new_order_role string A flag to indicate whether the new order should become the master order for the subscription. Accepts either 'parent' or 'child'. Defaults to 'parent' - replace the existing order. * @since 1.2 */ public static function generate_renewal_order($original_order, $product_id, $new_order_role = 'parent') { global $wpdb; if (!is_object($original_order)) { $original_order = new WC_Order($original_order); } if (!WC_Subscriptions_Order::order_contains_subscription($original_order) || !WC_Subscriptions_Order::is_item_a_subscription($original_order, $product_id)) { return false; } if (self::is_renewal($original_order, 'child')) { $original_order = self::get_parent_order($original_order); } $renewal_order_key = uniqid('order_'); // Create the new order $renewal_order_data = array('post_type' => 'shop_order', 'post_title' => sprintf(__('Subscription Renewal Order – %s', WC_Subscriptions::$text_domain), strftime(_x('%b %d, %Y @ %I:%M %p', 'Order date parsed by strftime', WC_Subscriptions::$text_domain))), 'post_status' => 'publish', 'ping_status' => 'closed', 'post_excerpt' => $original_order->customer_note, 'post_author' => 1, 'post_password' => $renewal_order_key); if ('child' == $new_order_role) { $renewal_order_data['post_parent'] = $original_order->id; } $renewal_order_id = wp_insert_post($renewal_order_data); // Set the order as pending wp_set_object_terms($renewal_order_id, 'pending', 'shop_order_status'); // Set a unique key for this order update_post_meta($renewal_order_id, '_order_key', $renewal_order_key); $order_meta_query = "SELECT `meta_key`, `meta_value` FROM {$wpdb->postmeta} WHERE `post_id` = {$original_order->id} AND `meta_key` NOT IN ('_paid_date', '_completed_date', '_order_key', '_edit_lock', '_original_order')"; // Superseding existing order so don't carry over payment details if ('parent' == $new_order_role) { $order_meta_query .= " AND `meta_key` NOT IN ('_payment_method', '_payment_method_title')"; } else { $order_meta_query .= " AND `meta_key` NOT LIKE '_order_recurring_%'"; } // Allow extensions to add/remove order meta $order_meta_query = apply_filters('woocommerce_subscriptions_renewal_order_meta_query', $order_meta_query, $original_order->id, $renewal_order_id, $new_order_role); // Carry all the required meta from the old order over to the new order $order_meta = $wpdb->get_results($order_meta_query, 'ARRAY_A'); $order_meta = apply_filters('woocommerce_subscriptions_renewal_order_meta', $order_meta, $original_order->id, $renewal_order_id, $new_order_role); foreach ($order_meta as $meta_item) { add_post_meta($renewal_order_id, $meta_item['meta_key'], maybe_unserialize($meta_item['meta_value']), true); } $outstanding_balance = WC_Subscriptions_Order::get_outstanding_balance($original_order, $product_id); // If there are outstanding payment amounts, add them to the order, otherwise set the order details to the values of the recurring totals if ($outstanding_balance > 0 && 'yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_add_outstanding_balance')) { $failed_payment_multiplier = WC_Subscriptions_Order::get_failed_payment_count($original_order, $product_id); } else { $failed_payment_multiplier = 1; } // Set order totals based on recurring totals from the original order $cart_discount = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_discount_cart', true); $order_discount = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_discount_total', true); $order_shipping_tax = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_shipping_tax_total', true); $order_tax = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_tax_total', true); $order_total = $failed_payment_multiplier * get_post_meta($original_order->id, '_order_recurring_total', true); update_post_meta($renewal_order_id, '_cart_discount', $cart_discount); update_post_meta($renewal_order_id, '_order_discount', $order_discount); update_post_meta($renewal_order_id, '_order_shipping_tax', $order_shipping_tax); update_post_meta($renewal_order_id, '_order_tax', $order_tax); update_post_meta($renewal_order_id, '_order_total', $order_total); // Set order taxes based on recurring taxes from the original order $recurring_order_taxes = get_post_meta($original_order->id, '_order_recurring_taxes', true); foreach ($recurring_order_taxes as $index => $recurring_order_tax) { if (isset($recurring_order_tax['cart_tax']) && $recurring_order_tax['cart_tax'] > 0) { $recurring_order_taxes[$index]['cart_tax'] = $failed_payment_multiplier * $recurring_order_tax['cart_tax']; } else { $recurring_order_taxes[$index]['cart_tax'] = 0; } if (isset($recurring_order_tax['shipping_tax']) && $recurring_order_tax['shipping_tax'] > 0) { $recurring_order_taxes[$index]['shipping_tax'] = $failed_payment_multiplier * $recurring_order_tax['shipping_tax']; } else { $recurring_order_taxes[$index]['shipping_tax'] = 0; } } update_post_meta($renewal_order_id, '_order_taxes', $recurring_order_taxes); // Set line totals to be recurring line totals and remove the subscription/recurring related item meta from each order item $order_items = WC_Subscriptions_Order::get_recurring_items($original_order); // Allow extensions to add/remove items or item meta $order_items = apply_filters('woocommerce_subscriptions_renewal_order_items', $order_items, $original_order->id, $renewal_order_id, $product_id, $new_order_role); foreach ($order_items as $item_index => $order_item) { $item_meta = new WC_Order_Item_Meta($order_item['item_meta']); // Remove recurring line items and set item totals based on recurring line totals foreach ($item_meta->meta as $meta_index => $meta_item) { switch ($meta_item['meta_name']) { case '_recurring_line_total': $order_items[$item_index]['line_total'] = $failed_payment_multiplier * $meta_item['meta_value']; case '_recurring_line_tax': $order_items[$item_index]['line_tax'] = $failed_payment_multiplier * $meta_item['meta_value']; case '_recurring_line_subtotal': $order_items[$item_index]['line_subtotal'] = $failed_payment_multiplier * $meta_item['meta_value']; case '_recurring_line_subtotal_tax': $order_items[$item_index]['line_subtotal_tax'] = $failed_payment_multiplier * $meta_item['meta_value']; case '_recurring_line_total': case '_recurring_line_tax': case '_recurring_line_subtotal': case '_recurring_line_subtotal_tax': case '_recurring_line_subtotal_tax': case '_subscription_recurring_amount': case '_subscription_sign_up_fee': case '_subscription_period': case '_subscription_interval': case '_subscription_length': case '_subscription_trial_length': case '_subscription_trial_period': if ('child' == $new_order_role) { unset($item_meta->meta[$meta_index]); } break; } } if ('child' == $new_order_role) { $order_items[$item_index]['name'] = sprintf(__('Renewal of "%s" purchased in Order %s', WC_Subscriptions::$text_domain), $order_item['name'], $original_order->get_order_number()); } $order_items[$item_index]['item_meta'] = $item_meta->meta; } // Save the item meta on the new order update_post_meta($renewal_order_id, '_order_items', $order_items); // Keep a record of the original order's ID on the renewal order update_post_meta($renewal_order_id, '_original_order', $original_order->id, true); $renewal_order = new WC_Order($renewal_order_id); if ('parent' == $new_order_role) { WC_Subscriptions_Manager::process_subscriptions_on_checkout($renewal_order_id); $original_order->add_order_note(sprintf(__('Order superseded by Renewal Order %s.', WC_Subscriptions::$text_domain), $renewal_order->get_order_number())); } do_action('woocommerce_subscriptions_renewal_order_created', $renewal_order, $original_order, $product_id, $new_order_role); return apply_filters('woocommerce_subscriptions_renewal_order_id', $renewal_order_id, $original_order, $product_id, $new_order_role); }
/** * When a new order is inserted, add subscriptions related order meta. * * @since 1.0 */ public static function add_order_meta($order_id, $posted) { global $woocommerce; if (!WC_Subscriptions_Cart::cart_contains_subscription_renewal('child') && WC_Subscriptions_Order::order_contains_subscription($order_id)) { // This works because the 'woocommerce_add_order_item_meta' runs before the 'woocommerce_checkout_update_order_meta' hook // Set the recurring totals so totals display correctly on order page update_post_meta($order_id, '_order_recurring_discount_cart', WC_Subscriptions_Cart::get_recurring_discount_cart()); update_post_meta($order_id, '_order_recurring_discount_cart_tax', WC_Subscriptions_Cart::get_recurring_discount_cart_tax()); update_post_meta($order_id, '_order_recurring_discount_total', WC_Subscriptions_Cart::get_recurring_discount_total()); update_post_meta($order_id, '_order_recurring_shipping_tax_total', WC_Subscriptions_Cart::get_recurring_shipping_tax_total()); update_post_meta($order_id, '_order_recurring_shipping_total', WC_Subscriptions_Cart::get_recurring_shipping_total()); update_post_meta($order_id, '_order_recurring_tax_total', WC_Subscriptions_Cart::get_recurring_total_tax()); update_post_meta($order_id, '_order_recurring_total', WC_Subscriptions_Cart::get_recurring_total()); // Set the recurring payment method - it starts out the same as the original by may change later update_post_meta($order_id, '_recurring_payment_method', get_post_meta($order_id, '_payment_method', true)); update_post_meta($order_id, '_recurring_payment_method_title', get_post_meta($order_id, '_payment_method_title', true)); $order = new WC_Order($order_id); $order_fees = $order->get_fees(); // the fee order items have already been set, we just need to to add the recurring total meta $cart_fees = $woocommerce->cart->get_fees(); foreach ($order->get_fees() as $item_id => $order_fee) { // Find the matching fee in the cart foreach ($cart_fees as $fee_index => $cart_fee) { if (sanitize_title($order_fee['name']) == $cart_fee->id) { woocommerce_add_order_item_meta($item_id, '_recurring_line_total', wc_format_decimal($cart_fee->recurring_amount)); woocommerce_add_order_item_meta($item_id, '_recurring_line_tax', wc_format_decimal($cart_fee->recurring_tax)); unset($cart_fees[$fee_index]); break; } } } // Get recurring taxes into same format as _order_taxes $order_recurring_taxes = array(); foreach (WC_Subscriptions_Cart::get_recurring_taxes() as $tax_key => $tax_amount) { $item_id = woocommerce_add_order_item($order_id, array('order_item_name' => WC_Tax::get_rate_code($tax_key), 'order_item_type' => 'recurring_tax')); if ($item_id) { wc_add_order_item_meta($item_id, 'rate_id', $tax_key); wc_add_order_item_meta($item_id, 'label', WC_Tax::get_rate_label($tax_key)); wc_add_order_item_meta($item_id, 'compound', absint(WC_Tax::is_compound($tax_key) ? 1 : 0)); wc_add_order_item_meta($item_id, 'tax_amount', wc_format_decimal(isset(WC()->cart->recurring_taxes[$tax_key]) ? WC()->cart->recurring_taxes[$tax_key] : 0)); wc_add_order_item_meta($item_id, 'shipping_tax_amount', wc_format_decimal(isset(WC()->cart->recurring_shipping_taxes[$tax_key]) ? WC()->cart->recurring_shipping_taxes[$tax_key] : 0)); } } $payment_gateways = $woocommerce->payment_gateways->payment_gateways(); if ('yes' == get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) { update_post_meta($order_id, '_wcs_requires_manual_renewal', 'true'); } elseif (isset($payment_gateways[$posted['payment_method']]) && !$payment_gateways[$posted['payment_method']]->supports('subscriptions')) { update_post_meta($order_id, '_wcs_requires_manual_renewal', 'true'); } $cart_item = WC_Subscriptions_Cart::cart_contains_subscription_renewal(); if (isset($cart_item['subscription_renewal']) && 'parent' == $cart_item['subscription_renewal']['role']) { update_post_meta($order_id, '_original_order', $cart_item['subscription_renewal']['original_order']); } // WC 2.1+ if (!WC_Subscriptions::is_woocommerce_pre('2.1')) { // Recurring coupons if ($applied_coupons = $woocommerce->cart->get_coupons()) { foreach ($applied_coupons as $code => $coupon) { if (!isset($woocommerce->cart->recurring_coupon_discount_amounts[$code])) { continue; } $item_id = woocommerce_add_order_item($order_id, array('order_item_name' => $code, 'order_item_type' => 'recurring_coupon')); // Add line item meta if ($item_id) { woocommerce_add_order_item_meta($item_id, 'discount_amount', isset($woocommerce->cart->recurring_coupon_discount_amounts[$code]) ? $woocommerce->cart->recurring_coupon_discount_amounts[$code] : 0); } } } // Add recurring shipping order items if (WC_Subscriptions_Cart::cart_contains_subscriptions_needing_shipping()) { $packages = $woocommerce->shipping->get_packages(); $checkout = $woocommerce->checkout(); foreach ($packages as $i => $package) { if (isset($package['rates'][$checkout->shipping_methods[$i]])) { $method = $package['rates'][$checkout->shipping_methods[$i]]; $item_id = woocommerce_add_order_item($order_id, array('order_item_name' => $method->label, 'order_item_type' => 'recurring_shipping')); if ($item_id) { woocommerce_add_order_item_meta($item_id, 'method_id', $method->id); woocommerce_add_order_item_meta($item_id, 'cost', WC_Subscriptions::format_total($method->cost)); woocommerce_add_order_item_meta($item_id, 'taxes', array_map('wc_format_decimal', $method->taxes)); do_action('woocommerce_subscriptions_add_recurring_shipping_order_item', $order_id, $item_id, $i); } } } } // Remove shipping on original order if it was added but is not required if (!WC_Subscriptions_Cart::charge_shipping_up_front()) { foreach ($order->get_shipping_methods() as $order_item_id => $shipping_method) { woocommerce_update_order_item_meta($order_item_id, 'cost', WC_Subscriptions::format_total(0)); } } } else { update_post_meta($order_id, '_recurring_shipping_method', get_post_meta($order_id, '_shipping_method', true), true); update_post_meta($order_id, '_recurring_shipping_method_title', get_post_meta($order_id, '_shipping_method_title', true), true); } } }
/** * Override the default PayPal standard args in WooCommerce for subscription purchases. * * Based on the HTML Variables documented here: https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU * * @since 1.0 */ public static function paypal_standard_subscription_args($paypal_args) { extract(self::get_order_id_and_key($paypal_args)); if (WC_Subscriptions_Order::order_contains_subscription($order_id) && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) { $order = new WC_Order($order_id); $order_items = $order->get_items(); // Only one subscription allowed in the cart when PayPal Standard is active $product = $order->get_product_from_item(array_pop($order_items)); // It's a subscription $paypal_args['cmd'] = '_xclick-subscriptions'; if (count($order->get_items()) > 1) { foreach ($order->get_items() as $item) { if ($item['qty'] > 1) { $item_names[] = $item['qty'] . ' x ' . $item['name']; } else { if ($item['qty'] > 0) { $item_names[] = $item['name']; } } } $paypal_args['item_name'] = sprintf(__('Order %s', WC_Subscriptions::$text_domain), $order->get_order_number()); } else { $paypal_args['item_name'] = $product->get_title(); } $unconverted_periods = array('billing_period' => WC_Subscriptions_Order::get_subscription_period($order), 'trial_period' => WC_Subscriptions_Order::get_subscription_trial_period($order)); $converted_periods = array(); // Convert period strings into PayPay's format foreach ($unconverted_periods as $key => $period) { switch (strtolower($period)) { case 'day': $converted_periods[$key] = 'D'; break; case 'week': $converted_periods[$key] = 'W'; break; case 'year': $converted_periods[$key] = 'Y'; break; case 'month': default: $converted_periods[$key] = 'M'; break; } } $price_per_period = WC_Subscriptions_Order::get_recurring_total($order); $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order); $subscription_length = WC_Subscriptions_Order::get_subscription_length($order); $subscription_installments = $subscription_length / $subscription_interval; $is_payment_change = WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment; $is_switch_order = WC_Subscriptions_Switcher::order_contains_subscription_switch($order->id); $sign_up_fee = $is_payment_change ? 0 : WC_Subscriptions_Order::get_sign_up_fee($order); $initial_payment = $is_payment_change ? 0 : WC_Subscriptions_Order::get_total_initial_payment($order); if ($is_payment_change) { // Add a nonce to the order ID to avoid "This invoice has already been paid" error when changing payment method to PayPal when it was previously PayPal $paypal_args['invoice'] = $paypal_args['invoice'] . '-wcscpm-' . wp_create_nonce(); // Set a flag on the order if changing from PayPal *to* PayPal to prevent incorrectly cancelling the subscription if ('paypal' == $order->recurring_payment_method) { add_post_meta($order_id, '_wcs_changing_payment_from_paypal_to_paypal', 'true', true); } } // If we're changing the payment date or switching subs, we need to set the trial period to the next payment date & installments to be the number of installments left if ($is_payment_change || $is_switch_order) { $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id); // Give a free trial until the next payment date $next_payment_timestamp = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $order->user_id, 'timestamp'); // When the subscription is on hold if ($next_payment_timestamp != false) { $trial_until = self::calculate_trial_periods_until($next_payment_timestamp); $subscription_trial_length = $trial_until['first_trial_length']; $converted_periods['trial_period'] = $trial_until['first_trial_period']; $second_trial_length = $trial_until['second_trial_length']; $second_trial_period = $trial_until['second_trial_period']; } // If is a payment change, we need to account for completed payments on the number of installments owing if ($is_payment_change && $subscription_length > 0) { $subscription_installments -= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key); } } else { $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order); } if ($subscription_trial_length > 0) { // Specify a free trial period if ($is_switch_order) { $paypal_args['a1'] = $initial_payment > 0 ? $initial_payment : 0; } else { $paypal_args['a1'] = $sign_up_fee > 0 ? $sign_up_fee : 0; } // Maybe add the sign up fee to the free trial period // Trial period length $paypal_args['p1'] = $subscription_trial_length; // Trial period $paypal_args['t1'] = $converted_periods['trial_period']; // We need to use a second trial period before we have more than 90 days until the next payment if (WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment && $second_trial_length > 0) { $paypal_args['a2'] = 0; $paypal_args['p2'] = $second_trial_length; $paypal_args['t2'] = $second_trial_period; } } elseif ($sign_up_fee > 0 || $initial_payment !== $price_per_period) { // No trial period, so charge sign up fee and per period price for the first period if ($subscription_installments == 1) { $param_number = 3; } else { $param_number = 1; } $paypal_args['a' . $param_number] = $initial_payment; // Sign Up interval $paypal_args['p' . $param_number] = $subscription_interval; // Sign Up unit of duration $paypal_args['t' . $param_number] = $converted_periods['billing_period']; } // We have a recurring payment if (!isset($param_number) || $param_number == 1) { // Subscription price $paypal_args['a3'] = $price_per_period; // Subscription duration $paypal_args['p3'] = $subscription_interval; // Subscription period $paypal_args['t3'] = $converted_periods['billing_period']; } // Recurring payments if ($subscription_installments == 1 || $sign_up_fee > 0 && $subscription_trial_length == 0 && $subscription_installments == 2) { // Non-recurring payments $paypal_args['src'] = 0; } else { $paypal_args['src'] = 1; if ($subscription_installments > 0) { if ($sign_up_fee > 0 && $subscription_trial_length == 0) { // An initial period is being used to charge a sign-up fee $subscription_installments--; } $paypal_args['srt'] = $subscription_installments; } } // Don't reattempt failed payments, instead let Subscriptions handle the failed payment $paypal_args['sra'] = 0; // Force return URL so that order description & instructions display $paypal_args['rm'] = 2; } return $paypal_args; }
/** * Adds subscriptions data to the order object * * @since 4.1.0 * @see SV_WC_Payment_Gateway::get_order() * @param WC_Order $order the order * @return WC_Order the orders */ public function get_order_1_5($order) { // bail if the order doesn't contain a subscription if (!WC_Subscriptions_Order::order_contains_subscription($order->id)) { return $order; } // subscriptions total, ensuring that we have a decimal point, even if it's 1.00 $order->payment_total = SV_WC_Helper::number_format(WC_Subscriptions_Order::get_total_initial_payment($order)); // load any required members that we might not have if (!isset($order->payment->token) || !$order->payment->token) { $order->payment->token = $this->get_gateway()->get_order_meta($order->id, 'payment_token'); } if (!isset($order->customer_id) || !$order->customer_id) { $order->customer_id = $this->get_gateway()->get_order_meta($order->id, 'customer_id'); } // ensure the payment token is still valid if (!$this->get_gateway()->has_payment_token($order->get_user_id(), $order->payment->token)) { $order->payment->token = null; } else { // get the token object $token = $this->get_gateway()->get_payment_token($order->get_user_id(), $order->payment->token); if (!isset($order->payment->account_number) || !$order->payment->account_number) { $order->payment->account_number = $token->get_last_four(); } if ($this->get_gateway()->is_credit_card_gateway()) { // credit card token if (!isset($order->payment->card_type) || !$order->payment->card_type) { $order->payment->card_type = $token->get_card_type(); } if (!isset($order->payment->exp_month) || !$order->payment->exp_month) { $order->payment->exp_month = $token->get_exp_month(); } if (!isset($order->payment->exp_year) || !$order->payment->exp_year) { $order->payment->exp_year = $token->get_exp_year(); } } elseif ($this->get_gateway()->is_echeck_gateway()) { // check token if (!isset($order->payment->account_type) || !$order->payment->account_type) { $order->payment->account_type = $token->get_account_type(); } } } return $order; }
/** * Override the default PayPal standard args in WooCommerce for subscription purchases. * * @since 1.0 */ public static function paypal_standard_subscription_args($paypal_args) { extract(self::get_order_id_and_key($paypal_args)); if (WC_Subscriptions_Order::order_contains_subscription($order_id)) { $order = new WC_Order($order_id); $order_items = $order->get_items(); // Only one subscription allowed in the cart when PayPal Standard is active $product = $order->get_product_from_item($order_items[0]); // It's a subscription $paypal_args['cmd'] = '_xclick-subscriptions'; if (count($order->get_items()) > 1) { foreach ($order->get_items() as $item) { if ($item['qty'] > 1) { $item_names[] = $item['qty'] . ' x ' . $item['name']; } else { if ($item['qty'] > 0) { $item_names[] = $item['name']; } } } $paypal_args['item_name'] = sprintf(__('Order %s', WC_Subscriptions::$text_domain), $order->get_order_number()); } else { $paypal_args['item_name'] = $product->get_title(); } // Subscription unit of duration switch (strtolower(WC_Subscriptions_Order::get_subscription_period($order))) { case 'day': $subscription_period = 'D'; break; case 'week': $subscription_period = 'W'; break; case 'year': $subscription_period = 'Y'; break; case 'month': default: $subscription_period = 'M'; break; } $sign_up_fee = WC_Subscriptions_Order::get_sign_up_fee($order); $price_per_period = WC_Subscriptions_Order::get_price_per_period($order); $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order); $subscription_length = WC_Subscriptions_Order::get_subscription_length($order); $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order); if ($subscription_trial_length > 0) { // Specify a free trial period $paypal_args['a1'] = $sign_up_fee > 0 ? $sign_up_fee : 0; // Add the sign up fee to the free trial period // Sign Up interval $paypal_args['p1'] = $subscription_trial_length; // Sign Up unit of duration $paypal_args['t1'] = $subscription_period; } elseif ($sign_up_fee > 0) { // No trial period, so charge sign up fee and per period price for the first period if ($subscription_length == 1) { $param_number = 3; } else { $param_number = 1; } $paypal_args['a' . $param_number] = $price_per_period + $sign_up_fee; // Sign Up interval $paypal_args['p' . $param_number] = $subscription_interval; // Sign Up unit of duration $paypal_args['t' . $param_number] = $subscription_period; } // We have a recurring payment if (!isset($param_number) || $param_number == 1) { // Subscription price $paypal_args['a3'] = $price_per_period; // Subscription duration $paypal_args['p3'] = $subscription_interval; // Subscription period $paypal_args['t3'] = $subscription_period; } // Recurring payments if ($subscription_length == 1 || $sign_up_fee > 0 && $subscription_trial_length == 0 && $subscription_length == 2) { // Non-recurring payments $paypal_args['src'] = 0; } else { $paypal_args['src'] = 1; if ($subscription_length > 0) { if ($sign_up_fee > 0 && $subscription_trial_length == 0) { // An initial period is being used to charge a sign-up fee $subscription_length--; } $paypal_args['srt'] = $subscription_length / $subscription_interval; } } // Force return URL so that order description & instructions display $paypal_args['rm'] = 2; } return $paypal_args; }
/** * Outputs the contents of the "Renewal Orders" meta box. * * @param object $post Current post data. */ public static function renewal_orders_meta_box($post) { $order = new WC_Order(absint($post->ID)); if (WC_Subscriptions_Renewal_Order::is_renewal($order, array('order_role' => 'child'))) { $parent_id = WC_Subscriptions_Renewal_Order::get_parent_order_id($order); } else { if (WC_Subscriptions_Order::order_contains_subscription($order)) { $parent_id = $post->ID; } } //Find any renewal orders associated with this order. $items = get_posts(array('post_type' => $post->post_type, 'post_parent' => $parent_id, 'numberposts' => -1)); if (WC_Subscriptions_Renewal_Order::is_renewal($order, array('order_role' => 'child'))) { $parent_order = new WC_Order($parent_id); printf('<p>%1$s <a href="%2$s">%3$s</a></p>', __('Initial Order:', WC_Subscriptions::$text_domain), get_edit_post_link($parent_id), $parent_order->get_order_number()); } if (empty($items)) { printf(' <p class="renewal-subtitle">%s</p>', __('No renewal payments yet.', WC_Subscriptions::$text_domain)); } else { printf('<p class="renewal-subtitle">%s</p>', __('Renewal Orders:', WC_Subscriptions::$text_domain)); echo '<ul class="renewal-orders">'; foreach ($items as $item) { $renewal_order = new WC_Order($item->ID); if ($item->ID == $post->ID) { printf('<li><strong>%s</strong></li>', $renewal_order->get_order_number()); } else { printf('<li><a href="%1$s">%2$s</a></li>', get_edit_post_link($item->ID), $renewal_order->get_order_number()); } } echo '</ul>'; } }
/** * Generate the epay button link **/ public function generate_epay_form($order_id) { global $woocommerce; $order = new WC_Order($order_id); $epay_args = array('merchantnumber' => $this->merchant, 'windowid' => $this->windowid, 'windowstate' => $this->windowstate, 'instantcallback' => 1, 'instantcapture' => $this->yesnotoint($this->instantcapture), 'group' => $this->group, 'mailreceipt' => $this->authmail, 'ownreceipt' => $this->yesnotoint($this->ownreceipt), 'amount' => class_exists('WC_Subscriptions_Order') ? WC_Subscriptions_Order::order_contains_subscription($order) ? WC_Subscriptions_Order::get_total_initial_payment($order) * 100 : $order->order_total * 100 : $order->order_total * 100, 'orderid' => str_replace(_x('#', 'hash before order number', 'woocommerce'), "", $order->get_order_number()), 'currency' => get_woocommerce_currency(), 'callbackurl' => $this->fix_url(add_query_arg('wooorderid', $order_id, add_query_arg('wc-api', 'WC_Gateway_EPayDk', $this->get_return_url($order)))), 'accepturl' => $this->fix_url($this->get_return_url($order)), 'cancelurl' => $this->fix_url($order->get_cancel_order_url()), 'language' => $this->get_language_code(get_locale()), 'subscription' => class_exists('WC_Subscriptions_Order') ? WC_Subscriptions_Order::order_contains_subscription($order) ? 1 : 0 : 0); if ($this->settings["enableinvoice"] == "yes") { $invoice = array(); $invoice["customer"] = array("emailaddress" => $order->billing_email, "firstname" => $this->jsonValueRemoveSpecialCharacters($order->billing_first_name), "lastname" => $this->jsonValueRemoveSpecialCharacters($order->billing_last_name), "address" => $this->jsonValueRemoveSpecialCharacters($order->billing_address_1 . ($order->billing_address_2 != null) ? ' ' . $order->billing_address_2 : ''), "zip" => $order->billing_postcode, "city" => $order->billing_city, "country" => $order->billing_country); $invoice["shippingaddress"] = array("firstname" => $this->jsonValueRemoveSpecialCharacters($order->shipping_first_name), "lastname" => $this->jsonValueRemoveSpecialCharacters($order->shipping_last_name), "address" => $this->jsonValueRemoveSpecialCharacters($order->shipping_address_1 . ($order->shipping_address_2 != null) ? ' ' . $order->shipping_address_2 : ''), "zip" => $order->shipping_postcode, "city" => $order->shipping_city, "country" => $order->shipping_country); $items = $order->get_items(); foreach ($items as $item) { $invoice["lines"][] = array("id" => $item["product_id"], "description" => $this->jsonValueRemoveSpecialCharacters($item["name"]), "quantity" => $item["qty"], "price" => round($item["line_subtotal"] / $item["qty"] * 100), "vat" => round($item["line_subtotal_tax"] / $item["line_subtotal"] * 100)); } $discount = $order->get_total_discount(); if ($discount > 0) { $invoice["lines"][] = array("id" => "discount", "description" => "discount", "quantity" => 1, "price" => -round($discount * 100), "vat" => round($order->get_total_tax() / ($order->get_total() - $order->get_total_tax()) * 100)); } $shipping = $order->get_total_shipping(); if ($shipping > 0) { $invoice["lines"][] = array("id" => "shipping", "description" => "shipping", "quantity" => 1, "price" => round($shipping * 100), "vat" => round($order->get_shipping_tax() / $shipping * 100)); } $epay_args['invoice'] = $this->jsonRemoveUnicodeSequences($invoice); } if (strlen($this->md5key) > 0) { $hash = ""; foreach ($epay_args as $key => $value) { $hash .= $value; } $epay_args["hash"] = md5($hash . $this->md5key); } $epay_args_array = array(); foreach ($epay_args as $key => $value) { $epay_args_array[] = '\'' . esc_attr($key) . '\': \'' . $value . '\''; } return '<script type="text/javascript"> function PaymentWindowReady() { paymentwindow = new PaymentWindow({ ' . implode(',', $epay_args_array) . ' }); paymentwindow.open(); } </script> <script type="text/javascript" src="https://ssl.ditonlinebetalingssystem.dk/integration/ewindow/paymentwindow.js" charset="UTF-8"></script> <a class="button" onclick="javascript: paymentwindow.open();" id="submit_epay_payment_form" />' . __('Pay via ePay', 'woocommerce-gateway-epay-dk') . '</a> <a class="button cancel" href="' . esc_url($order->get_cancel_order_url()) . '">' . __('Cancel order & restore cart', 'woocommerce-gateway-epay-dk') . '</a>'; }
/** * Override the default PayPal standard args in WooCommerce for subscription purchases when * automatic payments are enabled and when the recurring order totals is over $0.00 (because * PayPal doesn't support subscriptions with a $0 recurring total, we need to circumvent it and * manage it entirely ourselves.) * * Based on the HTML Variables documented here: https://developer.paypal.com/webapps/developer/docs/classic/paypal-payments-standard/integration-guide/Appx_websitestandard_htmlvariables/#id08A6HI00JQU * * @since 1.0 */ public static function paypal_standard_subscription_args($paypal_args) { extract(self::get_order_id_and_key($paypal_args)); $order = new WC_Order($order_id); if ($cart_item = WC_Subscriptions_Cart::cart_contains_failed_renewal_order_payment() || false !== WC_Subscriptions_Renewal_Order::get_failed_order_replaced_by($order_id)) { $renewal_order = $order; $order = WC_Subscriptions_Renewal_Order::get_parent_order($renewal_order); $order_contains_failed_renewal = true; } else { $order_contains_failed_renewal = false; } if ($order_contains_failed_renewal || WC_Subscriptions_Order::order_contains_subscription($order) && WC_Subscriptions_Order::get_recurring_total($order) > 0 && 'yes' !== get_option(WC_Subscriptions_Admin::$option_prefix . '_turn_off_automatic_payments', 'no')) { // Only one subscription allowed in the cart when PayPal Standard is active $product = $order->get_product_from_item(array_pop(WC_Subscriptions_Order::get_recurring_items($order))); // It's a subscription $paypal_args['cmd'] = '_xclick-subscriptions'; if (count($order->get_items()) > 1) { foreach ($order->get_items() as $item) { if ($item['qty'] > 1) { $item_names[] = $item['qty'] . ' x ' . self::paypal_item_name($item['name']); } elseif ($item['qty'] > 0) { $item_names[] = self::paypal_item_name($item['name']); } } $paypal_args['item_name'] = self::paypal_item_name(sprintf(__('Order %s', 'woocommerce-subscriptions'), $order->get_order_number() . " - " . implode(', ', $item_names))); } else { $paypal_args['item_name'] = self::paypal_item_name($product->get_title()); } $unconverted_periods = array('billing_period' => WC_Subscriptions_Order::get_subscription_period($order), 'trial_period' => WC_Subscriptions_Order::get_subscription_trial_period($order)); $converted_periods = array(); // Convert period strings into PayPay's format foreach ($unconverted_periods as $key => $period) { switch (strtolower($period)) { case 'day': $converted_periods[$key] = 'D'; break; case 'week': $converted_periods[$key] = 'W'; break; case 'year': $converted_periods[$key] = 'Y'; break; case 'month': default: $converted_periods[$key] = 'M'; break; } } $price_per_period = WC_Subscriptions_Order::get_recurring_total($order); $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order); $subscription_length = WC_Subscriptions_Order::get_subscription_length($order); $subscription_installments = $subscription_length / $subscription_interval; $is_payment_change = WC_Subscriptions_Change_Payment_Gateway::$is_request_to_change_payment; $is_switch_order = WC_Subscriptions_Switcher::order_contains_subscription_switch($order->id); $is_synced_subscription = WC_Subscriptions_Synchroniser::order_contains_synced_subscription($order->id); $sign_up_fee = $is_payment_change ? 0 : WC_Subscriptions_Order::get_sign_up_fee($order); $initial_payment = $is_payment_change ? 0 : WC_Subscriptions_Order::get_total_initial_payment($order); if ($is_payment_change) { // Add a nonce to the order ID to avoid "This invoice has already been paid" error when changing payment method to PayPal when it was previously PayPal $paypal_args['invoice'] = $paypal_args['invoice'] . '-wcscpm-' . wp_create_nonce(); } elseif ($order_contains_failed_renewal) { // Set the invoice details to the original order's invoice but also append a special string and this renewal orders ID so that we can match it up as a failed renewal order payment later $paypal_args['invoice'] = self::$invoice_prefix . ltrim($order->get_order_number(), '#') . '-wcsfrp-' . $renewal_order->id; $paypal_args['custom'] = serialize(array($order->id, $order->order_key)); } if ($order_contains_failed_renewal) { $sign_up_fee = 0; $initial_payment = $renewal_order->get_total(); // Initial payment can be left in case the customer is purchased other products with the payment $subscription_trial_length = 0; $subscription_installments = max($subscription_installments - WC_Subscriptions_Manager::get_subscriptions_completed_payment_count(WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id)), 0); // If we're changing the payment date or switching subs, we need to set the trial period to the next payment date & installments to be the number of installments left } elseif ($is_payment_change || $is_switch_order || $is_synced_subscription) { $subscription_key = WC_Subscriptions_Manager::get_subscription_key($order_id, $product->id); // Give a free trial until the next payment date if ($is_switch_order) { $next_payment_timestamp = get_post_meta($order->id, '_switched_subscription_first_payment_timestamp', true); } elseif ($is_synced_subscription) { $next_payment_timestamp = WC_Subscriptions_Synchroniser::calculate_first_payment_date($product, 'timestamp'); } else { $next_payment_timestamp = WC_Subscriptions_Manager::get_next_payment_date($subscription_key, $order->user_id, 'timestamp'); } // When the subscription is on hold if ($next_payment_timestamp != false && !empty($next_payment_timestamp)) { $trial_until = self::calculate_trial_periods_until($next_payment_timestamp); $subscription_trial_length = $trial_until['first_trial_length']; $converted_periods['trial_period'] = $trial_until['first_trial_period']; $second_trial_length = $trial_until['second_trial_length']; $second_trial_period = $trial_until['second_trial_period']; } else { $subscription_trial_length = 0; } // If is a payment change, we need to account for completed payments on the number of installments owing if ($is_payment_change && $subscription_length > 0) { $subscription_installments -= WC_Subscriptions_Manager::get_subscriptions_completed_payment_count($subscription_key); } } else { $subscription_trial_length = WC_Subscriptions_Order::get_subscription_trial_length($order); } if ($subscription_trial_length > 0) { // Specify a free trial period if ($is_switch_order || $is_synced_subscription || $initial_payment != $sign_up_fee) { $paypal_args['a1'] = $initial_payment > 0 ? $initial_payment : 0; } else { $paypal_args['a1'] = $sign_up_fee > 0 ? $sign_up_fee : 0; // Maybe add the sign up fee to the free trial period } // Trial period length $paypal_args['p1'] = $subscription_trial_length; // Trial period $paypal_args['t1'] = $converted_periods['trial_period']; // We need to use a second trial period before we have more than 90 days until the next payment if (isset($second_trial_length) && $second_trial_length > 0) { $paypal_args['a2'] = 0.01; // Alas, although it's undocumented, PayPal appears to require a non-zero value in order to allow a second trial period $paypal_args['p2'] = $second_trial_length; $paypal_args['t2'] = $second_trial_period; } } elseif ($sign_up_fee > 0 || $initial_payment != $price_per_period) { // No trial period, so charge sign up fee and per period price for the first period if ($subscription_installments == 1) { $param_number = 3; } else { $param_number = 1; } $paypal_args['a' . $param_number] = $initial_payment; // Sign Up interval $paypal_args['p' . $param_number] = $subscription_interval; // Sign Up unit of duration $paypal_args['t' . $param_number] = $converted_periods['billing_period']; } // We have a recurring payment if (!isset($param_number) || $param_number == 1) { // Subscription price $paypal_args['a3'] = $price_per_period; // Subscription duration $paypal_args['p3'] = $subscription_interval; // Subscription period $paypal_args['t3'] = $converted_periods['billing_period']; } // Recurring payments if ($subscription_installments == 1 || $sign_up_fee > 0 && $subscription_trial_length == 0 && $subscription_installments == 2) { // Non-recurring payments $paypal_args['src'] = 0; } else { $paypal_args['src'] = 1; if ($subscription_installments > 0) { if ($sign_up_fee > 0 && $subscription_trial_length == 0) { // An initial period is being used to charge a sign-up fee $subscription_installments--; } $paypal_args['srt'] = $subscription_installments; } } // Don't reattempt failed payments, instead let Subscriptions handle the failed payment $paypal_args['sra'] = 0; // Force return URL so that order description & instructions display $paypal_args['rm'] = 2; } return $paypal_args; }
/** * Process the payment and return the result **/ function process_payment($order_id) { global $woocommerce; $order = new WC_Order($order_id); if (class_exists("WC_Subscriptions_Order") && WC_Subscriptions_Order::order_contains_subscription($order)) { // Charge sign up fee + first period here.. // Periodic charging should happen via scheduled_subscription_payment_fatzebra $amount = (int) (WC_Subscriptions_Order::get_total_initial_payment($order) * 100); } else { $amount = (int) ($order->order_total * 100); } $page_url = $this->parent_settings["sandbox_mode"] == "yes" ? $this->sandbox_paynow_url : $this->live_paynow_url; $_SESSION['masterpass_order_id'] = $order_id; $username = $this->parent_settings["username"]; $currency = $order->get_order_currency(); $reference = (string) $order_id; $return_args = array('wc-api' => 'WC_FatZebra_MasterPass', "echo[order_id]" => $order_id); if ($amount === 0) { $return_args["echo[tokenize]"] = true; } $return_path = str_replace('https:', 'http:', add_query_arg($return_args, home_url('/'))); $verification_string = implode(":", array($reference, $amount, $currency, $return_path)); $verification_value = hash_hmac("md5", $verification_string, $this->settings["shared_secret"]); $redirect = "{$page_url}/{$username}/{$reference}/{$currency}/{$amount}/{$verification_value}?masterpass=true&iframe=true&return_path=" . urlencode($return_path); if ($amount === 0) { $redirect .= "&tokenize_only=true"; } $result = array('result' => 'success', 'redirect' => $redirect); return $result; }
/** * Adds a renewal orders section to the Related Orders meta box displayed on subscription orders. * * @since 1.4 */ public static function renewal_orders_meta_box_section($order, $post) { if (self::is_renewal($order, array('order_role' => 'child'))) { $parent_id = self::get_parent_order_id($order); } elseif (WC_Subscriptions_Order::order_contains_subscription($order)) { $parent_id = $order->id; } //Find any renewal orders associated with this order. $items = get_posts(array('post_type' => $post->post_type, 'post_parent' => $parent_id, 'numberposts' => -1)); if (self::is_renewal($order, array('order_role' => 'child'))) { $parent_order = new WC_Order($parent_id); printf('<p>%1$s <a href="%2$s">%3$s</a></p>', __('Initial Order:', 'woocommerce-subscriptions'), get_edit_post_link($parent_id), $parent_order->get_order_number()); } elseif (self::is_renewal($order, array('order_role' => 'parent'))) { $original_order_id = WC_Subscriptions_Order::get_meta($order, 'original_order', false); $original_order = new WC_Order($original_order_id); printf('<p>%1$s <a href="%2$s">%3$s</a></p>', __('Renewal of Subscription Purchased in Order:', 'woocommerce-subscriptions'), get_edit_post_link($original_order_id), $original_order->get_order_number()); } else { $original_order_post = get_posts(array('meta_key' => '_original_order', 'meta_value' => $parent_id, 'post_parent' => 0, 'post_type' => 'shop_order')); if (!empty($original_order_post) && isset($original_order_post[0])) { $original_order = new WC_Order($original_order_post[0]->ID); printf('<p>%1$s <a href="%2$s">%3$s</a></p>', __('Superseeded by Subscription Purchased in Order:', 'woocommerce-subscriptions'), get_edit_post_link($original_order->id), $original_order->get_order_number()); } } if (empty($items)) { printf(' <p class="renewal-subtitle">%s</p>', __('No renewal payments yet.', 'woocommerce-subscriptions')); } else { printf('<p class="renewal-subtitle">%s</p>', __('Renewal Orders:', 'woocommerce-subscriptions')); echo '<ul class="renewal-orders">'; foreach ($items as $item) { $renewal_order = new WC_Order($item->ID); if ($item->ID == $post->ID) { printf('<li><strong>%s</strong></li>', $renewal_order->get_order_number()); } else { printf('<li><a href="%1$s">%2$s</a></li>', get_edit_post_link($item->ID), $renewal_order->get_order_number()); } } echo '</ul>'; } }
/** * 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_Order::is_item_subscription($order, $order_item)) { self::trash_subscription($order->customer_user, self::get_subscription_key($order->id, WC_Subscriptions_Order::get_items_product_id($order_item))); } } } }
/** * Change the send date of the email for 'before_renewal' and 'before_expire' triggers * @param array $insert * @param FUE_Email $email * @return array */ public function modify_insert_send_date($insert, $email) { if ($email->type != 'subscription') { return $insert; } $order_id = $insert['order_id']; $order = WC_FUE_Compatibility::wc_get_order($order_id); if (!WC_Subscriptions_Order::order_contains_subscription($order)) { return $insert; } $subs_key = WC_Subscriptions_Manager::get_subscription_key($order_id); if ($email->trigger == 'subs_before_renewal') { $renewal_date = WC_Subscriptions_Manager::get_next_payment_date($subs_key); if (!$renewal_date) { // return false to tell FUE to skip importing this email/order return false; } // convert to local time $local_renewal_date = get_date_from_gmt($renewal_date, 'U'); $add = FUE_Sending_Scheduler::get_time_to_add($email->interval, $email->duration); $insert['send_on'] = $local_renewal_date - $add; } elseif ($email->trigger == 'subs_before_expire') { $expiry_date = WC_Subscriptions_Manager::get_subscription_expiration_date($subs_key); if (!$expiry_date) { return false; } // convert to local time $expiry_timestamp = get_date_from_gmt($expiry_date, 'U'); $add = FUE_Sending_Scheduler::get_time_to_add($email->interval, $email->duration); $insert['send_on'] = $expiry_timestamp - $add; } // Add the subscription key if it is not present in the meta if (!isset($insert['meta']) || empty($insert['meta']['subs_key'])) { $insert['meta']['subs_key'] = $subs_key; } return $insert; }
/** * 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 . '">'; }
/** * 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); } }
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; } }
/** * Check if order contains subscriptions. * * @param int $order_id * @return bool */ protected function order_contains_subscription($order_id) { return class_exists('WC_Subscriptions_Order') && (WC_Subscriptions_Order::order_contains_subscription($order_id) || WC_Subscriptions_Renewal_Order::is_renewal($order_id)); }