diff --git a/MPM/mpm.php b/MPM/mpm.php index 3f5e4367f..e70a3ea25 100644 --- a/MPM/mpm.php +++ b/MPM/mpm.php @@ -119,7 +119,13 @@ function mpm_webhook() { if ($payment->status === Mollie_API_Object_Payment::STATUS_CANCELLED) { - $order->cancel_order(); + //User cancelled payment on mollie or issuer page, add a cancel note.. do not cancel order. + $order->add_order_note("User cancelled payment"); + $isCancelled = get_post_meta($order->id, '_is_mollie_cancelled'); + if (!$isCancelled) + { + update_post_meta($order_id, '_is_mollie_cancelled', 1, $isCancelled); + } } else { diff --git a/MPM/mpm_gateway.php b/MPM/mpm_gateway.php index c955055bd..9a87a7b98 100644 --- a/MPM/mpm_gateway.php +++ b/MPM/mpm_gateway.php @@ -174,8 +174,30 @@ public function process_payment($order_id) $order->update_status('pending', __('Awaiting payment confirmation', 'MPM')); + // check if user cancelled previous payment. if so add a retry note and set cancelled to false. + $isCancelled = get_post_meta($order->id, '_is_mollie_cancelled'); + if ($isCancelled) + { + update_post_meta($order_id, '_is_mollie_cancelled', 0, $isCancelled); + $order->add_order_note("User retried payment"); + } + $webhook = admin_url('admin-ajax.php') . '?action=mollie_webhook'; - $return_url = $this->get_return_url_with_fix_endpoint_spaces($order); + + $woo_version = get_option('woocommerce_version', 'Unknown'); + if (version_compare($woo_version, '2.2.0', '>=')) + { + // use woocommerce endpoints + $return_url = $this->get_return_url_with_fix_endpoint_spaces($order); + } + else + { + // only use the mollie return page + $return_url = $mpm->return->get_return_link(); + $return_url = $return_url . (strpos($return_url, '?') !== FALSE ? '&' : '?') . 'order='.$order_id.'&key='.$order->order_key; + $return_url .= "&utm_nooverride=1"; + } + $data = array( "amount" => $order->get_total(), diff --git a/MPM/mpm_return.php b/MPM/mpm_return.php index b946288a4..e4d5cac99 100644 --- a/MPM/mpm_return.php +++ b/MPM/mpm_return.php @@ -9,6 +9,28 @@ class MPM_return extends MPM_Settings public function __construct() { + $this->return_page = $this->get_return_page(); + + // Create return page if not exists + if ($this->return_page === null) + { + $page_data = array( + 'post_status' => 'publish', + 'post_type' => 'page', + 'post_author' => 1, + 'post_name' => 'welcome_back', + 'post_title' => __('Welcome Back', 'MPM'), + 'post_content' => '[mollie_return_page]', + 'post_parent' => 0, + 'comment_status' => 'closed' + ); + if (!$this->is_return_page_2_1(wp_insert_post($page_data))) + { + $this->errors[] = __('Error: Could not find nor generate return page!', 'MPM'); + $this->display_errors(); + } + } + // Set return titles $this->return_page_titles = array( 'pending' => __('Payment Pending', 'MPM'), @@ -35,6 +57,17 @@ public function return_page_order_received_text($text, WC_Order $order = null) return $text; } + return $this->return_page_status($order); + } + + /** + * Status displayed on mollie return page. + * @param string $text + * @param WC_Order|null $order + * @return string + */ + public function return_page_status($order, $redirect = true) + { // Do we know that the key is checked by WC? check it for sure. $order = $this->order_get(($order != null) ? $order->id : 0, $_GET['key']); @@ -42,13 +75,31 @@ public function return_page_order_received_text($text, WC_Order $order = null) { $html = '

' . __('Your order was not recognised as being a valid order from this shop.', 'MPM') . '

' . __('If you did buy something in this shop, something apparently went wrong, and you should contact us as soon as possible.', 'MPM') . '

'; - return $html; + return $html; } $html = '

'. __('Order status:', 'MPM') . ' ' . $this->return_page_titles[$order->status] . '

'; + // if user cancelled at mollie or issuer, webhook will render post_meta: _is_mollie_cancelled true. + $isCancelled = get_post_meta($order->id, '_is_mollie_cancelled'); + switch ($order->status) { case 'pending': + // if user cancelled the order will stay pending and isCancelled is true. We redirect the user to the payment page. + if ($isCancelled) + { + if ($redirect) + { + wp_redirect($order->get_checkout_payment_url()); + } + $html .= '

' . __('You have cancelled your order.', 'MPM') . '

+

' . __('Please attempt your purchase again', 'MPM') . '

'; + } + else + { + $html .= '

' . __('We have not received a definite payment status. You will receive an email as soon as we receive a confirmation of the bank/merchant.', 'MPM') . '

'; + } + break; case 'on-hold': $html .= '

' . __('We have not received a definite payment status. You will receive an email as soon as we receive a confirmation of the bank/merchant.', 'MPM') . '

'; break; @@ -163,6 +214,32 @@ public function return_page_redirect() exit; } } + + // When on the mollie return page .. and order == pending && cancelled.. + // redirect here because headers are allready sent on shortcode. + if (is_page($this->return_page)) + { + $order_id = (int) $_GET['order']; + $key = $_GET['key']; + if (!$order_id || !$order = $this->order_get($order_id, $key)) + { + wp_redirect(get_permalink(woocommerce_get_page_id('checkout'))); + exit; + } + + if ($order->status == 'pending') + { + // check if cancelled.. + $isCancelled = get_post_meta($order->id, '_is_mollie_cancelled'); + if ($isCancelled) + { + // on mollie return page, has order, order is pending, and meta cancelled is true. + wp_redirect($order->get_checkout_payment_url()); + exit; + } + } + } + } /** @@ -203,9 +280,84 @@ public function get_order_id_from_request() $length = strlen($receive_page); $char = $pos + $length + 1; $char_end = strpos(substr($current_url, $char), '/'); + if (!$char_end) + { + $char_end = strpos(substr($current_url, $char), '?'); + } return substr($current_url, $char,$char_end); } } return null; } + + /** + * Locates the return page + * @return int|null + */ + public function get_return_page() + { + global $wpdb; + $q = $wpdb->get_row("SELECT `ID` FROM `$wpdb->posts` WHERE `post_status` = 'publish' AND `post_content` LIKE '%[mollie_return_page]%'", 'ARRAY_A'); + if (is_null($q) || !array_key_exists('ID', $q)) + { + return NULL; + } + return $q['ID']; + } + + /** + * Determines if a certain page contains the [mollie_return_page] shorttag + * @param int|WP_Post $page + * @return bool + */ + public function is_return_page_2_1($page) + { + if (!is_a($page, 'WP_Post')) + { + $page = get_post($page); + } + if (is_null($page)) + { + return FALSE; + } + return strpos($page->post_content, '[mollie_return_page]') !== FALSE; + } + + /** + * Makes a permalink of the return page, but always uses page id (no matter the permalink format) because we're changing the return page title + * @return string|null + */ + public function get_return_link() + { + if (!$this->return_page) + { + $this->return_page = $this->get_return_page(); + } + $post_id = $this->return_page; + if (is_null($post_id)) + { + $this->errors[] = __('Error: Return page not found!', 'MPM'); + $this->display_errors(); + return 'error'; + } + return get_permalink($post_id); + } + + /** + * Renders the return page + * @return string + */ + public function return_page_render() + { + $order = $this->order_get($_GET['order'], $_GET['key'], true); + $html = $this->return_page_status($order, false); + + ob_start(); + do_action( 'woocommerce_thankyou_' . $order->payment_method, $order->id ); + do_action( 'woocommerce_thankyou', $order->id ); + $html .= ob_get_contents(); + ob_end_clean(); + + return $html; + } } \ No newline at end of file diff --git a/MPM/mpm_settings.php b/MPM/mpm_settings.php index 0ed8d454a..71ed61ec9 100644 --- a/MPM/mpm_settings.php +++ b/MPM/mpm_settings.php @@ -76,8 +76,17 @@ public function __construct() add_filter('the_title', array(&$this->return, 'return_page_title'), 10, 2); // set return page title manually add_filter('option_woocommerce_default_gateway', array(&$this, 'set_default_gateway')); // alter default gateway name - // we don't need to render the tankyou page ourselves. We just pass a text to the thankyou page. - add_filter('woocommerce_thankyou_order_received_text', array(&$this->return, 'return_page_order_received_text'),10,2); + $woo_version = get_option('woocommerce_version', 'Unknown'); + if (version_compare($woo_version, '2.2.0', '>=')) + { + // Only after 2.2 we don't need to render the tankyou page ourselves. We just pass a text to the thankyou page. + add_filter('woocommerce_thankyou_order_received_text', array(&$this->return, 'return_page_order_received_text'),10,2); + } + else + { + // On woo <= 2.1 we use the mollie return page. + add_shortcode('mollie_return_page', array(&$this->return, 'return_page_render')); + } } return $mpm;