From 3eeb71bf6956bd921ca1dc196d65f6a51cae4d03 Mon Sep 17 00:00:00 2001 From: htdat Date: Mon, 17 Apr 2017 21:46:56 +0700 Subject: [PATCH 01/16] The skeleton files for OnePay Domestic --- inc/class-wooviet-onepay-domestic.php | 86 +++++++++++++++++++++++++++ inc/onepay/domestic-settings.php | 71 ++++++++++++++++++++++ woo-viet.php | 13 ++++ 3 files changed, 170 insertions(+) create mode 100644 inc/class-wooviet-onepay-domestic.php create mode 100644 inc/onepay/domestic-settings.php diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php new file mode 100644 index 0000000..8a6666b --- /dev/null +++ b/inc/class-wooviet-onepay-domestic.php @@ -0,0 +1,86 @@ +id = 'wooviet_onepay_domestic'; + $this->has_fields = false; + $this->order_button_text = __( 'Proceed to OnePay', 'woo-viet' ); + $this->method_title = __( 'OnePay Domestic Gateway (by Woo Viet)', 'woo-viet' ); + // @todo - check the method description + $this->method_description = __( 'OnePay supports all major bank ATMs in Vietnam.', 'woo-viet' ); + $this->supports = array( + 'products', + ); + // Load the settings. + $this->init_form_fields(); + $this->init_settings(); + // Define user set variables. + $this->title = $this->get_option( 'title' ); + $this->description = $this->get_option( 'description' ); + $this->merchant_id = $this->get_option( 'merchant_id' ); + $this->access_code = $this->get_option( 'access_code' ); + $this->secure_secret = $this->get_option( 'secure_secret' ); + + // @todo: the sandbox option + + add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); + } + /** + * Initialise Gateway Settings Form Fields. + */ + public function init_form_fields() { + $this->form_fields = include( 'onepay/domestic-settings.php' ); + } + /** + * Process the payment. + */ + public function process_payment( $order_id ) { + $order = wc_get_order( $order_id ); + return array( + 'result' => 'success', + 'redirect' => $this->get_pay_url( $order ) + ); + } + /** + * Get the OnePay pay URL for an order. + * @param WC_Order $order + * @return string + */ + public function get_pay_url ( $order ) { + $access_key = $this->access_key; + $secret = $this->secret; // require your secret key from 1pay + $return_url = $this->get_1pay_return_url(); + $command = 'request_transaction'; + $amount = $order->get_total(); // >10000 + $order_id = $order->id; + $order_info = sprintf( 'The payment for the order number %1$s on the site: %2$s', $order->id, get_home_url()); + + // @todo: review and see the file do.php in the demo files + + } + + // @todo review this function + /* + public function static get_return_url(){ + return WC()->api_request_url( __CLASS__ ); + } + */ +} diff --git a/inc/onepay/domestic-settings.php b/inc/onepay/domestic-settings.php new file mode 100644 index 0000000..baa53d4 --- /dev/null +++ b/inc/onepay/domestic-settings.php @@ -0,0 +1,71 @@ + array( + 'title' => __( 'Enable/Disable', 'woo-viet' ), + 'type' => 'checkbox', + 'label' => __( 'OnePay Domestic Gateway (by Woo Viet)', 'woo-viet' ), + 'default' => 'yes' + ), + 'title' => array( + 'title' => __( 'Title', 'woo-viet' ), + 'type' => 'text', + 'description' => __( 'This controls the title which the user sees during checkout.', 'woo-viet' ), + 'default' => __( 'OnePay Domestic Gateway', 'woo-viet' ), + 'desc_tip' => true, + ), + 'description' => array( + 'title' => __( 'Description', 'woo-viet' ), + 'type' => 'text', + 'desc_tip' => true, + 'description' => __( 'This controls the description which the user sees during checkout.', 'woo-viet' ), + 'default' => __( 'With OnePay Bank, you can make payment by using any local Vietnam ATM card.', 'woo-viet' ) + ), + 'api_details' => array( + 'title' => __( 'API Credentials', 'woo-viet' ), + 'type' => 'title', + 'description' => sprintf( __( 'Enter your OnePay API credentials. Contact OnePay to have your credentials %shere%s.', 'woo-viet' ), '', '' ), + ), + 'merchant_id' => array( + 'title' => __( 'Merchant ID', 'woo-viet' ), + 'type' => 'text', + 'description' => __( 'Get your Merchant ID from OnePay.', 'woo-viet' ), + 'default' => '', + 'desc_tip' => true, + 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) + ), + 'access code' => array( + 'title' => __( 'Access Code', 'woocommerce' ), + 'type' => 'text', + 'description' => __( 'Get your Access Code from from OnePay.', 'woo-viet' ), + 'default' => '', + 'desc_tip' => true, + 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) + ), + 'secure_secret' => array( + 'title' => __( 'Secure Secret', 'woocommerce' ), + 'type' => 'text', + 'description' => __( 'Get your Secure Secret from from OnePay.', 'woo-viet' ), + 'default' => '', + 'desc_tip' => true, + 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) + ), + /* + // @todo: Add more help info later + + 'help_title' => array( + 'title' => __( 'More info about 1Pay', 'woo-viet' ), + 'type' => 'title', + 'description' => __( 'You can see more info at this link.', 'woo-viet' ) + ), + */ + +); \ No newline at end of file diff --git a/woo-viet.php b/woo-viet.php index e056150..2b4b469 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -119,11 +119,24 @@ class WooViet { load_plugin_textdomain( 'woo-viet', false, basename( dirname( __FILE__ ) ) . '/languages/' ); } + + public function add_gateway_class( $methods ) { + $methods[] = 'WooViet_OnePay_Domestic'; + return $methods; + + } + /** * The main method to load the components */ public function main() { + // @todo: ver 1.3 check this + add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateway_class' ) ); + + include( 'inc/class-wooviet-onepay-domestic.php'); + + if ( is_admin() ) { // Add the admin setting page include( WOO_VIET_DIR . 'inc/class-wooviet-admin-page.php' ); From 5f43aeb47daccab76f189e38541c43c9a8ef797b Mon Sep 17 00:00:00 2001 From: htdat Date: Tue, 18 Apr 2017 10:06:25 +0700 Subject: [PATCH 02/16] Finish: Build the payment URL --- inc/class-wooviet-onepay-domestic.php | 81 ++++++++++++++++++++++----- inc/onepay/domestic-settings.php | 11 +++- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index 8a6666b..a10bbf4 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -1,5 +1,4 @@ title = $this->get_option( 'title' ); $this->description = $this->get_option( 'description' ); + $this->testmode = 'yes' === $this->get_option( 'testmode', 'no' ); $this->merchant_id = $this->get_option( 'merchant_id' ); $this->access_code = $this->get_option( 'access_code' ); $this->secure_secret = $this->get_option( 'secure_secret' ); @@ -65,22 +65,75 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { * @return string */ public function get_pay_url ( $order ) { - $access_key = $this->access_key; - $secret = $this->secret; // require your secret key from 1pay - $return_url = $this->get_1pay_return_url(); - $command = 'request_transaction'; - $amount = $order->get_total(); // >10000 - $order_id = $order->id; - $order_info = sprintf( 'The payment for the order number %1$s on the site: %2$s', $order->id, get_home_url()); + $args = array( + 'Title' => __('OnePay Payment Title', 'woo-viet'), + 'vpc_Merchant' => $this->merchant_id, + 'vpc_AccessCode' => $this->access_code, + 'vpc_MerchTxnRef' => sprintf('%1$s_%2$s', $order->id, date ( 'YmdHis' )), + 'vpc_OrderInfo' => substr( + sprintf('Order #%1$s - %2$s', $order->id, get_home_url()), + 0, + 32 ), // Limit 32 characters + 'vpc_Amount' => $order->get_total() * 100, // Multiplying 100 is a requirement from OnePay + 'vpc_ReturnURL' => $this->get_onepay_return_url(), + 'vpc_Version' => '2', + 'vpc_Command' => 'pay', + 'vpc_Locale' => ( 'vi' == get_locale() ) ? 'vn' : 'en', + 'vpc_Currency' => 'VND', + 'vpc_TicketNo' => $_SERVER['REMOTE_ADDR'], + ); + + // Get the secure hash + $vpc_SecureHash = $this->create_vpc_SecureHash( $args ); + + // Add the secure hash to the args + $args['vpc_SecureHash'] = $vpc_SecureHash; + $http_args = http_build_query( $args, '', '&' ); + + + if ( $this->testmode ) { + return 'https://mtf.onepay.vn/onecomm-pay/vpc.op?' . $http_args; + } else { + return 'https://onepay.vn/onecomm-pay/vpc.op?' . $http_args; + } + - // @todo: review and see the file do.php in the demo files } - - // @todo review this function - /* - public function static get_return_url(){ + // @todo: need to check this and WC_Payment_Gateway::get_return_url($order = NULL) + public function get_onepay_return_url(){ return WC()->api_request_url( __CLASS__ ); } - */ + + /** + * Get the PayPal request URL for an order. + * @param array $args + * @return string + */ + public function create_vpc_SecureHash ( $args ){ + $stringHashData = ""; + + // arrange array data a-z before make a hash + ksort ($args ); + + foreach($args as $key => $value) { + + // tạo chuỗi đầu dữ liệu những tham số có dữ liệu + if (strlen($value) > 0) { + //sử dụng cả tên và giá trị tham số để mã hóa + if ((strlen($value) > 0) && ((substr($key, 0,4)=="vpc_") || (substr($key,0,5) =="user_"))) { + $stringHashData .= $key . "=" . $value . "&"; + } + } + } + //xóa ký tự & ở thừa ở cuối chuỗi dữ liệu mã hóa***************************** + $stringHashData = rtrim($stringHashData, "&"); + + return strtoupper(hash_hmac('SHA256', $stringHashData, pack('H*', $this->secure_secret ))); + } + + public function process_return_url (){ + // http://localhost/woo-viet/wc-api/WooViet_OnePay_Domestic/?vpc_AdditionData=686868&vpc_Amount=40000000&vpc_Command=pay&vpc_CurrencyCode=VND&vpc_Locale=en&vpc_MerchTxnRef=%23133_20170418024557&vpc_Merchant=ONEPAY&vpc_OrderInfo=%23133+-+http%3A%2F%2Flocalhost%2Fwoo-viet&vpc_TransactionNo=1576998&vpc_TxnResponseCode=0&vpc_Version=2&vpc_SecureHash=25C4443CFF95F6D5BCE4AD86DAA6756960688BD8868CBE898989125050504361 + } + } diff --git a/inc/onepay/domestic-settings.php b/inc/onepay/domestic-settings.php index baa53d4..aa77cd3 100644 --- a/inc/onepay/domestic-settings.php +++ b/inc/onepay/domestic-settings.php @@ -15,6 +15,13 @@ return array( 'label' => __( 'OnePay Domestic Gateway (by Woo Viet)', 'woo-viet' ), 'default' => 'yes' ), + 'testmode' => array( + 'title' => __( 'OnePay Sandbox', 'woocommerce' ), + 'type' => 'checkbox', + 'label' => __( 'Enable OnePay sandbox (testing)', 'woocommerce' ), + 'default' => 'no', + 'description' => sprintf( __( 'OnePay sandbox can be used to test payments. See the testing info.', 'woocommerce' ), 'https://mtf.onepay.vn/developer/?page=modul_noidia' ), + ), 'title' => array( 'title' => __( 'Title', 'woo-viet' ), 'type' => 'text', @@ -27,7 +34,7 @@ return array( 'type' => 'text', 'desc_tip' => true, 'description' => __( 'This controls the description which the user sees during checkout.', 'woo-viet' ), - 'default' => __( 'With OnePay Bank, you can make payment by using any local Vietnam ATM card.', 'woo-viet' ) + 'default' => __( 'With OnePay, you can make payment by using any local Vietnam ATM card.', 'woo-viet' ) ), 'api_details' => array( 'title' => __( 'API Credentials', 'woo-viet' ), @@ -42,7 +49,7 @@ return array( 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) ), - 'access code' => array( + 'access_code' => array( 'title' => __( 'Access Code', 'woocommerce' ), 'type' => 'text', 'description' => __( 'Get your Access Code from from OnePay.', 'woo-viet' ), From cb989175a5a117c4f00bfd5f734cd591d633e3c5 Mon Sep 17 00:00:00 2001 From: htdat Date: Tue, 18 Apr 2017 19:01:50 +0700 Subject: [PATCH 03/16] Added functions to handle IPN and return URL Still need to consider something more --- inc/class-wooviet-onepay-domestic.php | 144 ++++++++++++++++++++++++-- 1 file changed, 135 insertions(+), 9 deletions(-) diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index a10bbf4..cb32156 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -19,11 +19,10 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { * Constructor for the gateway. */ public function __construct() { - $this->id = 'wooviet_onepay_domestic'; + $this->id = strtolower(__CLASS__); $this->has_fields = false; $this->order_button_text = __( 'Proceed to OnePay', 'woo-viet' ); $this->method_title = __( 'OnePay Domestic Gateway (by Woo Viet)', 'woo-viet' ); - // @todo - check the method description $this->method_description = __( 'OnePay supports all major bank ATMs in Vietnam.', 'woo-viet' ); $this->supports = array( 'products', @@ -39,9 +38,11 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { $this->access_code = $this->get_option( 'access_code' ); $this->secure_secret = $this->get_option( 'secure_secret' ); - // @todo: the sandbox option - add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); + + add_action('woocommerce_thankyou_' . $this->id, array($this, 'handle_onepay_return_url')); + + add_action('woocommerce_api_' . strtolower(__CLASS__), array($this, 'handle_onepay_ipn' ) ); } /** * Initialise Gateway Settings Form Fields. @@ -75,7 +76,7 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { 0, 32 ), // Limit 32 characters 'vpc_Amount' => $order->get_total() * 100, // Multiplying 100 is a requirement from OnePay - 'vpc_ReturnURL' => $this->get_onepay_return_url(), + 'vpc_ReturnURL' => $this->get_return_url($order), 'vpc_Version' => '2', 'vpc_Command' => 'pay', 'vpc_Locale' => ( 'vi' == get_locale() ) ? 'vn' : 'en', @@ -100,13 +101,12 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { } - // @todo: need to check this and WC_Payment_Gateway::get_return_url($order = NULL) + // @todo: need to check this and WC_Payment_Gateway::get_return_url($order = NULL). This might be used for IPN only public function get_onepay_return_url(){ return WC()->api_request_url( __CLASS__ ); } /** - * Get the PayPal request URL for an order. * @param array $args * @return string */ @@ -132,8 +132,134 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { return strtoupper(hash_hmac('SHA256', $stringHashData, pack('H*', $this->secure_secret ))); } - public function process_return_url (){ - // http://localhost/woo-viet/wc-api/WooViet_OnePay_Domestic/?vpc_AdditionData=686868&vpc_Amount=40000000&vpc_Command=pay&vpc_CurrencyCode=VND&vpc_Locale=en&vpc_MerchTxnRef=%23133_20170418024557&vpc_Merchant=ONEPAY&vpc_OrderInfo=%23133+-+http%3A%2F%2Flocalhost%2Fwoo-viet&vpc_TransactionNo=1576998&vpc_TxnResponseCode=0&vpc_Version=2&vpc_SecureHash=25C4443CFF95F6D5BCE4AD86DAA6756960688BD8868CBE898989125050504361 + + public function check_vpc_SecureHash ($args, $vpc_SecureHash) { + // Generate the "vpc_SecureHash" value from $args + $vpc_SecureHash_from_args = $this->create_vpc_SecureHash($args); + + if ($vpc_SecureHash_from_args == $vpc_SecureHash ) { + return true; + } else { + return false; + } } + public function handle_onepay_return_url(){ + if (isset($_GET['vpc_SecureHash'])) { + + $this->process_onepay_response_data( $_GET ); + + // @todo NEXT check this part + // Redirect to the return URL without the OnePay parameters + // wp_redirect($this->get_return_url( $order )); + } + } + + public function process_onepay_response_data ($args ) { + $vpc_SecureHash = $args['vpc_SecureHash']; + + // Remove the parameter "vpc_SecureHash" for validating SecureHash + unset($args['vpc_SecureHash']); + + $check_vpc_SecureHash = $this->check_vpc_SecureHash($args, $vpc_SecureHash); + + if ( $check_vpc_SecureHash ) { + /** + * $vpc_MerchTxnRef looks like this "139_20170418101843" or {order_id}_{date_time} + * @see $this->get_pay_url(); + */ + $vpc_MerchTxnRef = $args['vpc_MerchTxnRef']; + + // Get the order_id part only + $order_id = substr($vpc_MerchTxnRef,0,strrpos($vpc_MerchTxnRef,'_')); + + $order = wc_get_order($order_id); + + $vpc_TxnResponseCode = $args['vpc_TxnResponseCode']; + + // The payment was made successfully + if ("0" == $vpc_TxnResponseCode ) { + $order->payment_complete(); + } + + // Add the order note for the reference + $order_note = sprintf( + __('OnePay Domestic Gateway Info | Code: %1$s | Message: %2$s | MerchantTxnRef: %3$s', 'woo-viet'), + $vpc_TxnResponseCode, + $this->OnePay_getResponseDescription($vpc_TxnResponseCode), + $vpc_MerchTxnRef + ); + $order->add_order_note($order_note); + + // return $order; + + } + } + + public function handle_onepay_ipn() { + if (isset($_POST['vpc_SecureHash'])) { + + $this->process_onepay_response_data( $_POST ); + + // Write the response + } + } + + public function OnePay_getResponseDescription($responseCode) { + + switch ($responseCode) { + case "0" : + $result = "Giao dịch thành công - Approved"; + break; + case "1" : + $result = "Ngân hàng từ chối giao dịch - Bank Declined"; + break; + case "3" : + $result = "Mã đơn vị không tồn tại - Merchant not exist"; + break; + case "4" : + $result = "Không đúng access code - Invalid access code"; + break; + case "5" : + $result = "Số tiền không hợp lệ - Invalid amount"; + break; + case "6" : + $result = "Mã tiền tệ không tồn tại - Invalid currency code"; + break; + case "7" : + $result = "Lỗi không xác định - Unspecified Failure "; + break; + case "8" : + $result = "Số thẻ không đúng - Invalid card Number"; + break; + case "9" : + $result = "Tên chủ thẻ không đúng - Invalid card name"; + break; + case "10" : + $result = "Thẻ hết hạn/Thẻ bị khóa - Expired Card"; + break; + case "11" : + $result = "Thẻ chưa đăng ký sử dụng dịch vụ - Card Not Registed Service(internet banking)"; + break; + case "12" : + $result = "Ngày phát hành/Hết hạn không đúng - Invalid card date"; + break; + case "13" : + $result = "Vượt quá hạn mức thanh toán - Exist Amount"; + break; + case "21" : + $result = "Số tiền không đủ để thanh toán - Insufficient fund"; + break; + case "99" : + $result = "Người sủ dụng hủy giao dịch - User cancel"; + break; + default : + $result = "Giao dịch thất bại - Failured"; + } + return $result; + } + + + + } From 70d2182b5044e2682f461079feb79b613aae0911 Mon Sep 17 00:00:00 2001 From: htdat Date: Thu, 20 Apr 2017 17:02:19 +0700 Subject: [PATCH 04/16] Almost finish Need to check: IPN and queryDR And add the option in WooViet settings page --- inc/class-wooviet-onepay-domestic.php | 217 ++++++++++++++++++++------ inc/onepay/domestic-settings.php | 34 ++-- woo-viet.php | 2 + 3 files changed, 196 insertions(+), 57 deletions(-) diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index cb32156..4394147 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -11,9 +11,6 @@ if ( ! defined( 'ABSPATH' ) ) { * */ - - - class WooViet_OnePay_Domestic extends WC_Payment_Gateway { /** * Constructor for the gateway. @@ -27,9 +24,11 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { $this->supports = array( 'products', ); + // Load the settings. $this->init_form_fields(); $this->init_settings(); + // Define user set variables. $this->title = $this->get_option( 'title' ); $this->description = $this->get_option( 'description' ); @@ -37,12 +36,18 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { $this->merchant_id = $this->get_option( 'merchant_id' ); $this->access_code = $this->get_option( 'access_code' ); $this->secure_secret = $this->get_option( 'secure_secret' ); + $this->user = $this->get_option( 'user' ); + $this->password = $this->get_option( 'password' ); + // Process the admin options add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); add_action('woocommerce_thankyou_' . $this->id, array($this, 'handle_onepay_return_url')); add_action('woocommerce_api_' . strtolower(__CLASS__), array($this, 'handle_onepay_ipn' ) ); + + // @todo: check whether or not this can be lodded in the cron job + add_action('wooviet_handle_onepay_querydr', array($this, 'handle_onepay_querydr'), 10, 1); } /** * Initialise Gateway Settings Form Fields. @@ -50,8 +55,12 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { public function init_form_fields() { $this->form_fields = include( 'onepay/domestic-settings.php' ); } + /** - * Process the payment. + * Process the payment + * @param int $order_id + * + * @return array */ public function process_payment( $order_id ) { $order = wc_get_order( $order_id ); @@ -60,8 +69,26 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { 'redirect' => $this->get_pay_url( $order ) ); } + /** - * Get the OnePay pay URL for an order. + * Set the cron job running queryDR in 20 mintues + * Because the OnePay payment timeout is 15 minutes + * + * @param string $vpc_MerchTxnRef + */ + public function set_onepay_querydr_cron( $vpc_MerchTxnRef ) { + + wp_schedule_single_event( + time() + 20 * 60, + 'wooviet_handle_onepay_querydr', + array( $vpc_MerchTxnRef ) // @todo check this + ); + + } + /** + * Get the OnePay pay URL for an order + * AND set the queryDR cron for this transaction + * * @param WC_Order $order * @return string */ @@ -84,6 +111,9 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { 'vpc_TicketNo' => $_SERVER['REMOTE_ADDR'], ); + // Set the queryDR cron for this transaction + $this->set_onepay_querydr_cron($args['vpc_MerchTxnRef']); + // Get the secure hash $vpc_SecureHash = $this->create_vpc_SecureHash( $args ); @@ -91,22 +121,26 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { $args['vpc_SecureHash'] = $vpc_SecureHash; $http_args = http_build_query( $args, '', '&' ); - if ( $this->testmode ) { return 'https://mtf.onepay.vn/onecomm-pay/vpc.op?' . $http_args; } else { return 'https://onepay.vn/onecomm-pay/vpc.op?' . $http_args; } - - } - // @todo: need to check this and WC_Payment_Gateway::get_return_url($order = NULL). This might be used for IPN only - public function get_onepay_return_url(){ + + /** + * Get the IPN URL for OnePay + * Format: http://my-site.com/wc-api/WooViet_OnePay_Domestic/ + */ + static function get_onepay_ipn_url(){ return WC()->api_request_url( __CLASS__ ); } /** + * Create the vpc_SecureHash value. + * @see https://mtf.onepay.vn/developer/?page=modul_noidia_php + * * @param array $args * @return string */ @@ -118,21 +152,28 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { foreach($args as $key => $value) { - // tạo chuỗi đầu dữ liệu những tham số có dữ liệu if (strlen($value) > 0) { - //sử dụng cả tên và giá trị tham số để mã hóa if ((strlen($value) > 0) && ((substr($key, 0,4)=="vpc_") || (substr($key,0,5) =="user_"))) { $stringHashData .= $key . "=" . $value . "&"; } } } - //xóa ký tự & ở thừa ở cuối chuỗi dữ liệu mã hóa***************************** + //Remove the last character "&" $stringHashData = rtrim($stringHashData, "&"); return strtoupper(hash_hmac('SHA256', $stringHashData, pack('H*', $this->secure_secret ))); } - + /** + * Whether or not the arguments and a provided $vpc_SecureHash are the same + * + * @see https://mtf.onepay.vn/developer/?page=modul_noidia_php + * + * @param $args + * @param $vpc_SecureHash + * + * @return bool + */ public function check_vpc_SecureHash ($args, $vpc_SecureHash) { // Generate the "vpc_SecureHash" value from $args $vpc_SecureHash_from_args = $this->create_vpc_SecureHash($args); @@ -143,68 +184,153 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { return false; } } - + /** + * Handle the return URL - GET request from OnePay + */ public function handle_onepay_return_url(){ + if (isset($_GET['vpc_SecureHash'])) { - $this->process_onepay_response_data( $_GET ); + $this->process_onepay_response_data( $_GET, 'return' ); - // @todo NEXT check this part - // Redirect to the return URL without the OnePay parameters - // wp_redirect($this->get_return_url( $order )); } } - public function process_onepay_response_data ($args ) { - $vpc_SecureHash = $args['vpc_SecureHash']; + /** + * Handle the IPN POST request from OnePay + */ + public function handle_onepay_ipn() { - // Remove the parameter "vpc_SecureHash" for validating SecureHash - unset($args['vpc_SecureHash']); + if (isset($_POST['vpc_SecureHash'])) { - $check_vpc_SecureHash = $this->check_vpc_SecureHash($args, $vpc_SecureHash); + $this->process_onepay_response_data( $_POST ); - if ( $check_vpc_SecureHash ) { + } + } + + /** + * Handle the queryDR request + * @param string $vpc_MerchTxnRef + */ + public function handle_onepay_querydr( $vpc_MerchTxnRef ) { + // Build the queryDR link + $args = array( + 'vpc_Command' => 'queryDR', + 'vpc_Version' => '1', + 'vpc_MerchTxnRef' => $vpc_MerchTxnRef, + 'vpc_Merchant' => $this->merchant_id, + 'vpc_AccessCode' => $this->access_code, + 'vpc_User' => $this->user, + 'vpc_Password' => $this->password, + ); + + $http_args = http_build_query( $args, '', '&' ); + + if ( $this->testmode ) { + $http_link = 'https://mtf.onepay.vn/onecomm-pay/Vpcdps.op?' . $http_args; + } else { + $http_link = 'https://onepay.vn/onecomm-pay/Vpcdps.op?' . $http_args; + } + + // Connect to OnePay to get the queryDR info + $http_response = wp_remote_get( $http_link ); + parse_str( wp_remote_retrieve_body( $http_response ), $args_response ); + + // Process the data + $this->process_onepay_response_data($args_response); + + } + + /** + * Handle the repsonse data from OnePay + * @param string $args the response data from OnePay + * @param string $type + */ + public function process_onepay_response_data ($args, $type = '' ) { + $types_accepted = array( + 'return', + 'ipn', + 'querydr', + ); + + // Do nothing if the type is wrong + if ( ! in_array($type, $types_accepted) ) { + return; + } + + $is_secure = false; + $is_querydr_exists = false; + + if ('return' == $type OR 'ipn' == $type ) { + $vpc_SecureHash = $args['vpc_SecureHash']; + + // Remove the parameter "vpc_SecureHash" for validating SecureHash + unset($args['vpc_SecureHash']); + + $is_secure = $this->check_vpc_SecureHash($args, $vpc_SecureHash); + + } elseif ('querydr' == $type ) { + $is_querydr_exists = ( 'Y' == $args['vpc_DRExists'] ); + + } + + // Process the data + if ( $is_secure OR $is_querydr_exists ) { /** * $vpc_MerchTxnRef looks like this "139_20170418101843" or {order_id}_{date_time} * @see $this->get_pay_url(); */ $vpc_MerchTxnRef = $args['vpc_MerchTxnRef']; + $vpc_TxnResponseCode = $args['vpc_TxnResponseCode']; // Get the order_id part only $order_id = substr($vpc_MerchTxnRef,0,strrpos($vpc_MerchTxnRef,'_')); $order = wc_get_order($order_id); - $vpc_TxnResponseCode = $args['vpc_TxnResponseCode']; - - // The payment was made successfully - if ("0" == $vpc_TxnResponseCode ) { - $order->payment_complete(); - } - // Add the order note for the reference $order_note = sprintf( - __('OnePay Domestic Gateway Info | Code: %1$s | Message: %2$s | MerchantTxnRef: %3$s', 'woo-viet'), + __('OnePay Domestic Gateway Info | Code: %1$s | Message: %2$s | MerchantTxnRef: %3$s | Type: %4$s', 'woo-viet'), $vpc_TxnResponseCode, $this->OnePay_getResponseDescription($vpc_TxnResponseCode), - $vpc_MerchTxnRef + $vpc_MerchTxnRef, + $type ); $order->add_order_note($order_note); - // return $order; + // If the payment is successful, update the order + if ("0" == $vpc_TxnResponseCode ) + $order->payment_complete(); + switch ( $type ) { + + case 'return': + wp_redirect($this->get_return_url( $order )); + break; + + case 'ipn': + wp_die('responsecode=1&desc=confirm-success'); + break; + + case 'querydr': + // Do nothing + break; + } + + } else { + if ( 'ipn' == $type ) + wp_die('responsecode=0&desc=confirm-success'); } } - public function handle_onepay_ipn() { - if (isset($_POST['vpc_SecureHash'])) { - - $this->process_onepay_response_data( $_POST ); - - // Write the response - } - } - + /** + * Get the response description based on the response code + * This is code is from OnePay + * + * @param string $responseCode + * + * @return string + */ public function OnePay_getResponseDescription($responseCode) { switch ($responseCode) { @@ -259,7 +385,4 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { return $result; } - - - } diff --git a/inc/onepay/domestic-settings.php b/inc/onepay/domestic-settings.php index aa77cd3..522cb14 100644 --- a/inc/onepay/domestic-settings.php +++ b/inc/onepay/domestic-settings.php @@ -4,7 +4,6 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } -// @todo - ver 1.3 - check all texts /** * Settings for 1Pay Gateway. */ @@ -21,6 +20,7 @@ return array( 'label' => __( 'Enable OnePay sandbox (testing)', 'woocommerce' ), 'default' => 'no', 'description' => sprintf( __( 'OnePay sandbox can be used to test payments. See the testing info.', 'woocommerce' ), 'https://mtf.onepay.vn/developer/?page=modul_noidia' ), + //@todo: add the logo https://mtf.onepay.vn/developer/?page=logo ), 'title' => array( 'title' => __( 'Title', 'woo-viet' ), @@ -31,7 +31,7 @@ return array( ), 'description' => array( 'title' => __( 'Description', 'woo-viet' ), - 'type' => 'text', + 'type' => 'textarea', 'desc_tip' => true, 'description' => __( 'This controls the description which the user sees during checkout.', 'woo-viet' ), 'default' => __( 'With OnePay, you can make payment by using any local Vietnam ATM card.', 'woo-viet' ) @@ -65,14 +65,28 @@ return array( 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) ), - /* - // @todo: Add more help info later - - 'help_title' => array( - 'title' => __( 'More info about 1Pay', 'woo-viet' ), - 'type' => 'title', - 'description' => __( 'You can see more info at this link.', 'woo-viet' ) + 'user' => array( + 'title' => __( 'User for queryDR. Test value: op01', 'woocommerce' ), + 'type' => 'text', + 'description' => __( 'Get your user info from from OnePay.', 'woo-viet' ), + 'default' => '', + 'desc_tip' => true, + 'placeholder' => __( 'Required. Provided by OnePay', 'woo-viet' ) + ), + 'password' => array( + 'title' => __( 'Password for queryDR. Test value: op123456', 'woocommerce' ), + 'type' => 'text', + 'description' => __( 'Get your password info from from OnePay.', 'woo-viet' ), + 'default' => '', + 'desc_tip' => true, + 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) + ), + 'more_info' => array( + 'title' => __( 'Instant Payment Notification (IPN)', 'woo-viet' ), + 'type' => 'title', + 'description' => + sprintf('URL: %s', WooViet_OnePay_Domestic::get_onepay_ipn_url() ) . '

' . + sprintf( __( '%sContact OnePay%s to configure this URL on its site. This is required based on its guidelines.', 'woo-viet' ), '', '' ), ), - */ ); \ No newline at end of file diff --git a/woo-viet.php b/woo-viet.php index 2b4b469..d1b85ee 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -135,6 +135,8 @@ class WooViet { add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateway_class' ) ); include( 'inc/class-wooviet-onepay-domestic.php'); + $WooViet_OnePay_Domestic_Hook = new WooViet_OnePay_Domestic(); + add_action('wooviet_handle_onepay_querydr', array($WooViet_OnePay_Domestic_Hook, 'handle_onepay_querydr'), 10, 1); if ( is_admin() ) { From 0e252a978a855216c3ceb9aea6d110833ebffd52 Mon Sep 17 00:00:00 2001 From: htdat Date: Thu, 20 Apr 2017 17:39:11 +0700 Subject: [PATCH 05/16] Add the option in the Woo Viet setting page --- inc/class-wooviet-admin-page.php | 18 ++++++++++++++++++ woo-viet.php | 24 +++++++++++++++--------- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/inc/class-wooviet-admin-page.php b/inc/class-wooviet-admin-page.php index d572d55..f81f2a6 100644 --- a/inc/class-wooviet-admin-page.php +++ b/inc/class-wooviet-admin-page.php @@ -88,6 +88,24 @@ class WooViet_Admin_Page { value=""> + + + + + @@ -117,14 +118,14 @@ class WooViet_Admin_Page { - diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index cd39918..641a860 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -2,6 +2,7 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } + /** * The class to handle the domestic OnePay gateway https://mtf.onepay.vn/developer/?page=modul_noidia * @@ -10,17 +11,16 @@ if ( ! defined( 'ABSPATH' ) ) { * @since 1.3 * */ - class WooViet_OnePay_Domestic extends WC_Payment_Gateway { /** * Constructor for the gateway. */ public function __construct() { - $this->id = strtolower(__CLASS__); + $this->id = strtolower( __CLASS__ ); $this->has_fields = false; $this->order_button_text = __( 'Proceed to OnePay', 'woo-viet' ); $this->method_title = __( 'OnePay Domestic Gateway (by Woo Viet)', 'woo-viet' ); - $this->method_description = __( 'OnePay supports all major bank ATMs in Vietnam.', 'woo-viet' ); + $this->method_description = __( 'OnePay supports all major bank ATMs in Vietnam.', 'woo-viet' ); $this->supports = array( 'products', ); @@ -30,25 +30,29 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { $this->init_settings(); // Define user set variables. - $this->title = $this->get_option( 'title' ); - $this->description = $this->get_option( 'description' ); - $this->testmode = 'yes' === $this->get_option( 'testmode', 'no' ); - $this->merchant_id = $this->get_option( 'merchant_id' ); - $this->access_code = $this->get_option( 'access_code' ); - $this->secure_secret = $this->get_option( 'secure_secret' ); + $this->title = $this->get_option( 'title' ); + $this->description = $this->get_option( 'description' ); + $this->testmode = 'yes' === $this->get_option( 'testmode', 'no' ); + $this->merchant_id = $this->get_option( 'merchant_id' ); + $this->access_code = $this->get_option( 'access_code' ); + $this->secure_secret = $this->get_option( 'secure_secret' ); $this->user = $this->get_option( 'user' ); - $this->password = $this->get_option( 'password' ); + $this->password = $this->get_option( 'password' ); // Process the admin options - add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) ); + add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( + $this, + 'process_admin_options' + ) ); - add_action('woocommerce_thankyou_' . $this->id, array($this, 'handle_onepay_return_url')); + add_action( 'woocommerce_thankyou_' . $this->id, array( $this, 'handle_onepay_return_url' ) ); - add_action('woocommerce_api_' . strtolower(__CLASS__), array($this, 'handle_onepay_ipn' ) ); + add_action( 'woocommerce_api_' . strtolower( __CLASS__ ), array( $this, 'handle_onepay_ipn' ) ); // @todo: check whether or not this can be lodded in the cron job - add_action('wooviet_handle_onepay_querydr', array($this, 'handle_onepay_querydr'), 10, 1); + add_action( 'wooviet_handle_onepay_querydr', array( $this, 'handle_onepay_querydr' ), 10, 1 ); } + /** * Initialise Gateway Settings Form Fields. */ @@ -56,20 +60,75 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { $this->form_fields = include( 'onepay/domestic-settings.php' ); } + /** + * Get the IPN URL for OnePay + * Format: http://my-site.com/wc-api/WooViet_OnePay_Domestic/ + */ + static function get_onepay_ipn_url() { + return WC()->api_request_url( __CLASS__ ); + } + /** * Process the payment + * * @param int $order_id * * @return array */ public function process_payment( $order_id ) { - $order = wc_get_order( $order_id ); + $order = wc_get_order( $order_id ); + return array( 'result' => 'success', 'redirect' => $this->get_pay_url( $order ) ); } + /** + * Get the OnePay pay URL for an order + * AND set the queryDR cron for this transaction + * + * @param WC_Order $order + * + * @return string + */ + public function get_pay_url( $order ) { + $args = array( + 'Title' => __( 'OnePay Payment Title', 'woo-viet' ), + 'vpc_Merchant' => $this->merchant_id, + 'vpc_AccessCode' => $this->access_code, + 'vpc_MerchTxnRef' => sprintf( '%1$s_%2$s', $order->id, date( 'YmdHis' ) ), + 'vpc_OrderInfo' => substr( + sprintf( 'Order #%1$s - %2$s', $order->id, get_home_url() ), + 0, + 32 ), // Limit 32 characters + 'vpc_Amount' => $order->get_total() * 100, // Multiplying 100 is a requirement from OnePay + 'vpc_ReturnURL' => $this->get_return_url( $order ), + 'vpc_Version' => '2', + 'vpc_Command' => 'pay', + 'vpc_Locale' => ( 'vi' == get_locale() ) ? 'vn' : 'en', + 'vpc_Currency' => 'VND', + 'vpc_TicketNo' => $_SERVER['REMOTE_ADDR'], + ); + + // Set the queryDR cron for this transaction + $this->set_onepay_querydr_cron( $args['vpc_MerchTxnRef'] ); + + // Get the secure hash + $vpc_SecureHash = $this->create_vpc_SecureHash( $args ); + + // Add the secure hash to the args + $args['vpc_SecureHash'] = $vpc_SecureHash; + $http_args = http_build_query( $args, '', '&' ); + + if ( $this->testmode ) { + return 'https://mtf.onepay.vn/onecomm-pay/vpc.op?' . $http_args; + } else { + return 'https://onepay.vn/onecomm-pay/vpc.op?' . $http_args; + } + + } + /** * Set the cron job running queryDR in 20 mintues * Because the OnePay payment timeout is 15 minutes @@ -85,83 +144,131 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { ); } - /** - * Get the OnePay pay URL for an order - * AND set the queryDR cron for this transaction - * - * @param WC_Order $order - * @return string - */ - public function get_pay_url ( $order ) { - $args = array( - 'Title' => __('OnePay Payment Title', 'woo-viet'), - 'vpc_Merchant' => $this->merchant_id, - 'vpc_AccessCode' => $this->access_code, - 'vpc_MerchTxnRef' => sprintf('%1$s_%2$s', $order->id, date ( 'YmdHis' )), - 'vpc_OrderInfo' => substr( - sprintf('Order #%1$s - %2$s', $order->id, get_home_url()), - 0, - 32 ), // Limit 32 characters - 'vpc_Amount' => $order->get_total() * 100, // Multiplying 100 is a requirement from OnePay - 'vpc_ReturnURL' => $this->get_return_url($order), - 'vpc_Version' => '2', - 'vpc_Command' => 'pay', - 'vpc_Locale' => ( 'vi' == get_locale() ) ? 'vn' : 'en', - 'vpc_Currency' => 'VND', - 'vpc_TicketNo' => $_SERVER['REMOTE_ADDR'], - ); - - // Set the queryDR cron for this transaction - $this->set_onepay_querydr_cron($args['vpc_MerchTxnRef']); - - // Get the secure hash - $vpc_SecureHash = $this->create_vpc_SecureHash( $args ); - - // Add the secure hash to the args - $args['vpc_SecureHash'] = $vpc_SecureHash; - $http_args = http_build_query( $args, '', '&' ); - - if ( $this->testmode ) { - return 'https://mtf.onepay.vn/onecomm-pay/vpc.op?' . $http_args; - } else { - return 'https://onepay.vn/onecomm-pay/vpc.op?' . $http_args; - } - - } - - /** - * Get the IPN URL for OnePay - * Format: http://my-site.com/wc-api/WooViet_OnePay_Domestic/ - */ - static function get_onepay_ipn_url(){ - return WC()->api_request_url( __CLASS__ ); - } /** * Create the vpc_SecureHash value. * @see https://mtf.onepay.vn/developer/?page=modul_noidia_php * * @param array $args + * * @return string */ - public function create_vpc_SecureHash ( $args ){ + public function create_vpc_SecureHash( $args ) { $stringHashData = ""; // arrange array data a-z before make a hash - ksort ($args ); + ksort( $args ); - foreach($args as $key => $value) { + foreach ( $args as $key => $value ) { - if (strlen($value) > 0) { - if ((strlen($value) > 0) && ((substr($key, 0,4)=="vpc_") || (substr($key,0,5) =="user_"))) { + if ( strlen( $value ) > 0 ) { + if ( ( strlen( $value ) > 0 ) && ( ( substr( $key, 0, 4 ) == "vpc_" ) || ( substr( $key, 0, 5 ) == "user_" ) ) ) { $stringHashData .= $key . "=" . $value . "&"; } } } //Remove the last character "&" - $stringHashData = rtrim($stringHashData, "&"); + $stringHashData = rtrim( $stringHashData, "&" ); - return strtoupper(hash_hmac('SHA256', $stringHashData, pack('H*', $this->secure_secret ))); + return strtoupper( hash_hmac( 'SHA256', $stringHashData, pack( 'H*', $this->secure_secret ) ) ); + } + + /** + * Handle the return URL - GET request from OnePay + */ + public function handle_onepay_return_url() { + + if ( isset( $_GET['vpc_SecureHash'] ) ) { + + $this->process_onepay_response_data( $_GET, 'return' ); + + } + } + + /** + * Handle the repsonse data from OnePay + * + * @param string $args the response data from OnePay + * @param string $type + */ + public function process_onepay_response_data( $args, $type ) { + $types_accepted = array( + 'return', + 'ipn', + 'querydr', + ); + + // Do nothing if the type is wrong + if ( ! in_array( $type, $types_accepted ) ) { + return; + } + + $is_secure = false; + $is_querydr_exists = false; + + if ( 'return' == $type OR 'ipn' == $type ) { + $vpc_SecureHash = $args['vpc_SecureHash']; + + // Remove the parameter "vpc_SecureHash" for validating SecureHash + unset( $args['vpc_SecureHash'] ); + + $is_secure = $this->check_vpc_SecureHash( $args, $vpc_SecureHash ); + + } elseif ( 'querydr' == $type ) { + $is_querydr_exists = ( 'Y' == $args['vpc_DRExists'] ); + + } + + // Process the data + if ( $is_secure OR $is_querydr_exists ) { + /** + * $vpc_MerchTxnRef looks like this "139_20170418101843" or {order_id}_{date_time} + * @see $this->get_pay_url(); + */ + $vpc_MerchTxnRef = $args['vpc_MerchTxnRef']; + $vpc_TxnResponseCode = $args['vpc_TxnResponseCode']; + + // Get the order_id part only + $order_id = substr( $vpc_MerchTxnRef, 0, strrpos( $vpc_MerchTxnRef, '_' ) ); + + $order = wc_get_order( $order_id ); + + // Add the order note for the reference + $order_note = sprintf( + __( 'OnePay Domestic Gateway Info | Code: %1$s | Message: %2$s | MerchantTxnRef: %3$s | Type: %4$s', 'woo-viet' ), + $vpc_TxnResponseCode, + $this->OnePay_getResponseDescription( $vpc_TxnResponseCode ), + $vpc_MerchTxnRef, + $type + ); + $order->add_order_note( $order_note ); + + // If the payment is successful, update the order + if ( "0" == $vpc_TxnResponseCode ) { + $order->payment_complete(); + } + + switch ( $type ) { + + case 'return': + wp_redirect( $this->get_return_url( $order ) ); + break; + + case 'ipn': + exit( 'responsecode=1&desc=confirm-success' ); + break; + + case 'querydr': + // Do nothing + break; + } + + } else { + if ( 'ipn' == $type ) { + exit( 'responsecode=0&desc=confirm-success' ); + } + + } } /** @@ -174,155 +281,16 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { * * @return bool */ - public function check_vpc_SecureHash ($args, $vpc_SecureHash) { + public function check_vpc_SecureHash( $args, $vpc_SecureHash ) { // Generate the "vpc_SecureHash" value from $args - $vpc_SecureHash_from_args = $this->create_vpc_SecureHash($args); + $vpc_SecureHash_from_args = $this->create_vpc_SecureHash( $args ); - if ($vpc_SecureHash_from_args == $vpc_SecureHash ) { + if ( $vpc_SecureHash_from_args == $vpc_SecureHash ) { return true; } else { return false; } } - /** - * Handle the return URL - GET request from OnePay - */ - public function handle_onepay_return_url(){ - - if (isset($_GET['vpc_SecureHash'])) { - - $this->process_onepay_response_data( $_GET, 'return' ); - - } - } - - /** - * Handle the IPN POST request from OnePay - */ - public function handle_onepay_ipn() { - - if (isset($_REQUEST['vpc_SecureHash'])) { - - $this->process_onepay_response_data( $_REQUEST, 'ipn' ); - - } - } - - /** - * Handle the queryDR request - * @param string $vpc_MerchTxnRef - */ - public function handle_onepay_querydr( $vpc_MerchTxnRef ) { - // Build the queryDR link - $args = array( - 'vpc_Command' => 'queryDR', - 'vpc_Version' => '1', - 'vpc_MerchTxnRef' => $vpc_MerchTxnRef, - 'vpc_Merchant' => $this->merchant_id, - 'vpc_AccessCode' => $this->access_code, - 'vpc_User' => $this->user, - 'vpc_Password' => $this->password, - ); - - $http_args = http_build_query( $args, '', '&' ); - - if ( $this->testmode ) { - $http_link = 'https://mtf.onepay.vn/onecomm-pay/Vpcdps.op?' . $http_args; - } else { - $http_link = 'https://onepay.vn/onecomm-pay/Vpcdps.op?' . $http_args; - } - - // Connect to OnePay to get the queryDR info - $http_response = wp_remote_get( $http_link ); - parse_str( wp_remote_retrieve_body( $http_response ), $args_response ); - - // Process the data - $this->process_onepay_response_data($args_response, 'querydr'); - - } - - /** - * Handle the repsonse data from OnePay - * @param string $args the response data from OnePay - * @param string $type - */ - public function process_onepay_response_data ($args, $type ) { - $types_accepted = array( - 'return', - 'ipn', - 'querydr', - ); - - // Do nothing if the type is wrong - if ( ! in_array($type, $types_accepted) ) { - return; - } - - $is_secure = false; - $is_querydr_exists = false; - - if ('return' == $type OR 'ipn' == $type ) { - $vpc_SecureHash = $args['vpc_SecureHash']; - - // Remove the parameter "vpc_SecureHash" for validating SecureHash - unset($args['vpc_SecureHash']); - - $is_secure = $this->check_vpc_SecureHash($args, $vpc_SecureHash); - - } elseif ('querydr' == $type ) { - $is_querydr_exists = ( 'Y' == $args['vpc_DRExists'] ); - - } - - // Process the data - if ( $is_secure OR $is_querydr_exists ) { - /** - * $vpc_MerchTxnRef looks like this "139_20170418101843" or {order_id}_{date_time} - * @see $this->get_pay_url(); - */ - $vpc_MerchTxnRef = $args['vpc_MerchTxnRef']; - $vpc_TxnResponseCode = $args['vpc_TxnResponseCode']; - - // Get the order_id part only - $order_id = substr($vpc_MerchTxnRef,0,strrpos($vpc_MerchTxnRef,'_')); - - $order = wc_get_order($order_id); - - // Add the order note for the reference - $order_note = sprintf( - __('OnePay Domestic Gateway Info | Code: %1$s | Message: %2$s | MerchantTxnRef: %3$s | Type: %4$s', 'woo-viet'), - $vpc_TxnResponseCode, - $this->OnePay_getResponseDescription($vpc_TxnResponseCode), - $vpc_MerchTxnRef, - $type - ); - $order->add_order_note($order_note); - - // If the payment is successful, update the order - if ("0" == $vpc_TxnResponseCode ) - $order->payment_complete(); - - switch ( $type ) { - - case 'return': - wp_redirect($this->get_return_url( $order )); - break; - - case 'ipn': - exit( 'responsecode=1&desc=confirm-success'); - break; - - case 'querydr': - // Do nothing - break; - } - - } else { - if ( 'ipn' == $type ) - exit('responsecode=0&desc=confirm-success'); - - } - } /** * Get the response description based on the response code @@ -332,9 +300,9 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { * * @return string */ - public function OnePay_getResponseDescription($responseCode) { + public function OnePay_getResponseDescription( $responseCode ) { - switch ($responseCode) { + switch ( $responseCode ) { case "0" : $result = "Giao dịch thành công - Approved"; break; @@ -383,7 +351,54 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { default : $result = "Giao dịch thất bại - Failured"; } + return $result; } + /** + * Handle the IPN POST request from OnePay + */ + public function handle_onepay_ipn() { + + if ( isset( $_REQUEST['vpc_SecureHash'] ) ) { + + $this->process_onepay_response_data( $_REQUEST, 'ipn' ); + + } + } + + /** + * Handle the queryDR request + * + * @param string $vpc_MerchTxnRef + */ + public function handle_onepay_querydr( $vpc_MerchTxnRef ) { + // Build the queryDR link + $args = array( + 'vpc_Command' => 'queryDR', + 'vpc_Version' => '1', + 'vpc_MerchTxnRef' => $vpc_MerchTxnRef, + 'vpc_Merchant' => $this->merchant_id, + 'vpc_AccessCode' => $this->access_code, + 'vpc_User' => $this->user, + 'vpc_Password' => $this->password, + ); + + $http_args = http_build_query( $args, '', '&' ); + + if ( $this->testmode ) { + $http_link = 'https://mtf.onepay.vn/onecomm-pay/Vpcdps.op?' . $http_args; + } else { + $http_link = 'https://onepay.vn/onecomm-pay/Vpcdps.op?' . $http_args; + } + + // Connect to OnePay to get the queryDR info + $http_response = wp_remote_get( $http_link ); + parse_str( wp_remote_retrieve_body( $http_response ), $args_response ); + + // Process the data + $this->process_onepay_response_data( $args_response, 'querydr' ); + + } + } diff --git a/inc/onepay/domestic-settings.php b/inc/onepay/domestic-settings.php index 80b24ad..99dcc41 100644 --- a/inc/onepay/domestic-settings.php +++ b/inc/onepay/domestic-settings.php @@ -8,13 +8,13 @@ if ( ! defined( 'ABSPATH' ) ) { * Settings for 1Pay Gateway. */ return array( - 'enabled' => array( + 'enabled' => array( 'title' => __( 'Enable/Disable', 'woo-viet' ), 'type' => 'checkbox', 'label' => __( 'OnePay Domestic Gateway (by Woo Viet)', 'woo-viet' ), 'default' => 'no' ), - 'testmode' => array( + 'testmode' => array( 'title' => __( 'OnePay Sandbox', 'woocommerce' ), 'type' => 'checkbox', 'label' => __( 'Enable OnePay sandbox (testing)', 'woocommerce' ), @@ -22,26 +22,26 @@ return array( 'description' => sprintf( __( 'OnePay sandbox can be used to test payments. See the testing info.', 'woocommerce' ), 'https://mtf.onepay.vn/developer/?page=modul_noidia' ), //@todo: add the logo https://mtf.onepay.vn/developer/?page=logo ), - 'title' => array( + 'title' => array( 'title' => __( 'Title', 'woo-viet' ), 'type' => 'text', 'description' => __( 'This controls the title which the user sees during checkout.', 'woo-viet' ), 'default' => __( 'OnePay Domestic Gateway', 'woo-viet' ), 'desc_tip' => true, ), - 'description' => array( + 'description' => array( 'title' => __( 'Description', 'woo-viet' ), 'type' => 'textarea', 'desc_tip' => true, 'description' => __( 'This controls the description which the user sees during checkout.', 'woo-viet' ), 'default' => __( 'With OnePay, you can make payment by using any local Vietnam ATM card.', 'woo-viet' ) ), - 'api_details' => array( + 'api_details' => array( 'title' => __( 'API Credentials', 'woo-viet' ), 'type' => 'title', 'description' => sprintf( __( 'Enter your OnePay API credentials. Contact OnePay to have your credentials %shere%s.', 'woo-viet' ), '', '' ), ), - 'merchant_id' => array( + 'merchant_id' => array( 'title' => __( 'Merchant ID', 'woo-viet' ), 'type' => 'text', 'description' => __( 'Get your Merchant ID from OnePay.', 'woo-viet' ), @@ -49,7 +49,7 @@ return array( 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) ), - 'access_code' => array( + 'access_code' => array( 'title' => __( 'Access Code', 'woocommerce' ), 'type' => 'text', 'description' => __( 'Get your Access Code from from OnePay.', 'woo-viet' ), @@ -65,7 +65,7 @@ return array( 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) ), - 'user' => array( + 'user' => array( 'title' => __( 'User for queryDR. Test value: op01', 'woocommerce' ), 'type' => 'text', 'description' => __( 'Get your user info from from OnePay.', 'woo-viet' ), @@ -73,7 +73,7 @@ return array( 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay', 'woo-viet' ) ), - 'password' => array( + 'password' => array( 'title' => __( 'Password for queryDR. Test value: op123456', 'woocommerce' ), 'type' => 'text', 'description' => __( 'Get your password info from from OnePay.', 'woo-viet' ), @@ -81,11 +81,11 @@ return array( 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) ), - 'more_info' => array( + 'more_info' => array( 'title' => __( 'Instant Payment Notification (IPN)', 'woo-viet' ), 'type' => 'title', 'description' => - sprintf('URL: %s', WooViet_OnePay_Domestic::get_onepay_ipn_url() ) . '

' . + sprintf( 'URL: %s', WooViet_OnePay_Domestic::get_onepay_ipn_url() ) . '

' . sprintf( __( '%sContact OnePay%s to configure this URL on its site. This is required based on its guidelines.', 'woo-viet' ), '', '' ), ), From 44c0a34fe8b0ea2e3e67ceb07b93162c34387564 Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 11:47:46 +0700 Subject: [PATCH 12/16] Improve calling the cron job queryDR, avoid adding the note 2 times to the order Issue: OnePay Gateway - For the type return, the $order->add_order_note() run 2 times #19 --- woo-viet.php | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/woo-viet.php b/woo-viet.php index 7a79b50..17d4ad4 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -145,11 +145,13 @@ class WooViet { // Add the action to check the cron job for handling queryDR // It's not possible to add in the class "WooViet_OnePay_Domestic_Hook" because it's NOT always loadded - $this->WooViet_OnePay_Domestic_Hook = new WooViet_OnePay_Domestic(); - add_action( 'wooviet_handle_onepay_querydr', array( - $this->WooViet_OnePay_Domestic_Hook, - 'handle_onepay_querydr' - ), 10, 1 ); + if ( defined( 'DOING_CRON' ) and DOING_CRON ) { + $this->WooViet_OnePay_Domestic_Hook = new WooViet_OnePay_Domestic(); + add_action( 'wooviet_handle_onepay_querydr', array( + $this->WooViet_OnePay_Domestic_Hook, + 'handle_onepay_querydr' + ), 10, 1 ); + } } From 69c7dfae3c5cd5de2f826d0eb5e4f3077466ca08 Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 11:48:27 +0700 Subject: [PATCH 13/16] Clean some redundant codes --- inc/class-wooviet-onepay-domestic.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index 641a860..c48487a 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -49,8 +49,6 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { add_action( 'woocommerce_api_' . strtolower( __CLASS__ ), array( $this, 'handle_onepay_ipn' ) ); - // @todo: check whether or not this can be lodded in the cron job - add_action( 'wooviet_handle_onepay_querydr', array( $this, 'handle_onepay_querydr' ), 10, 1 ); } /** @@ -140,7 +138,7 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { wp_schedule_single_event( time() + 20 * 60, 'wooviet_handle_onepay_querydr', - array( $vpc_MerchTxnRef ) // @todo check this + array( $vpc_MerchTxnRef ) ); } From 6c7627549991ad304b0acea997674e5fff0aa78f Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 12:15:15 +0700 Subject: [PATCH 14/16] OnePay - Add the bank logos in the checkout page #20 --- assets/onepay_domestic.png | Bin 0 -> 21876 bytes inc/class-wooviet-onepay-domestic.php | 3 ++- woo-viet.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) create mode 100644 assets/onepay_domestic.png diff --git a/assets/onepay_domestic.png b/assets/onepay_domestic.png new file mode 100644 index 0000000000000000000000000000000000000000..92059e6a9251d1dc0b0be7b6599644b0496c91ac GIT binary patch literal 21876 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 z


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 literal 0 HcmV?d00001 diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index c48487a..b5e1afb 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -31,7 +31,8 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { // Define user set variables. $this->title = $this->get_option( 'title' ); - $this->description = $this->get_option( 'description' ); + $this->description = $this->get_option( 'description' ) . sprintf( '
', WOO_VIET_URL . 'assets/onepay_domestic.png' ); + $this->testmode = 'yes' === $this->get_option( 'testmode', 'no' ); $this->merchant_id = $this->get_option( 'merchant_id' ); $this->access_code = $this->get_option( 'access_code' ); diff --git a/woo-viet.php b/woo-viet.php index 17d4ad4..f2bede6 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -16,7 +16,7 @@ if ( ! defined( 'ABSPATH' ) ) { } define( 'WOO_VIET_DIR', plugin_dir_path( __FILE__ ) ); -// define( 'WOO_VIET_URL', plugins_url( '/', __FILE__ ) ); +define( 'WOO_VIET_URL', plugins_url( '/', __FILE__ ) ); /** * Start the instance From 8df0f118694549a34ab0cab0b7c96ea98dca1b08 Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 12:47:24 +0700 Subject: [PATCH 15/16] Open OnePay for VND only --- inc/class-wooviet-admin-page.php | 11 ++++++++++- woo-viet.php | 4 +++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/inc/class-wooviet-admin-page.php b/inc/class-wooviet-admin-page.php index c8bd503..b022f64 100644 --- a/inc/class-wooviet-admin-page.php +++ b/inc/class-wooviet-admin-page.php @@ -101,7 +101,16 @@ class WooViet_Admin_Page {
diff --git a/woo-viet.php b/woo-viet.php index f2bede6..319fe8d 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -138,7 +138,9 @@ class WooViet { $settings = self::get_settings(); // Check if "Add the OnePay Domestic Gateway" is enabled - if ( 'yes' == $settings['add_onepay_domestic']['enabled'] ) { + if ( 'yes' == $settings['add_onepay_domestic']['enabled'] + AND 'VND' == get_woocommerce_currency() + ) { include( 'inc/class-wooviet-onepay-domestic.php' ); add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateway_class' ) ); From 941438dda81004b18a3eaa34e39e4ae92a159959 Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 15:49:49 +0700 Subject: [PATCH 16/16] Correct the typos --- inc/onepay/domestic-settings.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/onepay/domestic-settings.php b/inc/onepay/domestic-settings.php index 99dcc41..9ac09bc 100644 --- a/inc/onepay/domestic-settings.php +++ b/inc/onepay/domestic-settings.php @@ -6,6 +6,7 @@ if ( ! defined( 'ABSPATH' ) ) { /** * Settings for 1Pay Gateway. + * @since 1.3 */ return array( 'enabled' => array( @@ -52,7 +53,7 @@ return array( 'access_code' => array( 'title' => __( 'Access Code', 'woocommerce' ), 'type' => 'text', - 'description' => __( 'Get your Access Code from from OnePay.', 'woo-viet' ), + 'description' => __( 'Get your Access Code from OnePay.', 'woo-viet' ), 'default' => '', 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) @@ -60,7 +61,7 @@ return array( 'secure_secret' => array( 'title' => __( 'Secure Secret', 'woocommerce' ), 'type' => 'text', - 'description' => __( 'Get your Secure Secret from from OnePay.', 'woo-viet' ), + 'description' => __( 'Get your Secure Secret from OnePay.', 'woo-viet' ), 'default' => '', 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' ) @@ -68,7 +69,7 @@ return array( 'user' => array( 'title' => __( 'User for queryDR. Test value: op01', 'woocommerce' ), 'type' => 'text', - 'description' => __( 'Get your user info from from OnePay.', 'woo-viet' ), + 'description' => __( 'Get your user info from OnePay.', 'woo-viet' ), 'default' => '', 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay', 'woo-viet' ) @@ -76,7 +77,7 @@ return array( 'password' => array( 'title' => __( 'Password for queryDR. Test value: op123456', 'woocommerce' ), 'type' => 'text', - 'description' => __( 'Get your password info from from OnePay.', 'woo-viet' ), + 'description' => __( 'Get your password info from OnePay.', 'woo-viet' ), 'default' => '', 'desc_tip' => true, 'placeholder' => __( 'Required. Provided by OnePay.', 'woo-viet' )
+ + > + +
+
+ +
diff --git a/woo-viet.php b/woo-viet.php index d1b85ee..4dcca12 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -60,7 +60,11 @@ class WooViet { 'currency' => 'USD', 'rate' => '22770', ), - ); + 'add_onepay_domestic' => + array( + 'enabled' => 'yes', + ), + ); /** * The properties to manage all classes under the "inc/" folder * Example: @@ -131,14 +135,6 @@ class WooViet { */ public function main() { - // @todo: ver 1.3 check this - add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateway_class' ) ); - - include( 'inc/class-wooviet-onepay-domestic.php'); - $WooViet_OnePay_Domestic_Hook = new WooViet_OnePay_Domestic(); - add_action('wooviet_handle_onepay_querydr', array($WooViet_OnePay_Domestic_Hook, 'handle_onepay_querydr'), 10, 1); - - if ( is_admin() ) { // Add the admin setting page include( WOO_VIET_DIR . 'inc/class-wooviet-admin-page.php' ); @@ -147,6 +143,16 @@ class WooViet { } $settings = self::get_settings(); + // Check if "Add the OnePay Domestic Gateway" is enabled + if ( 'yes' == $settings['add_onepay_domestic']['enabled'] ) { + // @todo: ver 1.3 check this + add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateway_class' ) ); + + include( 'inc/class-wooviet-onepay-domestic.php'); + $WooViet_OnePay_Domestic_Hook = new WooViet_OnePay_Domestic(); + add_action('wooviet_handle_onepay_querydr', array($WooViet_OnePay_Domestic_Hook, 'handle_onepay_querydr'), 10, 1); + + } // Check if "Add provinces for Vietnam " is enabled. if ( 'yes' == $settings['add_province']['enabled'] ) { From 0d07ecca4c29a9087f4895ed302e3779369e5a41 Mon Sep 17 00:00:00 2001 From: htdat Date: Thu, 20 Apr 2017 17:40:14 +0700 Subject: [PATCH 06/16] Change the dev version --- woo-viet.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/woo-viet.php b/woo-viet.php index 4dcca12..f5ef1a9 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -7,7 +7,7 @@ * Author URI: https://profiles.wordpress.org/htdat * Text Domain: woo-viet * Domain Path: /languages - * Version: 1.2 + * Version: 1.3-dev * License: GPLv2+ */ From 9fe23bd609f5b167f20f6b3820475c17e48bdbd6 Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 09:37:05 +0700 Subject: [PATCH 07/16] Make the process data better - require $type --- inc/class-wooviet-onepay-domestic.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index 4394147..036c963 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -203,7 +203,7 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { if (isset($_POST['vpc_SecureHash'])) { - $this->process_onepay_response_data( $_POST ); + $this->process_onepay_response_data( $_POST, 'ipn' ); } } @@ -237,7 +237,7 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { parse_str( wp_remote_retrieve_body( $http_response ), $args_response ); // Process the data - $this->process_onepay_response_data($args_response); + $this->process_onepay_response_data($args_response, 'querydr'); } @@ -246,7 +246,7 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { * @param string $args the response data from OnePay * @param string $type */ - public function process_onepay_response_data ($args, $type = '' ) { + public function process_onepay_response_data ($args, $type ) { $types_accepted = array( 'return', 'ipn', From 58022a6650d040daeebe1c3ec02f78b387747114 Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 09:48:29 +0700 Subject: [PATCH 08/16] Improve and reformat code for the main file --- woo-viet.php | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/woo-viet.php b/woo-viet.php index f5ef1a9..7a79b50 100644 --- a/woo-viet.php +++ b/woo-viet.php @@ -40,7 +40,7 @@ class WooViet { array( 'enabled' => 'yes', ), - 'add_city' => + 'add_city' => array( 'enabled' => 'yes', ), @@ -60,11 +60,11 @@ class WooViet { 'currency' => 'USD', 'rate' => '22770', ), - 'add_onepay_domestic' => + 'add_onepay_domestic' => array( 'enabled' => 'yes', ), - ); + ); /** * The properties to manage all classes under the "inc/" folder * Example: @@ -123,13 +123,6 @@ class WooViet { load_plugin_textdomain( 'woo-viet', false, basename( dirname( __FILE__ ) ) . '/languages/' ); } - - public function add_gateway_class( $methods ) { - $methods[] = 'WooViet_OnePay_Domestic'; - return $methods; - - } - /** * The main method to load the components */ @@ -143,14 +136,20 @@ class WooViet { } $settings = self::get_settings(); + // Check if "Add the OnePay Domestic Gateway" is enabled if ( 'yes' == $settings['add_onepay_domestic']['enabled'] ) { - // @todo: ver 1.3 check this + include( 'inc/class-wooviet-onepay-domestic.php' ); + add_filter( 'woocommerce_payment_gateways', array( $this, 'add_gateway_class' ) ); - include( 'inc/class-wooviet-onepay-domestic.php'); - $WooViet_OnePay_Domestic_Hook = new WooViet_OnePay_Domestic(); - add_action('wooviet_handle_onepay_querydr', array($WooViet_OnePay_Domestic_Hook, 'handle_onepay_querydr'), 10, 1); + // Add the action to check the cron job for handling queryDR + // It's not possible to add in the class "WooViet_OnePay_Domestic_Hook" because it's NOT always loadded + $this->WooViet_OnePay_Domestic_Hook = new WooViet_OnePay_Domestic(); + add_action( 'wooviet_handle_onepay_querydr', array( + $this->WooViet_OnePay_Domestic_Hook, + 'handle_onepay_querydr' + ), 10, 1 ); } @@ -198,7 +197,23 @@ class WooViet { static function get_settings() { $settings = get_option( 'woo-viet', self::$default_settings ); $settings = wp_parse_args( $settings, self::$default_settings ); + return $settings; } + /** + * Add the gateways to WooCommerce + * + * @param array $methods + * + * @since 1.3 + * @return array + */ + public function add_gateway_class( $methods ) { + $methods[] = 'WooViet_OnePay_Domestic'; + + return $methods; + + } + } \ No newline at end of file From 4f73556b278a1eddc0912e9febeda4b012be37dd Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 09:58:48 +0700 Subject: [PATCH 09/16] Correct the code for IPN Use exit() instead of wp_die() --- inc/class-wooviet-onepay-domestic.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/inc/class-wooviet-onepay-domestic.php b/inc/class-wooviet-onepay-domestic.php index 036c963..cd39918 100644 --- a/inc/class-wooviet-onepay-domestic.php +++ b/inc/class-wooviet-onepay-domestic.php @@ -201,9 +201,9 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { */ public function handle_onepay_ipn() { - if (isset($_POST['vpc_SecureHash'])) { + if (isset($_REQUEST['vpc_SecureHash'])) { - $this->process_onepay_response_data( $_POST, 'ipn' ); + $this->process_onepay_response_data( $_REQUEST, 'ipn' ); } } @@ -309,7 +309,7 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { break; case 'ipn': - wp_die('responsecode=1&desc=confirm-success'); + exit( 'responsecode=1&desc=confirm-success'); break; case 'querydr': @@ -319,7 +319,8 @@ class WooViet_OnePay_Domestic extends WC_Payment_Gateway { } else { if ( 'ipn' == $type ) - wp_die('responsecode=0&desc=confirm-success'); + exit('responsecode=0&desc=confirm-success'); + } } From dc226abb88a533e48db002543f5394321dc15179 Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 10:34:02 +0700 Subject: [PATCH 10/16] Change: 1.3 - OnePay Domestic Gateway should not be active by default #18 --- inc/onepay/domestic-settings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/inc/onepay/domestic-settings.php b/inc/onepay/domestic-settings.php index 522cb14..80b24ad 100644 --- a/inc/onepay/domestic-settings.php +++ b/inc/onepay/domestic-settings.php @@ -12,7 +12,7 @@ return array( 'title' => __( 'Enable/Disable', 'woo-viet' ), 'type' => 'checkbox', 'label' => __( 'OnePay Domestic Gateway (by Woo Viet)', 'woo-viet' ), - 'default' => 'yes' + 'default' => 'no' ), 'testmode' => array( 'title' => __( 'OnePay Sandbox', 'woocommerce' ), From a33745b8502c6091e063a62a5c045f14d9fc104b Mon Sep 17 00:00:00 2001 From: htdat Date: Sat, 22 Apr 2017 10:40:10 +0700 Subject: [PATCH 11/16] Reformat code by PHPStorm --- inc/class-wooviet-admin-page.php | 19 +- inc/class-wooviet-onepay-domestic.php | 449 +++++++++++++------------- inc/onepay/domestic-settings.php | 22 +- 3 files changed, 253 insertions(+), 237 deletions(-) diff --git a/inc/class-wooviet-admin-page.php b/inc/class-wooviet-admin-page.php index f81f2a6..c8bd503 100644 --- a/inc/class-wooviet-admin-page.php +++ b/inc/class-wooviet-admin-page.php @@ -92,16 +92,17 @@ class WooViet_Admin_Page { - > + >


+

> + >