/** * 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 subscription * * @param int $order_id * @return array */ public function process_subscription($order_id) { $order = wc_get_order($order_id); $token = isset($_POST['simplify_token']) ? wc_clean($_POST['simplify_token']) : ''; try { if (empty($token)) { $error_msg = __('Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'woocommerce'); if ('yes' == $this->sandbox) { $error_msg .= ' ' . __('Developers: Please make sure that you\'re including jQuery and there are no JavaScript errors on the page.', 'woocommerce'); } throw new Simplify_ApiException($error_msg); } // Create customer $customer = Simplify_Customer::createCustomer(array('token' => $token, 'email' => $order->billing_email, 'name' => trim($order->billing_first_name . ' ' . $order->billing_last_name), 'reference' => $order->id)); if (is_object($customer) && '' != $customer->id) { $customer_id = wc_clean($customer->id); // Store the customer ID in the order update_post_meta($order_id, '_simplify_customer_id', $customer_id); } else { $error_msg = __('Error creating user in Simplify Commerce.', 'woocommerce'); throw new Simplify_ApiException($error_msg); } $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 WC()->cart->empty_cart(); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } catch (Simplify_ApiException $e) { if ($e instanceof Simplify_BadRequestException && $e->hasFieldErrors() && $e->getFieldErrors()) { foreach ($e->getFieldErrors() as $error) { wc_add_notice($error->getFieldName() . ': "' . $error->getMessage() . '" (' . $error->getErrorCode() . ')', 'error'); } } else { wc_add_notice($e->getMessage(), 'error'); } return array('result' => 'fail', 'redirect' => ''); } }
/** * Process the subscription * * @param int $order_id * @return array */ public function process_subscription($order_id) { $order = new WC_Order($order_id); if ($this->sandbox == 'yes') { $error_msg .= ' ' . __('Developers: Please make sure that you\'re including jQuery and there are no JavaScript errors on the page.', 'woocommerce-payment-gateway-boilerplate'); } $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 WC()->cart->empty_cart(); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } 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); 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)); }
/** * Records a payment on a subscription. * * @param int $user_id The id of the user who owns the subscription. * @param string $subscription_key A subscription key of the form obtained by @see get_subscription_key( $order_id, $product_id ) * @since 1.0 */ public static function process_subscription_payment($user_id, $subscription_key) { // Store a record of the subscription payment date $subscription = self::get_subscription($subscription_key); $subscription['completed_payments'][] = gmdate('Y-m-d H:i:s'); // Reset failed payment count & suspension count $subscription['failed_payments'] = $subscription['suspension_count'] = 0; self::update_users_subscriptions($user_id, array($subscription_key => $subscription)); // Make sure subscriber is marked as a "Paying Customer" self::mark_paying_customer($subscription['order_id']); // Make sure subscriber has default role self::update_users_role($user_id, 'default_subscriber_role'); // Log payment on order $order = new WC_Order($subscription['order_id']); $item = WC_Subscriptions_Order::get_item_by_product_id($order, $subscription['product_id']); // Free trial & no-signup fee, no payment received if (0 == WC_Subscriptions_Order::get_total_initial_payment($order) && 1 == count($subscription['completed_payments'])) { if (WC_Subscriptions_Order::requires_manual_renewal($subscription['order_id'])) { $order_note = sprintf(__('Free trial commenced for subscription "%s"', 'woocommerce-subscriptions'), $item['name']); } else { $order_note = sprintf(__('Recurring payment authorized for subscription "%s"', 'woocommerce-subscriptions'), $item['name']); } } else { $order_note = sprintf(__('Payment received for subscription "%s"', 'woocommerce-subscriptions'), $item['name']); } $order->add_order_note($order_note); do_action('processed_subscription_payment', $user_id, $subscription_key); }
/** * Outputs the content for each column. * * @param array $item A singular item (one full row's worth of data) * @param array $column_name The name/slug of the column to be processed * @return string Text or HTML to be placed inside the column <td> * @since 1.0 */ public function column_default($item, $column_name) { global $woocommerce; $current_gmt_time = gmdate('U'); $column_content = ''; switch ($column_name) { case 'status': $actions = array(); $action_url = add_query_arg(array('page' => $_REQUEST['page'], 'user' => $item['user_id'], 'subscription' => $item['subscription_key'], '_wpnonce' => wp_create_nonce($item['subscription_key']))); if (isset($_REQUEST['status'])) { $action_url = add_query_arg(array('status' => $_REQUEST['status']), $action_url); } $order = new WC_Order($item['order_id']); $all_statuses = array('active' => __('Reactivate', 'woocommerce-subscriptions'), 'on-hold' => __('Suspend', 'woocommerce-subscriptions'), 'cancelled' => __('Cancel', 'woocommerce-subscriptions'), 'trash' => __('Trash', 'woocommerce-subscriptions'), 'deleted' => __('Delete Permanently', 'woocommerce-subscriptions')); foreach ($all_statuses as $status => $label) { if (WC_Subscriptions_Manager::can_subscription_be_changed_to($status, $item['subscription_key'], $item['user_id'])) { $action = 'deleted' == $status ? 'delete' : $status; // For built in CSS $actions[$action] = sprintf('<a href="%s">%s</a>', esc_url(add_query_arg('new_status', $status, $action_url)), $label); } } if ($item['status'] == 'pending') { unset($actions['active']); unset($actions['trash']); } elseif (!in_array($item['status'], array('cancelled', 'expired', 'switched', 'suspended'))) { unset($actions['trash']); } $actions = apply_filters('woocommerce_subscriptions_list_table_actions', $actions, $item); $column_content = sprintf('<mark class="%s">%s</mark> %s', sanitize_title($item[$column_name]), WC_Subscriptions_Manager::get_status_to_display($item[$column_name], $item['subscription_key'], $item['user_id']), $this->row_actions($actions)); $column_content = apply_filters('woocommerce_subscriptions_list_table_column_status_content', $column_content, $item, $actions, $this); break; case 'title': //Return the title contents $column_content = sprintf('<a href="%s">%s</a>', get_edit_post_link($item['product_id']), WC_Subscriptions_Order::get_item_name($item['order_id'], $item['product_id'])); $order = new WC_Order($item['order_id']); $order_item = WC_Subscriptions_Order::get_item_by_product_id($order, $item['product_id']); $product = $order->get_product_from_item($order_item); if (isset($product->variation_data)) { $column_content .= '<br />' . woocommerce_get_formatted_variation($product->variation_data, true); } break; case 'order_id': $order = new WC_Order($item[$column_name]); $column_content = sprintf('<a href="%1$s">%2$s</a>', get_edit_post_link($item[$column_name]), sprintf(__('Order %s', 'woocommerce-subscriptions'), $order->get_order_number())); break; case 'user': $user = get_user_by('id', $item['user_id']); if (is_object($user)) { $column_content = sprintf('<a href="%s">%s</a>', admin_url('user-edit.php?user_id=' . $user->ID), ucfirst($user->display_name)); } break; case 'start_date': case 'expiry_date': case 'end_date': if ($column_name == 'expiry_date' && $item[$column_name] == 0) { $column_content = __('Never', 'woocommerce-subscriptions'); } else { if ($column_name == 'end_date' && $item[$column_name] == 0) { $column_content = __('Not yet ended', 'woocommerce-subscriptions'); } else { $gmt_timestamp = strtotime($item[$column_name]); $user_timestamp = $gmt_timestamp + get_option('gmt_offset') * 3600; $column_content = sprintf('<time>%s</time>', date_i18n(woocommerce_date_format(), $user_timestamp)); } } break; case 'trial_expiry_date': $trial_expiration = WC_Subscriptions_Manager::get_trial_expiration_date($item['subscription_key'], $item['user_id'], 'timestamp'); if (empty($trial_expiration)) { $column_content = '-'; } else { $column_content = sprintf('<time title="%s">%s</time>', esc_attr($trial_expiration), date_i18n(woocommerce_date_format(), $trial_expiration + get_option('gmt_offset') * 3600)); } break; case 'last_payment_date': // Although we record the sign-up date as a payment, if there is a free trial and no sign-up fee, no payment is actually charged if (0 == WC_Subscriptions_Order::get_total_initial_payment($item['order_id']) && 1 == count($item['completed_payments'])) { $column_content = '-'; } else { $last_payment_timestamp = strtotime($item['last_payment_date']); $time_diff = $current_gmt_time - $last_payment_timestamp; if ($time_diff > 0 && $time_diff < 7 * 24 * 60 * 60) { $last_payment = sprintf(__('%s ago', 'woocommerce-subscriptions'), human_time_diff($last_payment_timestamp, $current_gmt_time)); } else { $last_payment = date_i18n(woocommerce_date_format(), $last_payment_timestamp + get_option('gmt_offset') * 3600); } $column_content = sprintf('<time title="%s">%s</time>', esc_attr($last_payment_timestamp), $last_payment); } break; case 'next_payment_date': $next_payment_timestamp_gmt = WC_Subscriptions_Manager::get_next_payment_date($item['subscription_key'], $item['user_id'], 'timestamp'); $next_payment_timestamp = $next_payment_timestamp_gmt + get_option('gmt_offset') * 3600; if ($next_payment_timestamp_gmt == 0) { $column_content = '-'; } else { // Convert to site time $time_diff = $next_payment_timestamp_gmt - $current_gmt_time; if ($time_diff > 0 && $time_diff < 7 * 24 * 60 * 60) { $next_payment = sprintf(__('In %s', 'woocommerce-subscriptions'), human_time_diff($current_gmt_time, $next_payment_timestamp_gmt)); } else { $next_payment = date_i18n(woocommerce_date_format(), $next_payment_timestamp); } $column_content = sprintf('<time class="next-payment-date" title="%s">%s</time>', esc_attr($next_payment_timestamp), $next_payment); if (WC_Subscriptions_Manager::can_subscription_be_changed_to('new-payment-date', $item['subscription_key'], $item['user_id'])) { $column_content .= '<div class="edit-date-div row-actions hide-if-no-js">'; $column_content .= '<img class="date-picker-icon" src="' . admin_url('images/date-button.gif') . '" title="' . __('Date Picker Icon', 'woocommerce-subscriptions') . '" />'; $column_content .= '<a href="#edit_timestamp" class="edit-timestamp" tabindex="4">' . __('Change', 'woocommerce-subscriptions') . '</a>'; $column_content .= '<div class="date-picker-div hide-if-js">'; $column_content .= WC_Subscriptions_Manager::touch_time(array('date' => date('Y-m-d', $next_payment_timestamp), 'echo' => false, 'multiple' => true, 'include_time' => false)); $column_content .= '</div>'; $column_content .= '</div>'; } } break; case 'renewal_order_count': $count = WC_Subscriptions_Renewal_Order::get_renewal_order_count($item['order_id']); $column_content = sprintf('<a href="%1$s">%2$d</a>', admin_url('edit.php?post_status=all&post_type=shop_order&_renewal_order_parent_id=' . absint($item['order_id'])), $count); break; } return apply_filters('woocommerce_subscriptions_list_table_column_content', $column_content, $item, $column_name); }
/** * Adds subscriptions data to the order object * * @since 1.0 * @see SV_WC_Payment_Gateway::get_order() * @param WC_Order $order the order * @return WC_Order the orders */ public function subscriptions_get_order($order) { // bail if the gateway doesn't support subscriptions or the order doesn't contain a subscription if (!$this->supports_subscriptions() || !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 = number_format((double) WC_Subscriptions_Order::get_total_initial_payment($order), 2, '.', ''); // load any required members that we might not have if (!isset($order->payment->token) || !$order->payment->token) { $order->payment->token = get_post_meta($order->id, '_wc_' . $this->get_id() . '_payment_token', true); } if (!isset($order->customer_id) || !$order->customer_id) { $order->customer_id = get_post_meta($order->id, '_wc_' . $this->get_id() . '_customer_id', true); } // ensure the payment token is still valid if (!$this->has_payment_token($order->user_id, $order->payment->token)) { $order->payment->token = null; } else { // get the token object $token = $this->get_payment_token($order->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->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->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; }
/** * Filters WC_Subscriptions_Order::get_sign_up_fee() to make sure the sign-up fee for a subscription product * that is synchronised is returned correctly. * * @param float The initial sign-up fee charged when the subscription product in the order was first purchased, if any. * @param mixed $order A WC_Order object or the ID of the order which the subscription was purchased in. * @param int $product_id The post ID of the subscription WC_Product object purchased in the order. Defaults to the ID of the first product purchased in the order. * @return float The initial sign-up fee charged when the subscription product in the order was first purchased, if any. * @since 1.5.3 * @deprecated 2.0 */ public static function get_sign_up_fee($sign_up_fee, $order, $product_id, $non_subscription_total) { _deprecated_function(__METHOD__, '2.0', __CLASS__ . '::get_synced_sign_up_fee'); if ('shop_order' == get_post_type($order) && self::order_contains_synced_subscription($order->id) && WC_Subscriptions_Order::get_subscription_trial_length($order) < 1) { $sign_up_fee = max(WC_Subscriptions_Order::get_total_initial_payment($order) - $non_subscription_total, 0); } return $sign_up_fee; }
/** * Set up the charge that will be sent to Stripe * * @access private * @return void */ private function charge_set_up() { global $s4wc; // Add a customer or retrieve an existing one $customer = $this->get_customer(); $customer_info = get_user_meta($this->order->user_id, $s4wc->settings['stripe_db_location'], true); // Update default card if ($this->form_data['chosen_card'] !== 'new') { $default_card = $customer_info['cards'][intval($this->form_data['chosen_card'])]['id']; S4WC_DB::update_customer($this->order->user_id, array('default_card' => $default_card)); } $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($this->order); $charge = $this->process_subscription_payment($initial_payment); $this->charge = $charge; $this->transaction_id = $charge->id; }
/** * 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. * * 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; }
/** * callback_handler function. * * Is called after a payment has been submitted in the QuickPay payment window. * * @access public * @return void */ public function callback_handler() { $request_body = file_get_contents("php://input"); $json = json_decode($request_body); $payment = new WC_QuickPay_API_Payment($request_body); if ($payment->is_authorized_callback($request_body)) { // Fetch order number; $order_number = WC_QuickPay_Order::get_order_id_from_callback($json); // Instantiate order object $order = new WC_QuickPay_Order($order_number); // Get last transaction in operation history $transaction = end($json->operations); // Is the transaction accepted? if ($json->accepted) { // Add order transaction fee $order->add_transaction_fee($transaction->amount); // Perform action depending on the operation status type try { switch ($transaction->type) { // // Cancel callbacks are currently not supported by the QuickPay API // case 'cancel': if (WC_QuickPay_Helper::subscription_is_active()) { if ($order->contains_subscription()) { WC_Subscriptions_Manager::cancel_subscriptions_for_order($order->id); } } // Write a note to the order history $order->note(__('Payment cancelled.', 'woo-quickpay')); break; case 'capture': // Write a note to the order history $order->note(__('Payment captured.', 'woo-quickpay')); break; case 'refund': $order->note(sprintf(__('Refunded %s %s', 'woo-quickpay'), WC_QuickPay_Helper::price_normalize($transaction->amount), $json->currency)); break; case 'authorize': // Set the transaction ID $order->set_transaction_id($json->id); // Set the transaction order ID $order->set_transaction_order_id($json->order_id); // Remove payment link $order->delete_payment_link(); // Remove payment ID, now we have the transaction ID $order->delete_payment_id(); // Subscription authorization if (isset($json->type) and strtolower($json->type) == 'subscription') { // Create subscription instance $subscription = new WC_QuickPay_API_Subscription($request_body); // Write log $order->note(sprintf(__('Subscription authorized. Transaction ID: %s', 'woo-quickpay'), $json->id)); // If 'capture first payment on subscription' is enabled if (WC_QuickPay_Helper::option_is_enabled($this->s('quickpay_autodraw_subscription'))) { // Check if there is an initial payment on the subscription $subscription_initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order); // Only make an instant payment if there is an initial payment if ($subscription_initial_payment > 0) { // New subscription instance $subscription = new WC_QuickPay_API_Subscription(); // Perform API recurring payment request $recurring = $subscription->recurring($json->id, $order, $subscription_initial_payment); // Process the recurring response data WC_QuickPay_API_Subscription::process_recurring_response($recurring, $order); } } } else { // Write a note to the order history $order->note(sprintf(__('Payment authorized. Transaction ID: %s', 'woo-quickpay'), $json->id)); } // Register the payment on the order $order->payment_complete(); break; } } catch (QuickPay_API_Exception $e) { $e->write_to_logs(); } } else { // Write debug information $this->log->separator(); $this->log->add(sprintf(__('Transaction failed for #%s.', 'woo-quickpay'), $order_number)); $this->log->add(sprintf(__('QuickPay status code: %s.', 'woo-quickpay'), $transaction->qp_status_code)); $this->log->add(sprintf(__('QuickPay status message: %s.', 'woo-quickpay'), $transaction->qp_status_msg)); $this->log->add(sprintf(__('Acquirer status code: %s', 'woo-quickpay'), $transaction->aq_status_code)); $this->log->add(sprintf(__('Acquirer status message: %s', 'woo-quickpay'), $transaction->aq_status_msg)); $this->log->separator(); // Update the order statuses if ($transaction->type == 'subscribe' or $transaction->type == 'recurring') { WC_Subscriptions_Manager::process_subscription_payment_failure_on_order($order); } else { $order->update_status('failed'); } } } else { $this->log->add(sprintf(__('Invalid callback body for order #%s.', 'woo-quickpay'), $order_number)); } }
/** * 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 subscription * * @param int $order_id * @return array */ public function process_subscription($order_id, $retry = true) { $order = new WC_Order($order_id); $stripe_token = isset($_POST['stripe_token']) ? wc_clean($_POST['stripe_token']) : ''; $card_id = isset($_POST['stripe_card_id']) ? wc_clean($_POST['stripe_card_id']) : ''; $customer_id = is_user_logged_in() ? get_user_meta(get_current_user_id(), '_stripe_customer_id', true) : 0; if (!$customer_id || !is_string($customer_id)) { $customer_id = 0; } // Use Stripe CURL API for payment try { $post_data = array(); // Pay using a saved card! if ($card_id !== 'new' && $card_id && $customer_id) { $post_data['customer'] = $customer_id; $post_data['card'] = $card_id; } elseif (empty($stripe_token)) { $error_msg = __('Please make sure your card details have been entered correctly and that your browser supports JavaScript.', 'woocommerce-gateway-stripe'); if ($this->testmode) { $error_msg .= ' ' . __('Developers: Please make sure that you are including jQuery and there are no JavaScript errors on the page.', 'woocommerce-gateway-stripe'); } throw new Exception($error_msg); } // Save token if (!$customer_id) { $customer_id = $this->add_customer($order, $stripe_token); if (is_wp_error($customer_id)) { throw new Exception($customer_id->get_error_message()); } unset($post_data['card']); $post_data['customer'] = $customer_id; } elseif (!$card_id || $card_id === 'new') { $card_id = $this->add_card($customer_id, $stripe_token); if (is_wp_error($card_id)) { // Customer param wrong? The user may have been deleted on stripe's end. Remove customer_id and retry. if ('customer' === $card_id->get_error_code() && $retry) { delete_user_meta(get_current_user_id(), '_stripe_customer_id'); return $this->process_subscription($order_id, false); // false to prevent retry again (endless loop) } throw new Exception($card_id->get_error_message()); } $post_data['card'] = $card_id; $post_data['customer'] = $customer_id; } // Store the ID in the order update_post_meta($order_id, '_stripe_customer_id', $customer_id); update_post_meta($order_id, '_stripe_card_id', $card_id); $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 { if (isset($payment_response->balance_transaction) && isset($payment_response->balance_transaction->fee)) { $fee = number_format($payment_response->balance_transaction->fee / 100, 2, '.', ''); update_post_meta($order->id, 'Stripe Fee', $fee); update_post_meta($order->id, 'Net Revenue From Stripe', $order->order_total - $fee); } // Payment complete $order->payment_complete($payment_response->id); // Remove cart WC()->cart->empty_cart(); // Activate subscriptions WC_Subscriptions_Manager::activate_subscriptions_for_order($order); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } } catch (Exception $e) { wc_add_notice(__('Error:', 'woocommerce-gateway-stripe') . ' "' . $e->getMessage() . '"', 'error'); return; } }
/** * 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; }
/** * Calculate the maximum amount that can be charged throughout the life of a subscription. Amazon displays this * to the customer when they're authorizing their payment. * * @since 2.0 * @param WC_Order $order the WC order object * @return float the maximum total amount that can be charged, rounded to the nearest whole number */ private function calculate_lifetime_subscription_total(WC_Order $order) { // start with the total initial payment, which includes any sign up fee or one-off shipping/tax charge $total = WC_Subscriptions_Order::get_total_initial_payment($order); // add the total from all the recurring periods if (WC_Subscriptions_Order::get_subscription_length($order) > 0) { $total += WC_Subscriptions_Order::get_recurring_total($order) * WC_Subscriptions_Order::get_subscription_length($order); // If a subscription never ends, use 5 years worth of recurring charges as a sensible maximum } else { // first get the subscription period in year terms switch (WC_Subscriptions_Order::get_subscription_period($order)) { case 'day': $period = 365; break; case 'week': $period = 52; break; case 'month': $period = 12; break; case 'year': $period = 1; break; default: $period = 1; break; } // divide by the interval (e.g. recurs every Xth week) $period = $period / WC_Subscriptions_Order::get_subscription_interval($order); // multiply by recurring total per period by the number of periods in a year by 5 years to get the total $total += WC_Subscriptions_Order::get_recurring_total($order) * $period * 5; } // finally increase by 25% to account for price increases / upgrades $total *= 1.25; /** * Round to whole number and allow an entirely different total to be set * * @since 2.0 * @param float $lifetime_subscription_total the total amount that may be charged, as shown to the customer during checkout @ Amazon * @param WC_Order $order the WC Order object */ return apply_filters('wc_amazon_fps_lifetime_subscription_total', round($total, 0), $order); }
/** * Process the payment and return the result **/ function process_payment($order_id) { global $woocommerce; $this->params["customer_ip"] = $this->get_customer_real_ip(); $defer_payment = $this->parent_settings["deferred_payments"] == "yes"; $test_mode = $this->parent_settings["test_mode"] == "yes"; $order = new WC_Order($order_id); $this->params["currency"] = $order->get_order_currency(); if (class_exists("WC_Subscriptions_Order") && WC_Subscriptions_Order::order_contains_subscription($order)) { // No deferred payments for subscriptions. $defer_payment = false; // Charge sign up fee + first period here.. // Periodic charging should happen via scheduled_subscription_payment_fatzebra $this->params["amount"] = (int) (WC_Subscriptions_Order::get_total_initial_payment($order) * 100); } else { $this->params["amount"] = (int) ($order->order_total * 100); } $this->params["reference"] = (string) $order_id; $this->params["test"] = $test_mode; $this->params["deferred"] = $defer_payment; $this->params["wallet"] = array("type" => "VISA", "callid" => $_POST['callid']); if (isset($_POST['token'])) { $this->params['card_token'] = $_POST['token']; } if ($this->parent_settings['fraud_data'] == 'yes') { $fz_base = new WC_FatZebra(); $fraud_data = $fz_base->get_fraud_payload($order); $this->params['fraud'] = $fraud_data; } if ($this->params["amount"] === 0) { $result = $this->tokenize_card($this->params); } else { $result = $this->do_payment($this->params); } if (is_wp_error($result)) { switch ($result->get_error_code()) { case 1: // Non-200 response, so failed... (e.g. 401, 403, 500 etc). $order->add_order_note($result->get_error_message()); wc_add_notice($result->get_error_message(), 'error'); break; case 2: // Gateway error (data etc) $errors = $result->get_error_data(); foreach ($errors as $error) { $order->add_order_note("Gateway Error: " . $error); } error_log("WooCommerce Fat Zebra - Gateway Error: " . print_r($errors, true)); wc_add_notice("Payment Failed: " . implode(", ", $errors), 'error'); break; case 3: // Declined - error data is array with keys: message, id $order->add_order_note(__("Payment Declined: " . $this->response_data->response->message . ". Reference: " . $this->response_data->response->transaction_id)); wc_add_notice("Payment declined: " . $this->response_data->response->message, 'error'); if (isset($this->response_data->response->fraud_result) && !empty($this->response_data->response->fraud_result)) { if ($this->response_data->response->fraud_result == 'Accept') { $order->add_order_note("Fraud Check Result: Accept"); } else { $order->add_order_note("Fraud Check Result: " . $this->response_data->response->fraud_result . " - " . implode(", ", $this->response_data->response->fraud_messages)); } } break; case 4: // Exception caught, something bad happened. Data is exception // Exception caught, something bad happened. Data is exception default: wc_add_notice("Unknown error.", 'error'); $order->add_order_note(__("Unknown Error (exception): " . print_r($result->get_error_data(), true))); break; } return; } else { // Success! Returned is an array with the transaction ID etc // For a deferred payment we set the status to on-hold and then add a detailed note for review. if ($defer_payment) { $date = new DateTime($result["card_expiry"], new DateTimeZone("Australia/Sydney")); $note = "Deferred Payment:<ul><li>Card Token: " . $result["card_token"] . "</li><li>Card Holder: " . $result["card_holder"] . "</li><li>Card Number: " . $result["card_number"] . "</li><li>Expiry: " . $date->format("m/Y") . "</li></ul>"; $order->update_status("on-hold", $note); update_post_meta($order_id, "_fatzebra_card_token", $result["card_token"]); update_post_meta($order_id, "fatzebra_card_token", $result["card_token"]); } else { if ($this->params["amount"] === 0) { $order->add_order_note(__("Fat Zebra payment complete - \$0 initial amount, card tokenized. Card token: " . $result["card_token"])); } else { $order->add_order_note(__("Fat Zebra payment complete. Reference: " . $result["transaction_id"])); } if (isset($this->response_data->response->fraud_result) && !empty($this->response_data->response->fraud_result)) { if ($this->response_data->response->fraud_result == 'Accept') { $order->add_order_note("Fraud Check Result: Accept"); } else { $order->add_order_note("Fraud Check Result: " . $this->response_data->response->fraud_result . " - " . implode(", ", $this->response_data->response->fraud_messages)); } } $order->payment_complete($result['transaction_id']); // Clear the session values $this->clear_visa_checkout_session_values(); // Store the card token as post meta update_post_meta($order_id, "_fatzebra_card_token", $result["card_token"]); update_post_meta($order_id, "fatzebra_card_token", $result["card_token"]); } $woocommerce->cart->empty_cart(); return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } }
/** * Process initial payment for a subscription * * @since 2.0 * @param \WC_Order $order the order object * @return array */ private function process_subscription_payment($order) { // get subscription amount $order->braintree_order['amount'] = WC_Subscriptions_Order::get_total_initial_payment($order); // create new braintree customer if needed if (empty($order->braintree_order['customerId'])) { $order = $this->create_customer($order); } // save card in vault if customer is using new card if (empty($order->braintree_order['paymentMethodToken'])) { $order = $this->create_credit_card($order); } else { // save payment token to order when processing $0 total subscriptions (e.g. those with a free trial) if (0 == $order->braintree_order['amount']) { update_post_meta($order->id, '_wc_braintree_cc_token', $order->braintree_order['paymentMethodToken']); } } // process transaction (the order amount will be $0 if a free trial exists) // note that customer ID & credit card token are saved to order when create_customer() or create_credit_card() are called if (0 == $order->braintree_order['amount'] || $this->do_transaction($order)) { // mark order as having received payment $order->payment_complete(); SV_WC_Plugin_Compatibility::WC()->cart->empty_cart(); return array('result' => 'success', 'redirect' => $this->get_return_url($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) && '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; } } $sign_up_fee = WC_Subscriptions_Order::get_sign_up_fee($order); $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($order); $price_per_period = WC_Subscriptions_Order::get_recurring_total($order); $subscription_interval = WC_Subscriptions_Order::get_subscription_interval($order); $subscription_installments = WC_Subscriptions_Order::get_subscription_length($order) / $subscription_interval; $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; // 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']; } 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; } } // Force return URL so that order description & instructions display $paypal_args['rm'] = 2; } return $paypal_args; }
/** * Relay response - handles response from NAB Transact CRN * At this stage we've just added a CRN record, and now we must process the payment to this CRN * * @since 1.2.0 */ function relay_response_crn() { global $woocommerce; // Process response $response = new stdClass; foreach ($_GET as $key => $value) { $response->$key = $value; } foreach ($_POST as $key => $value) { $response->$key = $value; } if ( ! empty( $response->order ) ) { $order = new WC_Order( (int) $response->order ); if ((!isset($response->afrescode) || $response->afrescode=='400' || $response->afrescode=='000') && ($response->rescode == '00' || $response->rescode == '08' || $response->rescode == '11')) { // Approved if ($order->key_is_valid( $response->key ) && $order->status != 'completed' && $order->status != 'processing') { // Save CRN to order meta also $this->save_subscription_meta( (int)$response->order , $response->CRN); // Add Order Note $order->add_order_note(__('Credit card details stored.','wc-nab')); if (!function_exists('wcs_get_subscriptions_for_order')) { $amount = WC_Subscriptions_Order::get_total_initial_payment($order); } else { $amount = $order->get_total(); } if (isset($response->is_payment_change) && $response->is_payment_change == '1' && get_post_meta($order->id,'_is_mid_change_method',true)) { $amount = 0; delete_post_meta($order->id,'_is_mid_change_method',true); } if ($amount == 0) { $order->payment_complete(); } else { // Now to process payment, but only if it hasn't already been done // (this url is used by result AND return) if ($order->status != 'completed') { $data = array( 'crn'=>$response->CRN, 'amountcents'=>($amount*100), 'reference'=>substr(urlencode($response->order.'-'.$order->order_key),0,32), 'currency'=>get_woocommerce_currency()); $payment_xml = $this->generatePaymentXMLMessage($data); $payment_result = $this->send($payment_xml,$this->xmlapiurl,true); $result_object = simplexml_load_string($payment_result); if ($result_object->Periodic->PeriodicList->PeriodicItem->responseCode == '00' || $result_object->Periodic->PeriodicList->PeriodicItem->responseCode == '08' || $result_object->Periodic->PeriodicList->PeriodicItem->responseCode == '11') { // Payment success! $order->add_order_note(sprintf(__("NAB Transaction id: %s\r\nNAB Settlement date: %s",'wc-nab'),$result_object->Periodic->PeriodicList->PeriodicItem->txnID,$result_object->Periodic->PeriodicList->PeriodicItem->settlementDate)); $order->payment_complete((string)$result_object->Periodic->PeriodicList->PeriodicItem->txnID); // Remove cart $woocommerce->cart->empty_cart(); } else { if ($order->status != 'completed' && $order->status != 'processing') { $order->update_status( 'failed', sprintf(__("NAB error whilst processing payment via XML API using CRN: code %s - %s.", 'wc-nab'), $result_object->Status->statusCode, $result_object->Status->statusDescription) ); } } } } } else { // payment received but order key didn't match! // Key did not match order id $order->add_order_note( sprintf(__('Payment received, but order ID did not match key: code %s - %s.', 'wc-nab'), $response->response_code, $response->response_reason_text ) ); // Put on hold if pending if ($order->status == 'pending' || $order->status == 'failed') { $order->update_status( 'on-hold' ); } } } else { // Transaction failed if ($order->status != 'completed' && $order->status != 'processing') { $order->update_status( 'failed', sprintf(__("NAB error whilst adding CRN: code %s - %s. PAYMENT NOT PROCESSED!", 'wc-nab'), $response->rescode, $response->restext) ); } } // It's possible we just processed a change of payment method, not a proper order // so we might want to just go back to the My Account page if (isset($_GET['is_payment_change']) && $_GET['is_payment_change'] == '1') { wp_redirect(get_permalink( woocommerce_get_page_id( 'myaccount' ) )); } else { wp_redirect( $this->get_return_url( $order ) ); } exit; } wp_redirect( $this->get_return_url() ); exit; }
/** * Filters WC_Subscriptions_Order::get_sign_up_fee() to make sure the sign-up fee for a subscription product * that is synchronised is returned correctly. * * @param float The initial sign-up fee charged when the subscription product in the order was first purchased, if any. * @param mixed $order A WC_Order object or the ID of the order which the subscription was purchased in. * @param int $product_id The post ID of the subscription WC_Product object purchased in the order. Defaults to the ID of the first product purchased in the order. * @return float The initial sign-up fee charged when the subscription product in the order was first purchased, if any. * @since 1.5.3 */ public static function get_sign_up_fee($sign_up_fee, $order, $product_id, $non_subscription_total) { if (self::order_contains_synced_subscription($order->id) && WC_Subscriptions_Order::get_subscription_trial_length($order) < 1) { $sign_up_fee = max(WC_Subscriptions_Order::get_total_initial_payment($order) - $non_subscription_total, 0); } return $sign_up_fee; }
/** * 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>'; }
/** * 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); } }
/** * Send subscription form data to Stripe * Handles sending the charge to an existing customer, a new customer (that's logged in), or a guest * * @access protected * @return bool */ protected function subscription_to_stripe() { // Get the credit card details submitted by the form $form_data = $this->get_form_data(); // If there are errors on the form, don't bother sending to Stripe. if ($form_data['errors'] == 1) { return; } // Set up the charge for Stripe's servers try { // Add a customer or retrieve an existing one $description = $this->current_user->user_login . ' (#' . $this->current_user_id . ' - ' . $this->current_user->user_email . ') ' . $form_data['customer']['name']; // username (user_id - user_email) Full Name $customer = $this->get_customer($description, $form_data); // Update default card if ($form_data['chosen_card'] !== 'new') { $default_card = $this->stripe_customer_info['cards'][(int) $form_data['chosen_card']]['id']; S4WC_DB::update_customer($this->current_user_id, array('default_card' => $default_card)); } $initial_payment = WC_Subscriptions_Order::get_total_initial_payment($this->order); $charge = $this->process_subscription_payment($this->order, $initial_payment); $this->transaction_id = $charge->id; // Save data for the "Capture" update_post_meta($this->order->id, '_transaction_id', $this->transaction_id); update_post_meta($this->order->id, 'capture', strcmp($this->settings['charge_type'], 'authorize') == 0); // Save data for cross-reference between Stripe Dashboard and WooCommerce update_post_meta($this->order->id, 'customer_id', $customer['customer_id']); return true; } catch (Exception $e) { // Stop page reload if we have errors to show unset(WC()->session->reload_checkout); $message = $this->get_stripe_error_message($e); wc_add_notice(__('Subscription Error:', 'stripe-for-woocommerce') . ' ' . $message, 'error'); return false; } }