/** * Dispatch the email * * @since 1.0 */ public function trigger($args) { if (!empty($args)) { $defaults = array('order' => '', 'message' => ''); $args = wp_parse_args($args, $defaults); extract($args); if (!is_object($order)) { return; } $this->object = $order; $this->recipient = $this->object->billing_email; $this->message = $message; $this->availability_date = WC_Pre_Orders_Product::get_localized_availability_date(WC_Pre_Orders_Order::get_pre_order_product($this->object)); $this->find[] = '{order_date}'; $this->replace[] = date_i18n(woocommerce_date_format(), strtotime($this->object->order_date)); $this->find[] = '{release_date}'; $this->replace[] = $this->availability_date; $this->find[] = '{order_number}'; $this->replace[] = $this->object->get_order_number(); } if (!$this->is_enabled() || !$this->get_recipient()) { return; } $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments()); }
/** * Dispatch the email * * @since 1.0 */ public function trigger($order_id, $message) { if ($order_id) { $this->object = new WC_Order($order_id); $this->recipient = $this->object->billing_email; $this->message = $message; $this->find[] = '{order_date}'; $this->replace[] = date_i18n(woocommerce_date_format(), strtotime($this->object->order_date)); $this->find[] = '{release_date}'; $this->replace[] = WC_Pre_Orders_Product::get_localized_availability_date(WC_Pre_Orders_Order::get_pre_order_product($this->object)); $this->find[] = '{order_number}'; $this->replace[] = $this->object->get_order_number(); } if (!$this->is_enabled() || !$this->get_recipient()) { return; } $this->send($this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments()); }
/** * Process the pre-order. * * @param WC_Order $order * * @return array */ protected function process_pre_order($order_id) { if (WC_Pre_Orders_Order::order_requires_payment_tokenization($order_id)) { try { $order = new WC_Order($order_id); // Reduce stock levels $order->reduce_order_stock(); // Remove cart $this->api->empty_card(); // Is pre ordered! WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // 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' => ''); } } else { return parent::process_payment($order_id); } }
/** * Marks the order as being a pre order if it contains pre order products in * case an order gets added manually from the administration panel * * @since 1.0.4 * @param int $order_id id of the newly saved order * @return void */ public function check_manual_order_for_pre_order_products($order_id) { // Make sure we are in the administration panel and we're saving an order if (!is_admin() || !isset($_POST['post_type']) || 'shop_order' != $_POST['post_type']) { return; } $order = new WC_Order($order_id); // Check if the order hasn't been processed already if (WC_Pre_Orders_Order::order_contains_pre_order($order)) { return; } // Order has not been processed yet (or doesn't contain pre orders) $contains_pre_orders = false; foreach ($order->get_items() as $item) { if ('line_item' == $item['type']) { $product = get_product($item['item_meta']['_product_id'][0]); if ('yes' == $product->wc_pre_orders_enabled) { // Set correct flags for this order, making it a pre order update_post_meta($order_id, '_wc_pre_orders_is_pre_order', 1); update_post_meta($order_id, '_wc_pre_orders_when_charged', $product->wc_pre_orders_when_to_charge); return; } } } }
/** * Process the pre-order. * * @param WC_Order $order * * @return array */ protected function process_pre_order($order_id) { if (WC_Pre_Orders_Order::order_requires_payment_tokenization($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 pre-order 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); // Reduce stock levels $order->reduce_order_stock(); // Remove cart $this->api->empty_card(); // Is pre ordered! WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // 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' => ''); } } else { return parent::process_payment($order_id); } }
/** * Cancel a pre-orders by changing its order status / pre-order status to 'cancelled' * * @since 1.0 * @param int|WC_Order $order post IDs or order object to cancel the pre-order for * @param string $message an optional message to include in communications to the customer */ public static function cancel_pre_order($order, $message = '') { if (!is_object($order)) { $order = new WC_Order($order); } if (!self::can_pre_order_be_changed_to('cancelled', $order)) { return; } // update the pre-order status WC_Pre_Orders_Order::update_pre_order_status($order, 'cancelled', $message); // add 'cancelled' order note for admins $order->add_order_note(__('Pre-Order Cancelled', 'wc-pre-orders')); // update the order status $order->update_status('cancelled'); do_action('wc_pre_orders_pre_order_cancelled', $order, $message); }
?> <?php do_action('woocommerce_email_header', $email_heading); ?> <?php $availability_date_text = !empty($availability_date) ? sprintf(__(' on %s.', WC_Pre_Orders::TEXT_DOMAIN), $availability_date) : '.'; ?> <?php if (WC_Pre_Orders_Order::order_will_be_charged_upon_release($order)) { ?> <?php if (WC_Pre_Orders_Order::order_has_payment_token($order)) { echo "<p>" . sprintf(__("Your pre-order has been received. You will be automatically charged for your order via your selected payment method when your pre-order is released%s Your order details are shown below for your reference.", WC_Pre_Orders::TEXT_DOMAIN), $availability_date_text) . "</p>"; } else { echo "<p>" . sprintf(__("Your pre-order has been received. You will be prompted for payment for your order when your pre-order is released%s Your order details are shown below for your reference.", WC_Pre_Orders::TEXT_DOMAIN), $availability_date_text) . "</p>"; } } else { ?> <p><?php printf(__("Your pre-order has been received. You will be notified when your pre-order is released%s Your order details are shown below for your reference.", WC_Pre_Orders::TEXT_DOMAIN), $availability_date_text); ?> </p> <?php } ?>
/** * Automatically change the pre-order status when the order status changes * 1) Change the pre-order status to 'active' when the order status changes to 'pre-ordered' * 2) Change the pre-order status to 'active' when the order status changes to 'on-hold' -- this ensures the pre-orders using * a gateway that does not call WC_Order::payment_complete() like BACS or Cheque will still show on the 'Manage Pre-Orders' page * 3) Change the pre-order status to 'cancelled' when the order status changes to 'cancelled' and the order contains a pre-order * * @since 1.0 * @param int $order_id post ID of the order * @param string $old_order_status the prior order status * @param string $new_order_status the new order status */ public function auto_update_pre_order_status($order_id, $old_order_status, $new_order_status) { // change to 'active' when changing order status to 'pre-ordered' if ('pre-ordered' === $new_order_status) { $this->update_pre_order_status($order_id, 'active'); } // change to 'active when changing order status to on-hold if ('on-hold' === $new_order_status && $this->order_contains_pre_order($order_id)) { $this->update_pre_order_status($order_id, 'active'); } // change to 'cancelled' when changing order status to 'cancelled', except when the pre-order status is already cancelled. this prevents sending double emails when bulk-cancelling pre-orders if ('cancelled' === $new_order_status && WC_Pre_Orders_Order::order_contains_pre_order($order_id) && 'cancelled' !== get_post_meta($order_id, '_wc_pre_orders_status', true)) { $this->update_pre_order_status($order_id, 'cancelled'); } }
/** * Handle the pre-order initial payment/tokenization, or defer back to the normal payment * processing flow * * @since 4.1.0 * @see SV_WC_Payment_Gateway::process_payment() * @param boolean $result the result of this pre-order payment process * @param int $order_id the order identifier * @return true|array true to process this payment as a regular transaction, otherwise * return an array containing keys 'result' and 'redirect' */ public function process_payment($result, $order_id) { if (WC_Pre_Orders_Order::order_contains_pre_order($order_id) && WC_Pre_Orders_Order::order_requires_payment_tokenization($order_id)) { $order = $this->get_gateway()->get_order($order_id); try { // using an existing tokenized payment method if (isset($order->payment->token) && $order->payment->token) { // save the tokenized card info for completing the pre-order in the future $this->get_gateway()->add_transaction_data($order); } else { // otherwise tokenize the payment method $order = $this->get_gateway()->create_payment_token($order); } // mark order as pre-ordered / reduce order stock WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // empty cart WC()->cart->empty_cart(); // redirect to thank you page return array('result' => 'success', 'redirect' => $this->get_gateway()->get_return_url($order)); } catch (SV_WC_Payment_Gateway_Exception $e) { $this->get_gateway()->mark_order_as_failed($order, sprintf(__('Pre-Order Tokenization attempt failed (%s)', 'woocommerce-plugin-framework'), $this->get_gateway()->get_method_title(), $e->getMessage())); } } // processing regular product return $result; }
/** * Process the payment * * @param int $order_id * @return array */ 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 pre-order } elseif (class_exists('WC_Pre_Orders_Order') && WC_Pre_Orders_Order::order_contains_pre_order($order_id)) { return $this->process_pre_order($order_id); // Processing regular product } else { return parent::process_payment($order_id); } }
/** * Maybe cancel pre order when product is trashed * * @param int $product_id Product ID * @return void */ public function maybe_cancel_pre_order_product_trashed($product_id) { global $wpdb; $orders = $wpdb->get_results($wpdb->prepare("\n\t\t\t\tSELECT order_items.order_id\n\t\t\t\tFROM {$wpdb->prefix}woocommerce_order_items AS order_items\n\t\t\t\t\tLEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS order_itemmeta\n\t\t\t\t\tON order_itemmeta.order_item_id = order_items.order_item_id\n\t\t\t\tWHERE order_itemmeta.meta_key = '_product_id'\n\t\t\t\tAND order_itemmeta.meta_value = %d\n\t\t\t", $product_id)); foreach ($orders as $order_data) { $order = new WC_Order($order_data->order_id); if (WC_Pre_Orders_Order::order_contains_pre_order($order) && WC_Pre_Orders_Manager::can_pre_order_be_changed_to('cancelled', $order)) { WC_Pre_Orders_Order::update_pre_order_status($order, 'cancelled'); } } }
/** * Process the pre-order * * @param int $order_id * @return array */ protected function process_pre_order($order_id) { if (WC_Pre_Orders_Order::order_requires_payment_tokenization($order_id)) { $order = wc_get_order($order_id); if (isset($_POST['payeezy-token']) && !empty($_POST['payeezy-token'])) { $post_id = wc_clean($_POST['payeezy-token']); $post = get_post($post_id); $card_meta = get_post_meta($post->ID, '_payeezy_card', true); } else { $card = ''; $payeezy = new WC_Payeezy_API(); $response = $payeezy->authorize($this, $order, 0, $card); if (isset($response->transaction_status) && 'approved' == $response->transaction_status) { $card_meta = array('token' => $response->token->token_data->value, 'expiry' => $response->card->exp_date, 'cardtype' => $response->card->type); } else { $error_msg = __('Payment was declined - please try another card.', 'woocommerce-payeezy'); throw new Exception($error_msg); } } // Store the ID in the order update_post_meta($order->id, '_payeezy_token', $card_meta['token']); update_post_meta($order->id, '_payeezy_expiry', $card_meta['expiry']); update_post_meta($order->id, '_payeezy_cardtype', $card_meta['cardtype']); // Reduce stock levels $order->reduce_order_stock(); // Remove cart WC()->cart->empty_cart(); // Is pre ordered! WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } else { return parent::process_payment($order_id); } }
/** * Process the pre-order * @param int $order_id * @return array */ public function process_pre_order($order_id, $retry, $force_customer) { if (WC_Pre_Orders_Order::order_requires_payment_tokenization($order_id)) { try { $order = wc_get_order($order_id); if ($order->get_total() * 100 < 50) { throw new Exception(__('Sorry, the minimum allowed order total is 0.50 to use this payment method.', 'woocommerce-gateway-stripe')); } $source = $this->get_source(get_current_user_id(), true); // We need a source on file to continue. if (empty($source->customer) || empty($source->source)) { throw new Exception(__('Unable to store payment details. Please try again.', 'woocommerce-gateway-stripe')); } // Store source to order meta $this->save_source($order, $source); // Reduce stock levels $order->reduce_order_stock(); // Remove cart WC()->cart->empty_cart(); // Is pre ordered! WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // Return thank you page redirect return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } catch (Exception $e) { wc_add_notice($e->getMessage(), 'error'); return; } } else { return parent::process_payment($order_id, $retry, $force_customer); } }
/** * Process initial payment for a pre-order * * @since 2.0 * @param \WC_Order $order the order object * @throws WC_Gateway_Braintree_Exception * @return array */ private function process_pre_order_payment($order) { // do pre-authorization if (WC_Pre_Orders_Order::order_requires_payment_tokenization($order->id)) { // for an existing customer using a saved credit card, there's no way in braintree to simply // perform a $1 auth/void, so assume the saved card is valid already. If there is an issue // with the saved card, the pre-order payment will fail upon release anyway // exceptions are thrown if either the create_customer() or create_credit_card() method fails // add the braintree customer ID to the order, or create a new braintree customer and add/verify the new card added if needed if (!empty($order->braintree_order['customerId'])) { update_post_meta($order->id, '_wc_braintree_customer_id', $order->braintree_order['customerId']); } else { $order = $this->create_customer($order); } // add the braintree credit card token to the order, or create a new credit card for the customer and verify it if needed if (!empty($order->braintree_order['paymentMethodToken'])) { update_post_meta($order->id, '_wc_braintree_cc_token', $order->braintree_order['paymentMethodToken']); } else { $order = $this->create_credit_card($order); } // mark order as pre-ordered / reduce order stock WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // empty cart SV_WC_Plugin_Compatibility::WC()->cart->empty_cart(); // redirect to thank you page return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } else { // charged upfront (or paying for a newly-released pre-order with the gateway), process just like regular product return parent::process_payment($order->id); } }
/** * Check if order contains pre-orders. * * @param int $order_id * * @return bool */ public function order_contains_pre_order($order_id) { return class_exists('WC_Pre_Orders_Order') && WC_Pre_Orders_Order::order_contains_pre_order($order_id); }
/** * Get column content, this is called once per column, per row item ($order) * returns the content to be rendered within that cell. * * @see WP_List_Table::single_row_columns() * @since 1.0 * @param WC_Order $order one row (item) in the table * @param string $column_name the column slug * @return string the column content */ public function column_default($order, $column_name) { switch ($column_name) { case 'status': $actions = array(); // base action url $action_url = add_query_arg('order_id[]', $order->id); // determine any available actions if (WC_Pre_Orders_Manager::can_pre_order_be_changed_to('cancelled', $order)) { $actions['cancel'] = sprintf('<a href="%s">%s</a>', add_query_arg('action', 'cancel', $action_url), __('Cancel', 'wc-pre-orders')); } $column_content = sprintf('<mark class="%s tips" data-tip="%s">%s</mark>', WC_Pre_Orders_Order::get_pre_order_status($order), WC_Pre_Orders_Order::get_pre_order_status_to_display($order), WC_Pre_Orders_Order::get_pre_order_status_to_display($order)); $column_content .= $this->row_actions($actions); break; case 'customer': if (0 !== $order->user_id) { $column_content = sprintf('<a href="%s">%s</a>', get_edit_user_link($order->user_id), $order->billing_email); } else { $column_content = $order->billing_email; } break; case 'product': $item = WC_Pre_Orders_Order::get_pre_order_item($order); $product_edit = get_edit_post_link($item['product_id']); $column_content = $product_edit ? sprintf('<a href="%s">%s</a>', $product_edit, $item['name']) : $item['name']; break; case 'order': $column_content = sprintf('<a href="%s">%s</a>', get_edit_post_link($order->id), sprintf(__('Order %s', 'wc-pre-orders'), $order->get_order_number())); break; case 'order_date': $column_content = date_i18n(woocommerce_date_format(), strtotime($order->order_date)); break; case 'availability_date': $product = WC_Pre_Orders_Order::get_pre_order_product($order); $column_content = WC_Pre_Orders_Product::get_localized_availability_date($product, '--'); break; default: $column_content = ''; break; } return $column_content; }
?> </a> </td> <td class="pre-order-title"> <a href="<?php echo get_post_permalink($item['product_id']); ?> "> <?php echo $item['name']; ?> </a> </td> <td class="pre-order-status" style="text-align:left; white-space:nowrap;"> <?php echo WC_Pre_Orders_Order::get_pre_order_status_to_display($order); ?> </td> <td class="pre-order-release-date"> <?php echo WC_Pre_Orders_Product::get_localized_availability_date($item['product_id']); ?> </td> <td class="pre-order-actions order-actions"> <?php foreach ($actions[$order->id] as $key => $action) { ?> <a href="<?php echo esc_url($action['url']); ?> " class="button <?php
/** * Handle the pre-order initial payment/tokenization, or defer back to the normal payment * processing flow * * @since 1.0 * @see SV_WC_Payment_Gateway::process_payment() * @param boolean $result the result of this pre-order payment process * @param int $order_id the order identifier * @return true|array true to process this payment as a regular transaction, otherwise * return an array containing keys 'result' and 'redirect' * @throws SV_WC_Payment_Gateway_Feature_Unsupported_Exception if pre-orders are not supported by this gateway or its current configuration */ public function process_pre_order_payment($result, $order_id) { if (!$this->supports_pre_orders()) { throw new SV_WC_Payment_Gateway_Feature_Unsupported_Exception('Pre-Orders not supported by gateway'); } if (WC_Pre_Orders_Order::order_contains_pre_order($order_id) && WC_Pre_Orders_Order::order_requires_payment_tokenization($order_id)) { $order = $this->get_order($order_id); try { // using an existing tokenized payment method if (isset($order->payment->token) && $order->payment->token) { // save the tokenized card info for completing the pre-order in the future $this->add_transaction_data($order); } else { // otherwise tokenize the payment method $order = $this->create_payment_token($order); } // mark order as pre-ordered / reduce order stock WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // empty cart SV_WC_Plugin_Compatibility::WC()->cart->empty_cart(); // redirect to thank you page return array('result' => 'success', 'redirect' => $this->get_return_url($order)); } catch (Exception $e) { $this->mark_order_as_failed($order, sprintf(_x('Pre-Order Tokenization attempt failed (%s)', 'Supports direct payment method pre-orders', $this->text_domain), $this->get_method_title(), $e->getMessage())); } } // processing regular product return $result; }
/** * Process the transaction after receiving the token from Amazon * * @since 2.0 * @param WC_Order $order the WC Order object */ protected function process_transaction(WC_Order $order) { /* processing subscription */ if (wc_amazon_fps()->is_subscriptions_active() && WC_Subscriptions_Order::order_contains_subscription($order)) { // set the initial payment total $order->amazon_order_total = WC_Subscriptions_Order::get_total_initial_payment($order); // if there is a free trial, mark the order as paid, otherwise process it if (0 == $order->amazon_order_total) { $this->mark_order_as_processing($order); } else { parent::process_transaction($order); } /* processing pre-order */ } elseif (wc_amazon_fps()->is_pre_orders_active() && WC_Pre_Orders_Order::order_contains_pre_order($order) && WC_Pre_Orders_Order::order_requires_payment_tokenization($order)) { // mark order as pre-ordered / reduce order stock WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); /* processing regular product (or a pre-order charged upfront) */ } else { parent::process_transaction($order); } }
/** * updates order status to pre-ordered for orders that are charged upfront. This handles gateways that don't call * payment_complete(). Unfortunately status changes show like pending->processing/completed->pre-ordered * * @since 1.0 * @param int $order_id the post ID of the order * @return string */ public function update_manual_payment_complete_order_status($order_id) { $order = new WC_Order($order_id); // don't update status for non pre-order orders if (!WC_Pre_Orders_Order::order_contains_pre_order($order)) { return; } // don't update if pre-order will be charged upon release if (WC_Pre_Orders_Order::order_will_be_charged_upon_release($order)) { return; } // change order status to pre-ordered $order->update_status('pre-ordered'); }
/** * Process the pre-order. * * @param WC_Order $order * @param string $cart_token * @uses Simplify_ApiException * @uses Simplify_BadRequestException * @return array */ protected function process_pre_order($order, $cart_token = '') { if (WC_Pre_Orders_Order::order_requires_payment_tokenization($order->id)) { try { if ($order->order_total * 100 < 50) { $error_msg = __('Sorry, the minimum allowed order total is 0.50 to use this payment method.', 'woocommerce'); throw new Simplify_ApiException($error_msg); } if (empty($cart_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' => $cart_token, 'email' => $order->billing_email, 'name' => trim($order->get_formatted_billing_full_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); } // Reduce stock levels $order->reduce_order_stock(); // Remove cart WC()->cart->empty_cart(); // Is pre ordered! WC_Pre_Orders_Order::mark_order_as_pre_ordered($order); // 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' => ''); } } else { return parent::process_standard_payments($order, $cart_token); } }
/** * Process the payment * * @param int $order_id * @return array */ public function process_payment($order_id, $retry = true) { // Processing subscription if (function_exists('wcs_order_contains_subscription') && (wcs_order_contains_subscription($order_id) || wcs_is_subscription($order_id) || wcs_order_contains_renewal($order_id))) { return $this->process_subscription($order_id, $retry); // Processing pre-order } elseif (class_exists('WC_Pre_Orders_Order') && WC_Pre_Orders_Order::order_contains_pre_order($order_id)) { return $this->process_pre_order($order_id, $retry); // Processing regular product } else { return parent::process_payment($order_id, $retry); } }