From d6a667ce052d72bafd6f51eccb8dbaa1d5c94939 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Tue, 10 Aug 2021 15:32:29 +0700 Subject: [PATCH 01/13] add note on hooks --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 0c470f3..b1be78e 100644 --- a/README.md +++ b/README.md @@ -174,6 +174,8 @@ function my_midtrans_on_notif_hook( $order, $midtrans_notification ) { For reference on where/which file to apply that code example, [refer here](https://blog.nexcess.net/the-right-way-to-add-custom-functions-to-your-wordpress-site/). +Note: for `midtrans_after_notification_payment_complete` & `midtrans_on_notification_received` hooks, if you are using [custom "WC Order Status on Payment Paid"](https://docs.midtrans.com/en/snap/with-plugins?id=advanced-customize-woocommerce-order-status-upon-payment-paid) config, the final WC Order status value can get overridden by that config. As that config is executed last. + #### Customizing Snap API parameters From 03ea46d403ea8e4479e5ec3abd74c0adec57ed4c Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Tue, 10 Aug 2021 15:31:54 +0700 Subject: [PATCH 02/13] improve finish url redirect to only accept authorized user - only allow the specific authorized transacting-user to reach order's detailed finish page url - prevent order id enumeration from unauth user --- abstract/abstract.midtrans-gateway.php | 14 +++++++++++ class/class.midtrans-gateway-installment.php | 3 ++- .../class.midtrans-gateway-installmentoff.php | 2 ++ .../class.midtrans-gateway-notif-handler.php | 25 ++++++++++++++----- .../class.midtrans-gateway-paymentrequest.php | 2 ++ class/class.midtrans-gateway-promo.php | 3 +++ class/class.midtrans-gateway.php | 3 +++ 7 files changed, 45 insertions(+), 7 deletions(-) diff --git a/abstract/abstract.midtrans-gateway.php b/abstract/abstract.midtrans-gateway.php index 67da586..5716575 100644 --- a/abstract/abstract.midtrans-gateway.php +++ b/abstract/abstract.midtrans-gateway.php @@ -386,6 +386,20 @@ public function midtrans_refund( $order_id, $refund_amount, $refund_reason, $isF return $refund; } + /** + * Custom helper function to set customer web session cookies of WC order's finish_url + * That will be used by finish url handler to redirect customer to upon finish url is reached + * Cookies is used to strictly allow only the transacting-customer + * to access the order's finish url + * @TAG: finish_url_user_cookies + * @param WC_Order $order WC Order instance of the current transaction + */ + public function set_finish_url_user_cookies( $order ) { + $cookie_name = 'wc_midtrans_last_order_finish_url'; + $order_finish_url = $order->get_checkout_order_received_url(); + setcookie($cookie_name, $order_finish_url); + } + /** * Custom helper function to write messages to WP/WC error log. * @TODO: refactor name to make it more descriptive? diff --git a/class/class.midtrans-gateway-installment.php b/class/class.midtrans-gateway-installment.php index 864450c..b562c00 100755 --- a/class/class.midtrans-gateway-installment.php +++ b/class/class.midtrans-gateway-installment.php @@ -105,7 +105,8 @@ function process_payment( $order_id ) { $order->update_meta_data('_mt_payment_snap_token',$snapResponse->token); $order->update_meta_data('_mt_payment_url',$snapResponse->redirect_url); $order->save(); - + // set wc order's finish_url on user's session cookie + $this->set_finish_url_user_cookies($order); if(property_exists($this,'enable_immediate_reduce_stock') && $this->enable_immediate_reduce_stock == 'yes'){ wc_reduce_stock_levels($order); } diff --git a/class/class.midtrans-gateway-installmentoff.php b/class/class.midtrans-gateway-installmentoff.php index 9f9e3d6..b9434db 100755 --- a/class/class.midtrans-gateway-installmentoff.php +++ b/class/class.midtrans-gateway-installmentoff.php @@ -135,6 +135,8 @@ public function process_payment( $order_id ) { $order->update_meta_data('_mt_payment_snap_token',$snapResponse->token); $order->update_meta_data('_mt_payment_url',$snapResponse->redirect_url); $order->save(); + // set wc order's finish_url on user's session cookie + $this->set_finish_url_user_cookies($order); if(property_exists($this,'enable_immediate_reduce_stock') && $this->enable_immediate_reduce_stock == 'yes'){ // Reduce item stock on WC, item also auto reduced on order `pending` status changes wc_reduce_stock_levels($order); diff --git a/class/class.midtrans-gateway-notif-handler.php b/class/class.midtrans-gateway-notif-handler.php index 176a6a9..1eeb257 100644 --- a/class/class.midtrans-gateway-notif-handler.php +++ b/class/class.midtrans-gateway-notif-handler.php @@ -50,6 +50,21 @@ public function doEarlyAckResponse() { return $raw_notification; } + /** + * Redirect transacting-user to the finish url set when they were checking out + * if they were the authorized transacting-user, they will have the finish_url on cookie + * @TAG: finish_url_user_cookies + */ + public function checkAndRedirectUserToFinishUrl(){ + if(isset($_COOKIE['wc_midtrans_last_order_finish_url'])){ + // authorized transacting-user + wp_redirect($_COOKIE['wc_midtrans_last_order_finish_url']); + }else{ + // else, unauthorized user, redirect to shop homepage by default. + wp_redirect( get_permalink( wc_get_page_id( 'shop' ) ) ); + } + } + /** * getPluginOptions * @param string $plugin_id plugin id of the paid order @@ -126,8 +141,7 @@ public function handleMidtransNotificationRequest() { if( !empty($sanitized['order_id']) && !empty($sanitized['status_code']) && $sanitized['status_code'] <= 200) { $order_id = $sanitized['order_id']; // error_log($this->get_return_url( $order )); //debug - $order = new WC_Order( $order_id ); - wp_redirect($order->get_checkout_order_received_url()); + $this->checkAndRedirectUserToFinishUrl(); } // if or pending/challenge else if( !empty($sanitized['order_id']) && !empty($sanitized['transaction_status']) && $sanitized['status_code'] == 201) { @@ -142,7 +156,7 @@ public function handleMidtransNotificationRequest() { wp_redirect( get_permalink( wc_get_page_id( 'shop' ) ) ); exit; } - wp_redirect($order->get_checkout_order_received_url()); + $this->checkAndRedirectUserToFinishUrl(); } //if deny, redirect to order checkout page again else if( !empty($sanitized['order_id']) && !empty($sanitized['transaction_status']) && $sanitized['status_code'] >= 202){ @@ -157,7 +171,7 @@ public function handleMidtransNotificationRequest() { $order = new WC_Order( $responses['order_id'] ); // if async payment paid if ( $responses['status_code'] == 200) { - wp_redirect($order->get_checkout_order_received_url()); + $this->checkAndRedirectUserToFinishUrl(); } // if async payment not paid else { @@ -180,8 +194,7 @@ public function handleMidtransNotificationRequest() { $order_id = $midtrans_notification->order_id; // if async payment paid if ($midtrans_notification->transaction_status == 'settlement'){ - $order = new WC_Order( $order_id ); - wp_redirect($order->get_checkout_order_received_url()); + $this->checkAndRedirectUserToFinishUrl(); } // if async payment not paid else { diff --git a/class/class.midtrans-gateway-paymentrequest.php b/class/class.midtrans-gateway-paymentrequest.php index afb6288..a69bd7d 100755 --- a/class/class.midtrans-gateway-paymentrequest.php +++ b/class/class.midtrans-gateway-paymentrequest.php @@ -98,6 +98,8 @@ function process_payment( $order_id ) { $order->update_meta_data('_mt_payment_snap_token',$snapResponse->token); $order->update_meta_data('_mt_payment_url',$snapResponse->redirect_url); $order->save(); + // set wc order's finish_url on user's session cookie + $this->set_finish_url_user_cookies($order); if(property_exists($this,'enable_immediate_reduce_stock') && $this->enable_immediate_reduce_stock == 'yes'){ wc_reduce_stock_levels($order); } diff --git a/class/class.midtrans-gateway-promo.php b/class/class.midtrans-gateway-promo.php index 6ffc717..71ac373 100755 --- a/class/class.midtrans-gateway-promo.php +++ b/class/class.midtrans-gateway-promo.php @@ -130,6 +130,9 @@ function process_payment( $order_id ) { $order->update_meta_data('_mt_payment_url',$snapResponse->redirect_url); $order->save(); + // set wc order's finish_url on user's session cookie + $this->set_finish_url_user_cookies($order); + if(property_exists($this,'enable_immediate_reduce_stock') && $this->enable_immediate_reduce_stock == 'yes'){ wc_reduce_stock_levels($order); } diff --git a/class/class.midtrans-gateway.php b/class/class.midtrans-gateway.php index 1299592..0c60803 100755 --- a/class/class.midtrans-gateway.php +++ b/class/class.midtrans-gateway.php @@ -151,6 +151,9 @@ public function process_payment_helper( $order_id, $options = false ) { $order->update_meta_data('_mt_payment_url',$snapResponse->redirect_url); $order->save(); + // set wc order's finish_url on user's session cookie + $this->set_finish_url_user_cookies($order); + // @TODO: default to yes or remove this options: enable_immediate_reduce_stock if(property_exists($this,'enable_immediate_reduce_stock') && $this->enable_immediate_reduce_stock == 'yes'){ // Reduce item stock on WC, item also auto reduced on order `pending` status changes From 0db182e74a245721e0fed3cf13b309eb62cc1ce4 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Tue, 10 Aug 2021 15:36:40 +0700 Subject: [PATCH 03/13] catch exception when order id not found on finish url --- .../class.midtrans-gateway-notif-handler.php | 22 ++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/class/class.midtrans-gateway-notif-handler.php b/class/class.midtrans-gateway-notif-handler.php index 1eeb257..1550f61 100644 --- a/class/class.midtrans-gateway-notif-handler.php +++ b/class/class.midtrans-gateway-notif-handler.php @@ -145,17 +145,19 @@ public function handleMidtransNotificationRequest() { } // if or pending/challenge else if( !empty($sanitized['order_id']) && !empty($sanitized['transaction_status']) && $sanitized['status_code'] == 201) { - $order_id = $sanitized['order_id']; - $order = new WC_Order( $order_id ); - $plugin_id = $order->get_payment_method(); + try { + $order_id = $sanitized['order_id']; + $order = new WC_Order( $order_id ); + $plugin_id = $order->get_payment_method(); - $plugin_options = $this->getPluginOptions($plugin_id); - if( array_key_exists('ignore_pending_status',$plugin_options) - && $plugin_options['ignore_pending_status'] == 'yes' - ){ - wp_redirect( get_permalink( wc_get_page_id( 'shop' ) ) ); - exit; - } + $plugin_options = $this->getPluginOptions($plugin_id); + if( array_key_exists('ignore_pending_status',$plugin_options) + && $plugin_options['ignore_pending_status'] == 'yes' + ){ + wp_redirect( get_permalink( wc_get_page_id( 'shop' ) ) ); + exit; + } + } catch (Exception $e) { } // catch if order not exist on WC $this->checkAndRedirectUserToFinishUrl(); } //if deny, redirect to order checkout page again From 21d49ffe1e8e2ed53ea310f4f514f0e3b58fd040 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Tue, 10 Aug 2021 17:36:41 +0700 Subject: [PATCH 04/13] tidy up payment icon images --- README.md | 2 +- .../payment-methods/{qris_1.png => alt_qris.png} | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename public/images/payment-methods/{qris_1.png => alt_qris.png} (100%) diff --git a/README.md b/README.md index b1be78e..a071bb3 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ You can customize icon that will be shown on payment buttons, from the plugin co All available values for the field: ``` -credit_card.png, gopay.png, shopeepay.png, qris.png, other_va.png, bni_va.png, bri_va.png, bca_va.png, permata_va.png, echannel.png, alfamart.png, indomaret.png, akulaku.png, bca_klikpay.png, cimb_clicks.png, danamon_online.png, midtrans.png +midtrans.png, credit_card.png, gopay.png, shopeepay.png, qris.png, other_va.png, bni_va.png, bri_va.png, bca_va.png, permata_va.png, echannel.png, alfamart.png, indomaret.png, akulaku.png, bca_klikpay.png, cimb_clicks.png, danamon_online.png ``` Or refer to [payment-methods folder](/public/images/payment-methods) to see the list of all available file names. The image file will be loaded from that folder. diff --git a/public/images/payment-methods/qris_1.png b/public/images/payment-methods/alt_qris.png similarity index 100% rename from public/images/payment-methods/qris_1.png rename to public/images/payment-methods/alt_qris.png From 301e96cdbb1ab5b09e23d8358feace654a376036 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Tue, 10 Aug 2021 17:37:09 +0700 Subject: [PATCH 05/13] update config page links to open in new browser tab --- class/midtrans-admin-settings.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/class/midtrans-admin-settings.php b/class/midtrans-admin-settings.php index 38f6836..3bbcf19 100644 --- a/class/midtrans-admin-settings.php +++ b/class/midtrans-admin-settings.php @@ -64,7 +64,7 @@ 'notification_url_display' => array( 'title' => __( 'Notification URL value', 'midtrans-woocommerce' ), 'type' => 'title', - 'description' => __( 'After you have filled required config above, don\'t forget to scroll to bottom and click Save Changes button.

Copy and use this recommended Notification URL '.$this->get_main_notification_url().' into "Midtrans Dashboard > Settings > Configuration > Notification Url". This will allow your WooCommerce to receive Midtrans payment status, which auto sync the payment status.','midtrans-woocommerce'), + 'description' => __( 'After you have filled required config above, don\'t forget to scroll to bottom and click Save Changes button.

Copy and use this recommended Notification URL '.$this->get_main_notification_url().' into "Midtrans Dashboard > Settings > Configuration > Notification Url". This will allow your WooCommerce to receive Midtrans payment status, which auto sync the payment status.','midtrans-woocommerce'), ), 'label_config_separator' => array( 'title' => __( 'II. Payment Buttons Appereance Section - Optional', 'midtrans-woocommerce' ), @@ -87,7 +87,7 @@ 'sub_payment_method_image_file_names_str' => array( 'title' => __( 'Button Icons', 'midtrans-woocommerce' ), 'type' => 'text', - 'description' => __( 'You can input multiple payment method names separated by coma (,).
See all available values here, you can copy paste the value, and adjust as needed. Also support https:// url to external image.', 'midtrans-woocommerce' ), + 'description' => __( 'You can input multiple payment method names separated by coma (,).
See all available values here, you can copy paste the value, and adjust as needed. Also support https:// url to external image.', 'midtrans-woocommerce' ), 'placeholder' => 'midtrans.png,credit_card.png', ), 'advanced_config_separator' => array( From b710ac947b339f719779a8ec41f682f1fce8d0d3 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Tue, 10 Aug 2021 15:48:38 +0700 Subject: [PATCH 06/13] changelog & bump version v2.31.0 --- midtrans-gateway.php | 2 +- readme.txt | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/midtrans-gateway.php b/midtrans-gateway.php index 3662d71..b6d8a8f 100644 --- a/midtrans-gateway.php +++ b/midtrans-gateway.php @@ -3,7 +3,7 @@ Plugin Name: Midtrans - WooCommerce Payment Gateway Plugin URI: https://github.com/veritrans/SNAP-Woocommerce Description: Accept all payment directly on your WooCommerce site in a seamless and secure checkout environment with Midtrans -Version: 2.30.1 +Version: 2.31.0 Author: Midtrans Author URI: http://midtrans.co.id License: GPLv2 or later diff --git a/readme.txt b/readme.txt index 942e359..5e1d6c1 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: yocki, rizdaprasetya Tags: midtrans, snap, payment, payment-gateway, credit-card, commerce, e-commerce, woocommerce, veritrans Requires at least: 3.9.1 Tested up to: 5.8 -Stable tag: 2.30.1 +Stable tag: 2.31.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -72,6 +72,10 @@ The best way please email to support@midtrans.com, but bugs can be reported in o == Changelog == += 2.31.0 - 2021-08-10 = +* improvement on finish url redirect flow, to prevent issue +* handle uncaught error on finish url + = 2.30.1 - 2021-08-09 = * prevent issue "cannot inherit abstract function" on outdated PHP v5.0.0 - v5.3.8 & v7.0.0 - v7.1.x * minor description improvement From 91f05ec0473de22ae718e11bf654ee49c1323a12 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Tue, 10 Aug 2021 15:48:38 +0700 Subject: [PATCH 07/13] changelog & bump version v2.31.0 --- midtrans-gateway.php | 2 +- readme.txt | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/midtrans-gateway.php b/midtrans-gateway.php index 3662d71..b6d8a8f 100644 --- a/midtrans-gateway.php +++ b/midtrans-gateway.php @@ -3,7 +3,7 @@ Plugin Name: Midtrans - WooCommerce Payment Gateway Plugin URI: https://github.com/veritrans/SNAP-Woocommerce Description: Accept all payment directly on your WooCommerce site in a seamless and secure checkout environment with Midtrans -Version: 2.30.1 +Version: 2.31.0 Author: Midtrans Author URI: http://midtrans.co.id License: GPLv2 or later diff --git a/readme.txt b/readme.txt index 942e359..7b0f737 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: yocki, rizdaprasetya Tags: midtrans, snap, payment, payment-gateway, credit-card, commerce, e-commerce, woocommerce, veritrans Requires at least: 3.9.1 Tested up to: 5.8 -Stable tag: 2.30.1 +Stable tag: 2.31.0 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -72,6 +72,10 @@ The best way please email to support@midtrans.com, but bugs can be reported in o == Changelog == += 2.31.0 - 2021-08-10 = +* improvement on finish url redirect flow, to prevent issue +* handle uncaught error on finish url + = 2.30.1 - 2021-08-09 = * prevent issue "cannot inherit abstract function" on outdated PHP v5.0.0 - v5.3.8 & v7.0.0 - v7.1.x * minor description improvement @@ -255,6 +259,10 @@ The best way please email to support@midtrans.com, but bugs can be reported in o == Upgrade Notice == += 2.31.0 - 2021-08-10 = +* improvement on finish url redirect flow, to prevent issue +* handle uncaught error on finish url + = 2.30.1 - 2021-08-09 = * prevent issue "cannot inherit abstract function" on outdated PHP v5.0.0 - v5.3.8 & v7.0.0 - v7.1.x * minor description improvement From 7c5ab7823e5c9f591813a0aa36267466d238d182 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Wed, 25 Aug 2021 14:42:22 +0700 Subject: [PATCH 08/13] clarify hooks --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a071bb3..ca24de5 100644 --- a/README.md +++ b/README.md @@ -136,11 +136,13 @@ If you are a developer or know how to customize Wordpress, this section may be u This plugin have few available [WP hooks](https://developer.wordpress.org/plugins/hooks/): - filter: `midtrans_snap_params_main_before_charge` (1 params) - - For if you want to modify Snap API JSON param on the main gateway, before transaction is created on Midtrans side. + - For if you want to modify Snap API JSON param on the main gateway, before transaction is created on Midtrans side. The $params is PHP Array representation of [Snap API JSON param](https://snap-docs.midtrans.com/#request-body-json-parameter) - action: `midtrans_after_notification_payment_complete` (2 params) - For if you want to perform action/update WC Order object when the payment is declared as complete upon Midtrans notification received. - action: `midtrans_on_notification_received` (2 params) - For if you want to perform action/update WC Order object upon Midtrans notification received. +- action: `midtrans-handle-valid-notification` (1 params) + - For if you want to perform something upon valid Midtrans notification received. Note: this is legacy hook, better use the hook above. Example implementation: ```php From a577ecbe77ab12cffca84c7eff700b0e3712f0a8 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Wed, 25 Aug 2021 14:49:22 +0700 Subject: [PATCH 09/13] change immediate-reduce-stock to disable by default - revert earlier version it was enabled by def --- class/midtrans-admin-settings.php | 2 +- readme.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/class/midtrans-admin-settings.php b/class/midtrans-admin-settings.php index 3bbcf19..f12b0f8 100644 --- a/class/midtrans-admin-settings.php +++ b/class/midtrans-admin-settings.php @@ -164,7 +164,7 @@ 'type' => 'checkbox', 'label' => 'Immediately reduce item stock on Midtrans payment pop-up?', 'description' => __( 'By default, item stock only reduced if payment status on Midtrans reach pending/success (customer choose payment channel and click pay on payment pop-up). Enable this if you want to immediately reduce item stock when payment pop-up generated/displayed.', 'midtrans-woocommerce' ), - 'default' => 'yes' + 'default' => 'no' ), // @Note: only main plugin class config will be applied on notif handler, sub plugin class config will not affect it, check gateway-notif-handler.php class to fix 'ignore_pending_status' => array( diff --git a/readme.txt b/readme.txt index 7b0f737..53fcd1d 100644 --- a/readme.txt +++ b/readme.txt @@ -75,6 +75,7 @@ The best way please email to support@midtrans.com, but bugs can be reported in o = 2.31.0 - 2021-08-10 = * improvement on finish url redirect flow, to prevent issue * handle uncaught error on finish url +* immediate-reduce-stock disabled by default = 2.30.1 - 2021-08-09 = * prevent issue "cannot inherit abstract function" on outdated PHP v5.0.0 - v5.3.8 & v7.0.0 - v7.1.x @@ -262,6 +263,7 @@ The best way please email to support@midtrans.com, but bugs can be reported in o = 2.31.0 - 2021-08-10 = * improvement on finish url redirect flow, to prevent issue * handle uncaught error on finish url +* immediate-reduce-stock disabled by default = 2.30.1 - 2021-08-09 = * prevent issue "cannot inherit abstract function" on outdated PHP v5.0.0 - v5.3.8 & v7.0.0 - v7.1.x From 2afd757a01d11097db90499c08437b128ddeb9c5 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Wed, 25 Aug 2021 14:55:00 +0700 Subject: [PATCH 10/13] handle snap order_id duplicated upon charge, auto suffix it - handle 406 duplicated Snap order_id on Snap charge (incase WP is reinstalled, or DB restored on Merchant side) by auto-adding suffix string - also auto remove the suffix on incoming order_id handler --- MAINTAINING.md | 5 +++ abstract/abstract.midtrans-gateway.php | 15 ++++++- class/class.midtrans-gateway-api.php | 35 ++++++++++++++++ class/class.midtrans-gateway-installment.php | 2 +- .../class.midtrans-gateway-installmentoff.php | 2 +- .../class.midtrans-gateway-notif-handler.php | 42 +++++++++++++++---- .../class.midtrans-gateway-paymentrequest.php | 2 +- class/class.midtrans-gateway-promo.php | 2 +- class/class.midtrans-gateway-subscription.php | 2 +- class/class.midtrans-gateway.php | 2 +- class/class.midtrans-utils.php | 35 ++++++++++++++++ public/js/midtrans-payment-page-main.js | 24 +++++++++++ readme.txt | 2 + 13 files changed, 154 insertions(+), 16 deletions(-) diff --git a/MAINTAINING.md b/MAINTAINING.md index 0a7c301..303fda5 100644 --- a/MAINTAINING.md +++ b/MAINTAINING.md @@ -28,6 +28,11 @@ Other: - External WC PG dev guide: https://www.skyverge.com/blog/how-to-create-a-simple-woocommerce-payment-gateway/ - WP get_options() functions: https://developer.wordpress.org/reference/functions/get_option/ +### Attention +- Due to the feature of "custom order_id suffix to prevent duplicated order_id", order_id input and output may need to be handled non-traditionally, look for `@TAG: order-suffix-separator` in the code comments. e.g: + - when sending order_id to Midtrans, it may need to go thru func `WC_Midtrans_Utils::generate_non_duplicate_order_id` + - when receiving order_id, it may need to go thru func `WC_Midtrans_Utils::check_and_restore_original_order_id` + ### Separted Payment Buttons To implement separated payment buttons (separate WC payment gateway) for each of Midtrans' supported payment methods, the following implementations are made: - within `/class/sub-specific-buttons` those are the class files diff --git a/abstract/abstract.midtrans-gateway.php b/abstract/abstract.midtrans-gateway.php index 5716575..8beb199 100644 --- a/abstract/abstract.midtrans-gateway.php +++ b/abstract/abstract.midtrans-gateway.php @@ -131,16 +131,26 @@ public function process_refund($order_id, $amount = null, $reason = '') { */ public function refund( $order, $order_id, $amount, $reason ) { $refund_params = array( + // @TODO: careful with this order_id here, which does not get deduplicated treatment 'refund_key' => 'RefundID' . $order_id . '-' . current_time('timestamp'), 'amount' => $amount, 'reason' => $reason ); try { - $response = WC_Midtrans_API::createRefund($order_id, $refund_params, $this->id); + if(strpos($this->id, 'midtrans_sub') !== false){ + // for sub separated gateway buttons, use main gateway plugin id instead + $this->id = 'midtrans'; + } + // @TODO: call refund API with transaction_id instead of order_id to avoid id not found for suffixed order_id. $order->get_transaction_id(); + $transaction_id = $order->get_transaction_id() + ? $order->get_transaction_id() + : $order_id; + $response = WC_Midtrans_API::createRefund($transaction_id, $refund_params, $this->id); } catch (Exception $e) { $this->setLogError( $e->getMessage() ); - $error_message = strpos($e->getMessage(), '412') ? $e->getMessage() . ' Note: Refund via Midtrans only for specific payment method, please consult to your midtrans PIC for more information' : $e->getMessage(); + // error_log(var_export($e,1)); + $error_message = strpos($e->getMessage(), '412') ? $e->getMessage() . ' Note: Refund via Midtrans API only available on some payment methods, and if the payment status is eligible. Please consult to your midtrans PIC for more information' : $e->getMessage(); return $error_message; } @@ -334,6 +344,7 @@ public function getResponseTemplate( $order ) { * @return WC_Order_Refund|WP_Error */ public function midtrans_refund( $order_id, $refund_amount, $refund_reason, $isFullRefund = false ) { + $order_id = WC_Midtrans_Utils::check_and_restore_original_order_id(); $order = wc_get_order( $order_id ); if( ! is_a( $order, 'WC_Order') ) { return; diff --git a/class/class.midtrans-gateway-api.php b/class/class.midtrans-gateway-api.php index cb44afd..7b9ab9a 100644 --- a/class/class.midtrans-gateway-api.php +++ b/class/class.midtrans-gateway-api.php @@ -87,12 +87,47 @@ public static function get_environment() { * @return void */ public static function fetchAndSetMidtransApiConfig( $plugin_id="midtrans" ) { + if(strpos($plugin_id, 'midtrans_sub') !== false){ + // for sub separated gateway buttons, use main gateway plugin id instead + $plugin_id = 'midtrans'; + } self::fetchAndSetCurrentPluginOptions( $plugin_id ); Midtrans\Config::$isProduction = (self::get_environment() == 'production') ? true : false; Midtrans\Config::$serverKey = self::get_server_key(); Midtrans\Config::$isSanitized = true; } + /** + * Same as createSnapTransaction, but it will auto handle exception + * 406 duplicated order_id exception from Snap API, by calling WC_Midtrans_Utils::generate_non_duplicate_order_id + * @param object $order the WC Order instance. + * @param array $params Payment options. + * @param string $plugin_id ID of the plugin class calling this function + * @return object Snap response (token and redirect_url). + * @throws Exception curl error or midtrans error. + */ + public static function createSnapTransactionHandleDuplicate( $order, $params, $plugin_id="midtrans") { + try { + $response = self::createSnapTransaction($params, $plugin_id); + } catch (Exception $e) { + // Handle: Snap order_id duplicated, retry with suffixed order_id + if( strpos($e->getMessage(), 'transaction_details.order_id sudah digunakan') !== false) { + self::setLogRequest( $e->getMessage().' - Attempt to auto retry with suffixed order_id', $plugin_id ); + // @TAG: order-id-suffix-handling + $params['transaction_details']['order_id'] = + WC_Midtrans_Utils::generate_non_duplicate_order_id($params['transaction_details']['order_id']); + $response = self::createSnapTransaction($params, $plugin_id); + + // store the suffixed order id to order metadata + // @TAG: order-id-suffix-handling-meta + $order->update_meta_data('_mt_suffixed_midtrans_order_id', $params['transaction_details']['order_id']); + } else { + throw $e; + } + } + return $response; + } + /** * Create Snap Token. * @param array $params Payment options. diff --git a/class/class.midtrans-gateway-installment.php b/class/class.midtrans-gateway-installment.php index b562c00..52c116d 100755 --- a/class/class.midtrans-gateway-installment.php +++ b/class/class.midtrans-gateway-installment.php @@ -88,7 +88,7 @@ function process_payment( $order_id ) { // Empty the cart because payment is initiated. $woocommerce->cart->empty_cart(); try { - $snapResponse = WC_Midtrans_API::createSnapTransaction( $params, $this->id ); + $snapResponse = WC_Midtrans_API::createSnapTransactionHandleDuplicate( $order, $params, $this->id ); } catch (Exception $e) { $this->setLogError( $e->getMessage() ); WC_Midtrans_Utils::json_print_exception( $e, $this ); diff --git a/class/class.midtrans-gateway-installmentoff.php b/class/class.midtrans-gateway-installmentoff.php index b9434db..b1bd030 100755 --- a/class/class.midtrans-gateway-installmentoff.php +++ b/class/class.midtrans-gateway-installmentoff.php @@ -117,7 +117,7 @@ public function process_payment( $order_id ) { // Empty the cart because payment is initiated. $woocommerce->cart->empty_cart(); try { - $snapResponse = WC_Midtrans_API::createSnapTransaction( $params, $this->id ); + $snapResponse = WC_Midtrans_API::createSnapTransactionHandleDuplicate( $order, $params, $this->id ); } catch (Exception $e) { $this->setLogError( $e->getMessage() ); WC_Midtrans_Utils::json_print_exception( $e, $this ); diff --git a/class/class.midtrans-gateway-notif-handler.php b/class/class.midtrans-gateway-notif-handler.php index 1550f61..37040bd 100644 --- a/class/class.midtrans-gateway-notif-handler.php +++ b/class/class.midtrans-gateway-notif-handler.php @@ -100,11 +100,19 @@ public function handleMidtransNotificationRequest() { $sanitizedPost['response'] = isset($_POST['response'])? sanitize_text_field($_POST['response']): null; + // @TAG: order-id-suffix-handling + $sanitized['order_id'] = + WC_Midtrans_Utils::check_and_restore_original_order_id($sanitized['order_id']); + // check whether the request is POST or GET, // @TODO: refactor this conditions, this doesn't quite represent conditions for a POST request if(empty($sanitized['order_id']) && empty($sanitizedPost['id']) && empty($sanitized['id']) && empty($sanitizedPost['response'])) { // Request is POST, proceed to create new notification, then update the payment status $raw_notification = $this->doEarlyAckResponse(); + + // @TAG: order-id-suffix-handling + $raw_notification['order_id'] = + WC_Midtrans_Utils::check_and_restore_original_order_id($raw_notification['order_id']); // Get WooCommerce order $wcorder = wc_get_order( $raw_notification['order_id'] ); // exit if the order id doesn't exist in WooCommerce dashboard @@ -122,7 +130,11 @@ public function handleMidtransNotificationRequest() { $midtrans_notification = WC_Midtrans_API::getStatusFromMidtransNotif( $plugin_id ); // If notification verified, handle it if (in_array($midtrans_notification->status_code, array(200, 201, 202, 407))) { - if (wc_get_order($midtrans_notification->order_id) != false) { + // @TAG: order-id-suffix-handling + $order_id = + WC_Midtrans_Utils::check_and_restore_original_order_id($midtrans_notification->order_id); + // @TODO: relocate this check into the function itself, to prevent unnecessary double DB query load + if (wc_get_order($order_id) != false) { do_action( "midtrans-handle-valid-notification", $midtrans_notification, $plugin_id ); } } @@ -170,6 +182,10 @@ public function handleMidtransNotificationRequest() { // if customer redirected from async payment with POST `response` (CIMB clicks, etc) } else if ( !empty($sanitizedPost['response']) ){ $responses = json_decode( stripslashes($sanitizedPost['response']), true); + + // @TAG: order-id-suffix-handling + $responses['order_id'] = + WC_Midtrans_Utils::check_and_restore_original_order_id($responses['order_id']); $order = new WC_Order( $responses['order_id'] ); // if async payment paid if ( $responses['status_code'] == 200) { @@ -193,7 +209,11 @@ public function handleMidtransNotificationRequest() { // But actually, BCA Klikpay already handled on finish-url-page.php, evaluate if this still needed $plugin_id = wc_get_order( $sanitized['id'] )->get_payment_method(); $midtrans_notification = WC_Midtrans_API::getMidtransStatus($id, $plugin_id); - $order_id = $midtrans_notification->order_id; + + // @TODO remove this order_id? seems unused + // @TAG: order-id-suffix-handling + $order_id = + WC_Midtrans_Utils::check_and_restore_original_order_id($midtrans_notification->order_id); // if async payment paid if ($midtrans_notification->transaction_status == 'settlement'){ $this->checkAndRedirectUserToFinishUrl(); @@ -219,10 +239,10 @@ public function handleMidtransNotificationRequest() { */ public function handleMidtransValidNotificationRequest( $midtrans_notification, $plugin_id = 'midtrans' ) { global $woocommerce; - - $order = new WC_Order( $midtrans_notification->order_id ); + // @TAG: order-id-suffix-handling + $order_id = WC_Midtrans_Utils::check_and_restore_original_order_id($midtrans_notification->order_id); + $order = new WC_Order( $order_id ); $order->add_order_note(__('Midtrans HTTP notification received: '.$midtrans_notification->transaction_status.'. Midtrans-'.$midtrans_notification->payment_type,'midtrans-woocommerce')); - $order_id = $midtrans_notification->order_id; // allow merchant-defined custom action function to perform action on $order upon notif handling do_action( 'midtrans_on_notification_received', $order, $midtrans_notification ); @@ -309,8 +329,11 @@ public function validateRefundNotif( $midtrans_notification ) { } $refund_request = $midtrans_notification->refunds[$lastArrayIndex]; + // @TAG: order-id-suffix-handling + $order_id = + WC_Midtrans_Utils::check_and_restore_original_order_id($midtrans_notification->order_id); // Validate the refund doesn't charge twice by the refund last index - $order_notes = wc_get_order_notes(array('order_id' => $midtrans_notification->order_id)); + $order_notes = wc_get_order_notes(array('order_id' => $order_id)); foreach($order_notes as $value) { if (strpos($value->content, $refund_request->refund_key ) !== false) { return false; @@ -327,10 +350,13 @@ public function validateRefundNotif( $midtrans_notification ) { * @return void */ public function checkAndHandleWCSubscriptionTxnNotif( $midtrans_notification, $order ) { + // @TAG: order-id-suffix-handling + $order_id = + WC_Midtrans_Utils::check_and_restore_original_order_id($midtrans_notification->order_id); // Process if this is a subscription transaction - if ( wcs_order_contains_subscription( $midtrans_notification->order_id ) || wcs_is_subscription( $midtrans_notification->order_id ) || wcs_order_contains_renewal( $midtrans_notification->order_id ) ) { + if ( wcs_order_contains_subscription( $order_id ) || wcs_is_subscription( $order_id ) || wcs_order_contains_renewal( $order_id ) ) { // if not subscription and wc status pending, don't process (because that's a recurring transaction) - if ( wcs_order_contains_renewal( $midtrans_notification->order_id) && $order->get_status() == 'pending' ) { + if ( wcs_order_contains_renewal( $order_id) && $order->get_status() == 'pending' ) { return false; } $subscriptions = wcs_get_subscriptions_for_order( $order, array( 'order_type' => 'any' ) ); diff --git a/class/class.midtrans-gateway-paymentrequest.php b/class/class.midtrans-gateway-paymentrequest.php index a69bd7d..e9573d9 100755 --- a/class/class.midtrans-gateway-paymentrequest.php +++ b/class/class.midtrans-gateway-paymentrequest.php @@ -81,7 +81,7 @@ function process_payment( $order_id ) { // Empty the cart because payment is initiated. $woocommerce->cart->empty_cart(); try { - $snapResponse = WC_Midtrans_API::createSnapTransaction( $params, $this->id ); + $snapResponse = WC_Midtrans_API::createSnapTransactionHandleDuplicate( $order, $params, $this->id ); } catch (Exception $e) { $this->setLogError( $e->getMessage() ); WC_Midtrans_Utils::json_print_exception( $e, $this ); diff --git a/class/class.midtrans-gateway-promo.php b/class/class.midtrans-gateway-promo.php index 71ac373..df9178c 100755 --- a/class/class.midtrans-gateway-promo.php +++ b/class/class.midtrans-gateway-promo.php @@ -112,7 +112,7 @@ function process_payment( $order_id ) { $woocommerce->cart->empty_cart(); try { - $snapResponse = WC_Midtrans_API::createSnapTransaction( $params, $this->id ); + $snapResponse = WC_Midtrans_API::createSnapTransactionHandleDuplicate( $order, $params, $this->id ); } catch (Exception $e) { $this->setLogError( $e->getMessage() ); WC_Midtrans_Utils::json_print_exception( $e, $this ); diff --git a/class/class.midtrans-gateway-subscription.php b/class/class.midtrans-gateway-subscription.php index 4941837..096f28b 100644 --- a/class/class.midtrans-gateway-subscription.php +++ b/class/class.midtrans-gateway-subscription.php @@ -109,7 +109,7 @@ function process_payment( $order_id ) { // Empty the cart because payment is initiated. $woocommerce->cart->empty_cart(); try { - $snapResponse = WC_Midtrans_API::createSnapTransaction( $params, $this->id ); + $snapResponse = WC_Midtrans_API::createSnapTransactionHandleDuplicate( $order, $params, $this->id ); } catch (Exception $e) { $this->setLogError( $e->getMessage() ); WC_Midtrans_Utils::json_print_exception( $e, $this ); diff --git a/class/class.midtrans-gateway.php b/class/class.midtrans-gateway.php index 0c60803..8ed29af 100755 --- a/class/class.midtrans-gateway.php +++ b/class/class.midtrans-gateway.php @@ -132,7 +132,7 @@ public function process_payment_helper( $order_id, $options = false ) { // allow merchant-defined custom filter function to modify snap $params $params = apply_filters( 'midtrans_snap_params_main_before_charge', $params ); try { - $snapResponse = WC_Midtrans_API::createSnapTransaction( $params, $this->id ); + $snapResponse = WC_Midtrans_API::createSnapTransactionHandleDuplicate( $order, $params, $this->id ); } catch (Exception $e) { $this->setLogError( $e->getMessage() ); WC_Midtrans_Utils::json_print_exception( $e, $this ); diff --git a/class/class.midtrans-utils.php b/class/class.midtrans-utils.php index 4cb0926..7de6a0f 100644 --- a/class/class.midtrans-utils.php +++ b/class/class.midtrans-utils.php @@ -130,5 +130,40 @@ function wp_get_inline_script_tag($javascript, $attributes = array()){ } } + /** + * In case Snap API return 406 duplicate order ID, this helper func will generate + * new order id that is to prevent duplicate, by adding suffix on the order_id string + * @TAG: order-suffix-separator + * @param string the original WC order_id + * @return string the non duplicate order_id added with suffix + */ + public static function generate_non_duplicate_order_id($order_id){ + $suffix_separator = '-wc-mdtrs-'; + $date = new DateTime(); + $unix_timestamp = $date->getTimestamp(); + + $non_duplicate_order_id = $order_id.$suffix_separator.$unix_timestamp; + return $non_duplicate_order_id; + } + + /** + * Retrieve original WC order_id from a non duplicate order_id produced by function above: + * generate_non_duplicate_order_id. This will check if the suffix separator exist, + * and split it to get the original order_id. + * @TAG: order-suffix-separator + * @param string any order_id either original or non duplicate version + * @return string the original WC order_id + */ + public static function check_and_restore_original_order_id($non_duplicate_order_id){ + $suffix_separator = '-wc-mdtrs-'; + $original_order_id = $non_duplicate_order_id; + if(strpos($non_duplicate_order_id, $suffix_separator) !== false){ + $splitted_order_id_strings = explode($suffix_separator, $non_duplicate_order_id); + // only return the left-side of the separator, ignore the rest + $original_order_id = $splitted_order_id_strings[0]; + } + return $original_order_id; + } + } ?> \ No newline at end of file diff --git a/public/js/midtrans-payment-page-main.js b/public/js/midtrans-payment-page-main.js index 739d9de..cf0ad3b 100644 --- a/public/js/midtrans-payment-page-main.js +++ b/public/js/midtrans-payment-page-main.js @@ -3,6 +3,21 @@ ;(function( $, window, document ) { var payButton = document.getElementById("pay-button"); + /** + * JS version of func `check_and_restore_original_order_id` of class `WC_Midtrans_Utils` + * @TAG: order-suffix-separator + */ + function check_and_restore_original_order_id(non_duplicate_order_id){ + var suffix_separator = '-wc-mdtrs-'; + var original_order_id = non_duplicate_order_id; + if(non_duplicate_order_id && non_duplicate_order_id.indexOf(suffix_separator)>0){ + var splitted_order_id_strings = non_duplicate_order_id.split(suffix_separator); + // only return the left-side of the separator, ignore the rest + original_order_id = splitted_order_id_strings[0]; + } + return original_order_id; + } + function MixpanelTrackResult(token, merchant_id, cms_name, cms_version, plugin_name, plugin_version, status, result) { var eventNames = { pay: 'pg-pay', @@ -71,6 +86,9 @@ if(wc_midtrans.is_using_map_finish_url){ var finish_url = result.finish_redirect_url; } else { + // @TODO: `&order_id=` param may no longer needed, since we use finish_url_user_cookies + // @TAG: order-id-suffix-handling + result.order_id = check_and_restore_original_order_id(result.order_id); var finish_url = wc_midtrans.finish_url+"&order_id="+result.order_id+"&status_code="+result.status_code+"&transaction_status="+result.transaction_status; } window.location = finish_url; @@ -81,6 +99,8 @@ if (result.fraud_status == 'challenge'){ // if challenge redirect to finish payButton.innerHTML = "Loading..."; + // @TAG: order-id-suffix-handling + result.order_id = check_and_restore_original_order_id(result.order_id); window.location = wc_midtrans.finish_url+"&order_id="+result.order_id+"&status_code="+result.status_code+"&transaction_status="+result.transaction_status; } @@ -88,6 +108,8 @@ // prevent redirect var pending_url = '#'; } else { + // @TAG: order-id-suffix-handling + result.order_id = check_and_restore_original_order_id(result.order_id); var pending_url = wc_midtrans.pending_url+"&order_id="+result.order_id+"&status_code="+result.status_code+"&transaction_status="+result.transaction_status; // redirect to thank you page window.location = pending_url; @@ -106,6 +128,8 @@ MixpanelTrackResult(SNAP_TOKEN, MERCHANT_ID, CMS_NAME, CMS_VERSION, PLUGIN_NAME, PLUGIN_VERSION, 'error', result); // console.log(result?result:'no result'); payButton.innerHTML = "Loading..."; + // @TAG: order-id-suffix-handling + result.order_id = check_and_restore_original_order_id(result.order_id); window.location = wc_midtrans.error_url+"&order_id="+result.order_id+"&status_code="+result.status_code+"&transaction_status="+result.transaction_status; }, onClose: function(){ diff --git a/readme.txt b/readme.txt index 53fcd1d..61b47c9 100644 --- a/readme.txt +++ b/readme.txt @@ -73,6 +73,7 @@ The best way please email to support@midtrans.com, but bugs can be reported in o == Changelog == = 2.31.0 - 2021-08-10 = +* handle duplicated Snap order_id (incase WP is reinstalled, or DB restored) by auto-adding suffix * improvement on finish url redirect flow, to prevent issue * handle uncaught error on finish url * immediate-reduce-stock disabled by default @@ -261,6 +262,7 @@ The best way please email to support@midtrans.com, but bugs can be reported in o == Upgrade Notice == = 2.31.0 - 2021-08-10 = +* handle duplicated Snap order_id (incase WP is reinstalled, or DB restored) by auto-adding suffix * improvement on finish url redirect flow, to prevent issue * handle uncaught error on finish url * immediate-reduce-stock disabled by default From 4d2534698aa5162a933f0cfac6d5e60f37b600c0 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Thu, 26 Aug 2021 17:09:15 +0700 Subject: [PATCH 11/13] add link to feedback form on main gateway desc --- class/class.midtrans-gateway.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/class/class.midtrans-gateway.php b/class/class.midtrans-gateway.php index 8ed29af..9d96737 100755 --- a/class/class.midtrans-gateway.php +++ b/class/class.midtrans-gateway.php @@ -199,7 +199,7 @@ protected function getDefaultTitle () { * @return string */ protected function getSettingsDescription() { - return __('Secure payment via Midtrans that accept various payment methods, with mobile friendly built-in interface, or (optionally) redirection. This is the main payment button, 1 single button for multiple available payments methods. Please follow "how-to configure guide" here.', 'midtrans-woocommerce'); + return __('Secure payment via Midtrans that accept various payment methods, with mobile friendly built-in interface, or (optionally) redirection. This is the main payment button, 1 single button for multiple available payments methods. Please follow "how-to configure guide" here. Any feedback & request let us know here.', 'midtrans-woocommerce'); } /** From 655b046dfc8eb57a843d03c84a1fa8651194e8d7 Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Thu, 26 Aug 2021 17:10:11 +0700 Subject: [PATCH 12/13] improve and sync readme --- README.md | 14 ++++++++------ readme.txt | 12 ++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index ca24de5..d1dea89 100644 --- a/README.md +++ b/README.md @@ -8,21 +8,23 @@ Also [Available on Wordpress plugin store](https://wordpress.org/plugins/midtran ### Description -This plugin will allow secure online payment on your WooCommerce store, without your customer ever need to leave your WooCommerce store! With beautiful responsive payment interface built-in. -Midtrans  is an online payment gateway. They strive to make payments simple for both the merchant and customers. -Support various online payment channel. -Support WooCommerce v3 & v2. +This plugin will allow secure online payment on your WooCommerce store, without your customer ever need to leave your WooCommerce store! + +Midtrans-WooCommerce is official plugin from [Midtrans](https://midtrans.com). Midtrans is an online payment gateway. We strive to make payments simple & secure for both the merchant and customers. Support various online payment channel. Support WooCommerce v3 & v2. + +Please follow [this step by step guide](https://docs.midtrans.com/en/snap/with-plugins?id=wordpress-woocommerce) for complete configuration. If you have any feedback or request, please [do let us know here](https://docs.midtrans.com/en/snap/with-plugins?id=feedback-and-request). Payment Method Feature: * Credit card fullpayment and other payment methods. -* Bank transfer, internet banking for various banks +* E-wallet, Bank transfer, internet banking for various banks * Credit card Online & offline installment payment. * Credit card BIN, bank transfer, and other channel promo payment. * Credit card MIGS acquiring channel. * Custom expiry. * Two-click & One-click feature. -* Midtrans Snap all payment method fullpayment. +* Midtrans Snap all supported payment method. +* Optional: Separated specific payment buttons with its own icons. ### Installation diff --git a/readme.txt b/readme.txt index 61b47c9..70c9ddd 100644 --- a/readme.txt +++ b/readme.txt @@ -13,21 +13,21 @@ Midtrans-WooCommerce is plugin for Midtrans, Indonesian Payment Gateway. Brings This plugin will allow secure online payment on your WooCommerce store, without your customer ever need to leave your WooCommerce store! -Midtrans-WooCommerce is official plugin from [Midtrans](https://midtrans.com), Indonesian Payment Gateway. Brings safety and highly dedicated to customer experience (UX) to WooCommerce.Support various online payment channel. -Support WooCommerce v3 & v2. +Midtrans-WooCommerce is official plugin from [Midtrans](https://midtrans.com). Midtrans is an online payment gateway. We strive to make payments simple & secure for both the merchant and customers. Support various online payment channel. Support WooCommerce v3 & v2. -Please follow [this step by step guide](https://docs.midtrans.com/en/snap/with-plugins?id=wordpress-woocommerce) for complete configuration. +Please follow [this step by step guide](https://docs.midtrans.com/en/snap/with-plugins?id=wordpress-woocommerce) for complete configuration. If you have any feedback or request, please [do let us know here](https://docs.midtrans.com/en/snap/with-plugins?id=feedback-and-request). Payment Method Feature: * Credit card fullpayment and other payment methods. -* Bank transfer, internet banking for various banks +* E-wallet, Bank transfer, internet banking for various banks * Credit card Online & offline installment payment. * Credit card BIN, bank transfer, and other channel promo payment. * Credit card MIGS acquiring channel. * Custom expiry. * Two-click & One-click feature. -* Midtrans Snap all payment method fullpayment. +* Midtrans Snap all supported payment method. +* Optional: Separated specific payment buttons with its own icons. == Installation == @@ -421,6 +421,6 @@ Support additional feature like installment, MIGS acq, and bin promo. == Get Help == * [Midtrans WooCommerce Configuration Guide](https://docs.midtrans.com/en/snap/with-plugins?id=wordpress-woocommerce) * [Midtrans registration](https://account.midtrans.com/register) +* [Midtrans Support Contact](https://midtrans.com/id/contact-us) * [Midtrans Documentation](https://docs.midtrans.com) -* [Midtrans Snap API Documentation](https://snap-docs.midtrans.com) * [Midtrans-WooCommerce Wiki](https://github.com/veritrans/SNAP-Woocommerce/wiki) \ No newline at end of file From e60d6ccf44ae930add93e98e32de90d3dd11d45e Mon Sep 17 00:00:00 2001 From: rizdaprasetya Date: Thu, 26 Aug 2021 17:12:06 +0700 Subject: [PATCH 13/13] update changelog date --- readme.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.txt b/readme.txt index 70c9ddd..ede9605 100644 --- a/readme.txt +++ b/readme.txt @@ -72,7 +72,7 @@ The best way please email to support@midtrans.com, but bugs can be reported in o == Changelog == -= 2.31.0 - 2021-08-10 = += 2.31.0 - 2021-08-26 = * handle duplicated Snap order_id (incase WP is reinstalled, or DB restored) by auto-adding suffix * improvement on finish url redirect flow, to prevent issue * handle uncaught error on finish url @@ -261,7 +261,7 @@ The best way please email to support@midtrans.com, but bugs can be reported in o == Upgrade Notice == -= 2.31.0 - 2021-08-10 = += 2.31.0 - 2021-08-26 = * handle duplicated Snap order_id (incase WP is reinstalled, or DB restored) by auto-adding suffix * improvement on finish url redirect flow, to prevent issue * handle uncaught error on finish url