From bbebc21a603094c9ef5dfc611a7617b626d1766d Mon Sep 17 00:00:00 2001 From: "allen.chang" Date: Thu, 7 Mar 2024 16:54:14 +0800 Subject: [PATCH] =?UTF-8?q?Woocommerce=20=E6=9C=AC=E6=AC=A1=E5=8D=87?= =?UTF-8?q?=E7=B4=9A=E8=88=87=E5=84=AA=E5=8C=96=20-=20=E7=9B=B8=E5=AE=B9?= =?UTF-8?q?=E7=89=88=E6=9C=AC=EF=BC=9APHP8.1=20/=20Woocommerce8.1.1=20/=20?= =?UTF-8?q?Wordpress=206.3.1=20-=20=E6=96=B0=E5=A2=9ETWQR=E5=8F=8ABNPL?= =?UTF-8?q?=E4=BB=98=E6=AC=BE=E6=96=B9=E5=BC=8F=20-=20=E5=84=AA=E5=8C=96?= =?UTF-8?q?=E9=87=91=E7=89=A9=E6=B5=81=E3=80=81=E7=99=BC=E7=A5=A8=E6=A8=A1?= =?UTF-8?q?=E7=B5=84=E5=90=84=E9=A0=85=E8=A8=AD=E5=AE=9A=20-=20=E8=AA=9E?= =?UTF-8?q?=E7=B3=BB=E6=AA=94=E8=AA=BF=E6=95=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../config/payment/settings-gateway-bnpl.php | 44 + .../config/payment/settings-gateway-dca.php | 53 + .../config/payment/settings-gateway-twqr.php | 45 + .../services/database/ecpay-db-process.php | 71 ++ .../helpers/invoice/ecpay-invoice-helper.php | 939 ++++++++++++++++++ .../services/helpers/logger/ecpay-logger.php | 90 ++ .../helpers/payment/ecpay-payment-helper.php | 491 +++++++++ .../services/payment/ecpay-gateway-bnpl.php | 78 ++ .../services/payment/ecpay-gateway-dca.php | 333 +++++++ .../services/payment/ecpay-gateway-twqr.php | 75 ++ .../public/js/wooecpay-dca.js | 102 ++ 11 files changed, 2321 insertions(+) create mode 100644 ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-bnpl.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-dca.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-twqr.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/services/database/ecpay-db-process.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/services/helpers/invoice/ecpay-invoice-helper.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/services/helpers/logger/ecpay-logger.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/services/helpers/payment/ecpay-payment-helper.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-bnpl.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-dca.php create mode 100644 ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-twqr.php create mode 100644 ecpay-ecommerce-for-woocommerce/public/js/wooecpay-dca.js diff --git a/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-bnpl.php b/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-bnpl.php new file mode 100644 index 0000000..afb4546 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-bnpl.php @@ -0,0 +1,44 @@ + [ + 'title' => __('Enable/Disable', 'woocommerce'), + 'label' => sprintf(__('Enable %s', 'ecpay-ecommerce-for-woocommerce'), $this->method_title), + 'type' => 'checkbox', + 'default' => 'no', + ], + 'title' => [ + 'title' => __('Title', 'woocommerce'), + 'type' => 'text', + 'default' => $this->method_title, + 'description' => __('This controls the title which the user sees during checkout.', 'woocommerce'), + 'desc_tip' => true, + ], + 'description' => [ + 'title' => __('Description', 'woocommerce'), + 'type' => 'text', + 'default' => $this->order_button_text, + 'desc_tip' => true, + 'description' => __('This controls the description which the user sees during checkout.', 'woocommerce'), + ], + 'min_amount' => [ + 'title' => __('A minimum order amount', 'ecpay-ecommerce-for-woocommerce'), + 'type' => 'number', + 'default' => 3000, + 'description' => __('The transaction amount must be at least NT$3,000.', 'ecpay-ecommerce-for-woocommerce'), + 'custom_attributes' => [ + 'min' => 3000, + 'step' => 1 + ] + ], + 'max_amount' => [ + 'title' => __('A maximum order amount', 'ecpay-ecommerce-for-woocommerce'), + 'type' => 'number', + 'default' => 0, + 'placeholder' => 0, + 'description' => __('0 to disable maximum amount limit.', 'ecpay-ecommerce-for-woocommerce'), + 'custom_attributes' => [ + 'min' => 0, + 'step' => 1 + ] + ] +]; diff --git a/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-dca.php b/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-dca.php new file mode 100644 index 0000000..0f52c8b --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-dca.php @@ -0,0 +1,53 @@ + [ + 'title' => __('Enable/Disable', 'woocommerce'), + /* translators: %s: Gateway method title */ + 'label' => sprintf(__('Enable %s', 'ecpay-ecommerce-for-woocommerce'), $this->method_title), + 'type' => 'checkbox', + 'default' => 'no', + ], + 'title' => [ + 'title' => __('Title', 'woocommerce'), + 'type' => 'text', + 'default' => $this->method_title, + 'description' => __('This controls the title which the user sees during checkout.', 'woocommerce'), + 'desc_tip' => true, + ], + 'description' => [ + 'title' => __('Description', 'woocommerce'), + 'type' => 'text', + 'default' => $this->order_button_text, + 'desc_tip' => true, + 'description' => __('This controls the description which the user sees during checkout.', 'woocommerce'), + ], + 'min_amount' => [ + 'title' => __('A minimum order amount', 'ecpay-ecommerce-for-woocommerce'), + 'type' => 'number', + 'default' => 0, + 'placeholder' => 0, + 'description' => __('0 to disable minimum amount limit.', 'ecpay-ecommerce-for-woocommerce'), + 'custom_attributes' => [ + 'min' => 0, + 'step' => 1 + ] + ], + 'max_amount' => [ + 'title' => __('A maximum order amount', 'ecpay-ecommerce-for-woocommerce'), + 'type' => 'number', + 'default' => 0, + 'placeholder' => 0, + 'description' => __('0 to disable maximum amount limit.', 'ecpay-ecommerce-for-woocommerce'), + 'custom_attributes' => [ + 'min' => 0, + 'step' => 1 + ] + ], + 'ecpay_dca' => [ + 'title' => __('DCA', 'ecpay-ecommerce-for-woocommerce'), + 'type' => 'ecpay_dca', + 'default' => '', + 'description' => '', + 'desc_tip' => true, + ], +]; diff --git a/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-twqr.php b/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-twqr.php new file mode 100644 index 0000000..75e13d7 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/config/payment/settings-gateway-twqr.php @@ -0,0 +1,45 @@ + [ + 'title' => __('Enable/Disable', 'woocommerce'), + 'label' => sprintf(__('Enable %s', 'ecpay-ecommerce-for-woocommerce'), $this->method_title), + 'type' => 'checkbox', + 'default' => 'no', + ], + 'title' => [ + 'title' => __('Title', 'woocommerce'), + 'type' => 'text', + 'default' => $this->method_title, + 'description' => __('This controls the title which the user sees during checkout.', 'woocommerce'), + 'desc_tip' => true, + ], + 'description' => [ + 'title' => __('Description', 'woocommerce'), + 'type' => 'text', + 'default' => $this->order_button_text, + 'desc_tip' => true, + 'description' => __('This controls the description which the user sees during checkout.', 'woocommerce'), + ], + 'min_amount' => [ + 'title' => __('A minimum order amount', 'ecpay-ecommerce-for-woocommerce'), + 'type' => 'number', + 'default' => 0, + 'placeholder' => 0, + 'description' => __('0 to disable minimum amount limit.', 'ecpay-ecommerce-for-woocommerce'), + 'custom_attributes' => [ + 'min' => 0, + 'step' => 1 + ] + ], + 'max_amount' => [ + 'title' => __('A maximum order amount', 'ecpay-ecommerce-for-woocommerce'), + 'type' => 'number', + 'default' => 0, + 'placeholder' => 0, + 'description' => __('0 to disable maximum amount limit.', 'ecpay-ecommerce-for-woocommerce'), + 'custom_attributes' => [ + 'min' => 0, + 'step' => 1 + ] + ] +]; diff --git a/ecpay-ecommerce-for-woocommerce/includes/services/database/ecpay-db-process.php b/ecpay-ecommerce-for-woocommerce/includes/services/database/ecpay-db-process.php new file mode 100644 index 0000000..d2e93a3 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/services/database/ecpay-db-process.php @@ -0,0 +1,71 @@ +prefix . 'ecpay_orders_payment_status'; + $sql = "CREATE TABLE $table_name ( + id bigint NOT NULL AUTO_INCREMENT, + order_id bigint NOT NULL, + payment_method varchar(60) NOT NULL, + merchant_trade_no varchar(60) NOT NULL DEFAULT '', + payment_status int(10) NOT NULL DEFAULT 0, + is_completed_duplicate int(1) NOT NULL DEFAULT 0, + updated_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + created_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (id) + )"; + + self::modify_db_table($table_name, $sql); + } + + /** + * 根據指定 SQL 異動資料庫 + * + * @param string $table_name + * @param string $sql + * @return void + */ + protected static function modify_db_table($table_name, $sql) { + global $wpdb; + + require_once(ABSPATH . '/wp-admin/includes/upgrade.php'); + + $isTableExists = $wpdb->get_var("SHOW TABLES LIKE '$table_name'") === $table_name; + $charset_collate = $isTableExists ? '' : $wpdb->get_charset_collate(); + + // 異動資料庫 + $dbDelta_result = dbDelta($sql . $charset_collate . ";"); + + // 更新綠界模組資料庫版本紀錄 + update_option('ecpay_db_version', self::$ecpay_db_version); + } +} \ No newline at end of file diff --git a/ecpay-ecommerce-for-woocommerce/includes/services/helpers/invoice/ecpay-invoice-helper.php b/ecpay-ecommerce-for-woocommerce/includes/services/helpers/invoice/ecpay-invoice-helper.php new file mode 100644 index 0000000..3614c4c --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/services/helpers/invoice/ecpay-invoice-helper.php @@ -0,0 +1,939 @@ + '個人', + self::INVOICE_TYPE_COMPANY => '公司', + self::INVOICE_TYPE_DONATE => '捐贈', + ]; + + /** + * 載具類別 + * + * @var array + */ + public $invoiceCarruerType = [ + self::INVOICE_CARRUER_TYPE_PAPER => '索取紙本', + self::INVOICE_CARRUER_TYPE_CLOUD => '雲端發票(中獎寄送紙本)', + self::INVOICE_CARRUER_TYPE_NATURAL_PERSON_ID => '自然人憑證', + self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE => '手機條碼', + ]; + + /** + * 取得綠界發票 API 介接資訊 + * + * @param string $action + * @return array $api_info + */ + public function get_ecpay_invoice_api_info($action = '') { + $api_info = [ + 'merchant_id' => '', + 'hashKey' => '', + 'hashIv' => '', + 'action' => '', + ]; + + // 介接資訊 + if ('yes' === get_option('wooecpay_enabled_invoice_stage', 'yes')) { + $api_info = [ + 'merchant_id' => '2000132', + 'hashKey' => 'ejCk326UnaZWKisg ', + 'hashIv' => 'q9jcZX8Ib9LM8wYk', + ]; + } else { + $merchant_id = get_option('wooecpay_invoice_mid'); + $hash_key = get_option('wooecpay_invoice_hashkey'); + $hash_iv = get_option('wooecpay_invoice_hashiv'); + + $api_info = [ + 'merchant_id' => $merchant_id, + 'hashKey' => $hash_key, + 'hashIv' => $hash_iv, + ]; + } + + // API URL + if ('yes' === get_option('wooecpay_enabled_invoice_stage', 'yes')) { + switch ($action) { + case 'check_Love_code': + $api_info['action'] = 'https://einvoice-stage.ecpay.com.tw/B2CInvoice/CheckLoveCode'; + break; + case 'check_barcode': + $api_info['action'] = 'https://einvoice-stage.ecpay.com.tw/B2CInvoice/CheckBarcode'; + break; + case 'issue': + $api_info['action'] = 'https://einvoice-stage.ecpay.com.tw/B2CInvoice/Issue'; + break; + case 'delay_issue': + $api_info['action'] = 'https://einvoice-stage.ecpay.com.tw/B2CInvoice/DelayIssue'; + break; + case 'invalid': + $api_info['action'] = 'https://einvoice-stage.ecpay.com.tw/B2CInvoice/Invalid'; + break; + case 'cancel_delay_issue': + $api_info['action'] = 'https://einvoice-stage.ecpay.com.tw/B2CInvoice/CancelDelayIssue'; + break; + default: + break; + } + } else { + switch ($action) { + case 'check_Love_code': + $api_info['action'] = 'https://einvoice.ecpay.com.tw/B2CInvoice/CheckLoveCode'; + break; + case 'check_barcode': + $api_info['action'] = 'https://einvoice.ecpay.com.tw/B2CInvoice/CheckBarcode'; + break; + case 'issue': + $api_info['action'] = 'https://einvoice.ecpay.com.tw/B2CInvoice/Issue'; + break; + case 'delay_issue': + $api_info['action'] = 'https://einvoice.ecpay.com.tw/B2CInvoice/DelayIssue'; + break; + case 'invalid': + $api_info['action'] = 'https://einvoice.ecpay.com.tw/B2CInvoice/Invalid'; + break; + case 'cancel_delay_issue': + $api_info['action'] = 'https://einvoice.ecpay.com.tw/B2CInvoice/CancelDelayIssue'; + break; + default: + break; + } + } + + return $api_info; + } + + /** + * 利用 od_sob 找出 order id + * + * @param array $info + * @return int|bool + */ + public function get_order_id($info) { + $order_prefix = get_option('wooecpay_invoice_prefix'); + + if (isset($info['od_sob'])) { + + $order_id = substr($info['od_sob'], strlen($order_prefix), strrpos($info['od_sob'], 'SN')); + + $order_id = (int) $order_id; + if ($order_id > 0) { + return $order_id; + } + } + + return false; + } + + /** + * 取得發票自訂編號 + * + * @param string $order_id + * @param string $order_prefix + * @return string + */ + public function get_relate_number($order_id, $order_prefix = '') { + $relate_no = $order_prefix . substr(str_pad($order_id, 8, '0', STR_PAD_LEFT), 0, 8) . 'SN' . substr(hash('sha256', (string) time()), -5); + return substr($relate_no, 0, 20); + } + + /** + * 結帳過程欄位檢查 + * + * @param array $fields + * @param array $switch + */ + public function check_invoice_fields($fields, $switch) { + // 發票開立方式 + if (isset($fields['wooecpay_invoice_type'])) { + $wooecpay_invoice_type = sanitize_text_field($fields['wooecpay_invoice_type']); + + switch ($wooecpay_invoice_type) { + case self::INVOICE_TYPE_COMPANY: + // 公司 + $wooecpay_invoice_customer_identifier = sanitize_text_field($fields['wooecpay_invoice_customer_identifier']); + $wooecpay_invoice_customer_company = sanitize_text_field($fields['wooecpay_invoice_customer_company']); + $wooecpay_invoice_carruer_type = sanitize_text_field($fields['wooecpay_invoice_carruer_type']); + + $response = $this->check_customer_identifier($wooecpay_invoice_customer_identifier, $wooecpay_invoice_carruer_type, $wooecpay_invoice_customer_company); + + if ($response['code'] !== '1') { + wc_add_notice($response['msg'], 'error'); + } + break; + case self::INVOICE_TYPE_DONATE: + // 捐贈 + $wooecpay_invoice_love_code = sanitize_text_field($fields['wooecpay_invoice_love_code']); + + $response = $this->check_love_code($wooecpay_invoice_love_code, $switch['billing_love_code_api_check']); + + if ($response['code'] !== '1') { + wc_add_notice($response['msg'], 'error'); + } + break; + } + } + + // 載具類別 + if (isset($fields['wooecpay_invoice_carruer_type'])) { + $wooecpay_invoice_carruer_type = sanitize_text_field($fields['wooecpay_invoice_carruer_type']); + $wooecpay_invoice_carruer_num = sanitize_text_field($fields['wooecpay_invoice_carruer_num']); + + switch ($wooecpay_invoice_carruer_type) { + case self::INVOICE_CARRUER_TYPE_NATURAL_PERSON_ID: + // 自然人憑證驗證 + $response = $this->check_citizen_digital_certificate($wooecpay_invoice_carruer_num); + if ($response['code'] !== '1') { + wc_add_notice($response['msg'], 'error'); + } + break; + case self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE: + // 手機載具驗證 + $response = $this->check_phone_barcode($wooecpay_invoice_carruer_num, $switch['billing_carruer_num_api_check']); + if ($response['code'] !== '1') { + wc_add_notice($response['msg'], 'error'); + } + break; + } + } + } + + /** + * 統一編號驗證 + * + * @param string $customer_identifier + * @param string $carruer_type + * @param string $customer_company + * @return array $result + */ + public function check_customer_identifier($customer_identifier, $carruer_type, $customer_company) { + // 預設驗證結果 + $result = [ + 'code' => '1', + 'msg' => '', + ]; + + if ($customer_identifier == '') { + $result['code'] = '1010'; + $result['msg'] = __('Please input Unified Business NO', 'ecpay-ecommerce-for-woocommerce'); + } else { + if (!preg_match('/^[0-9]{8}$/', $customer_identifier)) { + $result['code'] = '1011'; + $result['msg'] = __('Invalid tax ID number', 'ecpay-ecommerce-for-woocommerce'); + } + + if ($carruer_type == '0' && empty($customer_company)) { + $result['code'] = '1012'; + $result['msg'] = __('Please input the company name', 'ecpay-ecommerce-for-woocommerce'); + } + } + + return $result; + } + + /** + * 捐贈碼驗證 + * + * @param string $love_code + * @param bool $switch + * @return array $result + */ + public function check_love_code($love_code, $switch) { + // 預設驗證結果 + $result = [ + 'code' => '1', + 'msg' => '', + ]; + + if ($love_code == '') { + $result['code'] = '1020'; + $result['msg'] = __('Please input Donate number', 'ecpay-ecommerce-for-woocommerce'); + } else { + if (!preg_match('/^([xX]{1}[0-9]{2,6}|[0-9]{3,7})$/', $love_code)) { + $result['code'] = '1021'; + $result['msg'] = __('Invalid Donate number', 'ecpay-ecommerce-for-woocommerce'); + } else { + // 呼叫 SDK 捐贈碼驗證 + if ($switch) { + $api_payment_info = $this->get_ecpay_invoice_api_info('check_Love_code'); + + try { + $factory = new Factory([ + 'hashKey' => $api_payment_info['hashKey'], + 'hashIv' => $api_payment_info['hashIv'], + ]); + + $postService = $factory->create('PostWithAesJsonResponseService'); + + $data = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'LoveCode' => $love_code, + ]; + $input = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RqHeader' => [ + 'Timestamp' => time(), + 'Revision' => '3.0.0', + ], + 'Data' => $data, + ]; + + $response = $postService->post($input, $api_payment_info['action']); + + // 呼叫財政部API失敗 + if (isset($response['Data']['RtnCode']) && $response['Data']['RtnCode'] == 9000001) { + $result['code'] = '1022'; + $result['msg'] = __('Ministry of Finance system is currently under maintenance, unable to verify the carrier. Please choose another invoice mode.', 'ecpay-ecommerce-for-woocommerce'); + } + + // SDK 捐贈碼驗證失敗 + if (!isset($response['Data']['RtnCode']) || $response['Data']['RtnCode'] != 1 || $response['Data']['IsExist'] == 'N') { + $result['code'] = '1023'; + $result['msg'] = __('Please Check Donate number', 'ecpay-ecommerce-for-woocommerce'); + } + } catch (RtnException $e) { + $result['code'] = '1029'; + $result['msg'] = wp_kses_post('(' . $e->getCode() . ')' . $e->getMessage()) . PHP_EOL; + return $result; + } + } + } + } + + return $result; + } + + /** + * 自然人憑證驗證 + * + * @param string $carruer_num + * @return array $result + */ + public function check_citizen_digital_certificate($carruer_num) { + // 預設驗證結果 + $result = [ + 'code' => '1', + 'msg' => '', + ]; + + if ($carruer_num == '') { + $result['code'] = '1030'; + $result['msg'] = __('Please input Citizen Digital Certificate', 'ecpay-ecommerce-for-woocommerce'); + } else { + if (!preg_match('/^[a-zA-Z]{2}\d{14}$/', $carruer_num)) { + $result['code'] = '1031'; + $result['msg'] = __('Invalid Citizen Digital Certificate', 'ecpay-ecommerce-for-woocommerce'); + } + } + + return $result; + } + + /** + * 手機條碼驗證 + * + * @param string $carruer_num + * @param bool $switch + * @return array $result + */ + public function check_phone_barcode($carruer_num, $switch) { + // 預設驗證結果 + $result = [ + 'code' => '1', + 'msg' => '', + ]; + + if ($carruer_num == '') { + $result['code'] = '1040'; + $result['msg'] = __('Please input phone barcode', 'ecpay-ecommerce-for-woocommerce'); + } else { + if (!preg_match('/^\/{1}[0-9a-zA-Z+-.]{7}$/', $carruer_num)) { + $result['code'] = '1041'; + $result['msg'] = __('Invalid phone barcode', 'ecpay-ecommerce-for-woocommerce'); + } else { + // 呼叫 SDK 手機條碼驗證 + if ($switch) { + $api_payment_info = $this->get_ecpay_invoice_api_info('check_barcode'); + + try { + $factory = new Factory([ + 'hashKey' => $api_payment_info['hashKey'], + 'hashIv' => $api_payment_info['hashIv'], + ]); + + $postService = $factory->create('PostWithAesJsonResponseService'); + + $data = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'BarCode' => $carruer_num, + ]; + + $input = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RqHeader' => [ + 'Timestamp' => time(), + 'Revision' => '3.0.0', + ], + 'Data' => $data, + ]; + + $response = $postService->post($input, $api_payment_info['action']); + + // 呼叫財政部API失敗 + if (isset($response['Data']['RtnCode']) && $response['Data']['RtnCode'] == 9000001) { + $result['code'] = '1042'; + $result['msg'] = __('Ministry of Finance system is currently under maintenance, unable to verify the carrier. Please choose another invoice mode.', 'ecpay-ecommerce-for-woocommerce'); + } + + // SDK 手機條碼驗證失敗 + if (!isset($response['Data']['RtnCode']) || $response['Data']['RtnCode'] != 1 || $response['Data']['IsExist'] == 'N') { + $result['code'] = '1043'; + $result['msg'] = __('Please Check phone barcode', 'ecpay-ecommerce-for-woocommerce'); + } + } catch (RtnException $e) { + $result['code'] = '1049'; + $result['msg'] = wp_kses_post('(' . $e->getCode() . ')' . $e->getMessage()) . PHP_EOL; + return $result; + } + } + } + } + + return $result; + } + + /** + * 開立發票程序 + * + * @param WC_Order $order + * @return void + */ + public function invoice_create($order) { + + // 判斷發票是否存在,不存在則開立 + $wooecpay_invoice_process = $order->get_meta('_wooecpay_invoice_process', true); + + if (empty($wooecpay_invoice_process)) { + $wooecpay_invoice_dalay_date = get_option('wooecpay_invoice_dalay_date'); + $wooecpay_invoice_dalay_date = (int) $wooecpay_invoice_dalay_date; + + // 取得付款方式,判斷是否紀錄發票備註 + $payment_method = $order->get_meta('_payment_method', true); + + if (empty($wooecpay_invoice_dalay_date)) { + // 立即開立 + $api_payment_info = $this->get_ecpay_invoice_api_info('issue'); + $relateNumber = $this->get_relate_number($order->get_id(), get_option('wooecpay_invoice_prefix')); + + try { + $factory = new Factory([ + 'hashKey' => $api_payment_info['hashKey'], + 'hashIv' => $api_payment_info['hashIv'], + ]); + + $postService = $factory->create('PostWithAesJsonResponseService'); + + $items = []; + foreach ($order->get_items() as $item) { + + $item_price = round(($item->get_total() + $item->get_total_tax()) / $item->get_quantity(), 4); + $item_amount = round($item_price * $item->get_quantity(), 2); + $items[] = [ + 'ItemName' => mb_substr($item->get_name(), 0, 100), + 'ItemCount' => $item->get_quantity(), + 'ItemWord' => '批', + 'ItemPrice' => $item_price, + 'ItemTaxType' => '1', + 'ItemAmount' => $item_amount, + ]; + } + + // 物流費用 + $shipping_fee = $order->get_shipping_total() + $order->get_shipping_tax(); + if ($shipping_fee != 0) { + + $items[] = [ + 'ItemName' => __('Shipping fee', 'ecpay-ecommerce-for-woocommerce'), + 'ItemCount' => 1, + 'ItemWord' => '批', + 'ItemPrice' => $shipping_fee, + 'ItemTaxType' => '1', + 'ItemAmount' => $shipping_fee, + ]; + } + + $country = $order->get_billing_country(); + $countries = WC()->countries->get_countries(); + $full_country = ($country && isset($countries[$country])) ? $countries[$country] : $country; + + $state = $order->get_billing_state(); + $states = WC()->countries->get_states($country); + $full_state = ($state && isset($states[$state])) ? $states[$state] : $state; + + $data = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RelateNumber' => $relateNumber, + 'CustomerID' => '', + 'CustomerName' => $order->get_billing_last_name() . $order->get_billing_first_name(), + 'CustomerAddr' => $full_country . $full_state . $order->get_billing_city() . $order->get_billing_address_1() . $order->get_billing_address_2(), + 'CustomerPhone' => $order->get_billing_phone(), + 'CustomerEmail' => $order->get_billing_email(), + 'Print' => '0', + 'Donation' => '0', + 'LoveCode' => '', + 'CarrierType' => '', + 'CarrierNum' => '', + 'TaxType' => '1', + 'SalesAmount' => intval(round($order->get_total(), 0)), + 'Items' => $items, + 'InvType' => '07', + ]; + + // 記錄發票備註,卡號末四碼 + if (in_array($payment_method, array('Wooecpay_Gateway_Credit_Installment', 'Wooecpay_Gateway_Credit', 'Wooecpay_Gateway_Dca'))) { + $data['InvoiceRemark'] = '信用卡末四碼' . $order->get_meta('_ecpay_card4no', true); + } + + $wooecpay_invoice_type = $order->get_meta('_wooecpay_invoice_type', true); + $wooecpay_invoice_carruer_type = $order->get_meta('_wooecpay_invoice_carruer_type', true); + + switch ($wooecpay_invoice_type) { + case self::INVOICE_TYPE_PERSONAL: + switch ($wooecpay_invoice_carruer_type) { + case self::INVOICE_CARRUER_TYPE_CLOUD: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_CLOUD; + break; + case self::INVOICE_CARRUER_TYPE_NATURAL_PERSON_ID: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_NATURAL_PERSON_ID; + $data['CarrierNum'] = $order->get_meta('_wooecpay_invoice_carruer_num', true); + break; + case self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE; + $data['CarrierNum'] = $order->get_meta('_wooecpay_invoice_carruer_num', true); + break; + default: + $data['Print'] = '1'; + break; + } + break; + case self::INVOICE_TYPE_COMPANY: + $data['Print'] = '1'; + $data['CustomerIdentifier'] = $order->get_meta('_wooecpay_invoice_customer_identifier', true); + $company = $order->get_meta('_wooecpay_invoice_customer_company', true); + if ($company) { + $data['CustomerName'] = $company; + } + switch ($wooecpay_invoice_carruer_type) { + case self::INVOICE_CARRUER_TYPE_CLOUD: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_CLOUD; + break; + case self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE; + $data['CarrierNum'] = $order->get_meta('_wooecpay_invoice_carruer_num', true); + break; + } + break; + case self::INVOICE_TYPE_DONATE: + $data['Donation'] = '1'; + $data['LoveCode'] = $order->get_meta('_wooecpay_invoice_love_code', true); + break; + } + + $input = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RqHeader' => [ + 'Timestamp' => time(), + 'Revision' => '3.0.0', + ], + 'Data' => $data, + ]; + + ecpay_log('送出立即開立發票請求 ' . print_r(ecpay_log_replace_symbol('invoice', $input), true), 'C00005', $order->get_id()); + + $response = $postService->post($input, $api_payment_info['action']); + + ecpay_log('立即開立發票結果回傳 ' . print_r(ecpay_log_replace_symbol('invoice', $response), true), 'C00020', $order->get_id()); + + if ($response['TransCode'] == 1) { + if ($response['Data']['RtnCode'] == 1) { + // 更新訂單 + $order->update_meta_data('_wooecpay_invoice_relate_number', $relateNumber); + $order->update_meta_data('_wooecpay_invoice_RtnCode', $response['Data']['RtnCode']); + $order->update_meta_data('_wooecpay_invoice_RtnMsg', $response['Data']['RtnMsg']); + $order->update_meta_data('_wooecpay_invoice_no', $response['Data']['InvoiceNo']); + $order->update_meta_data('_wooecpay_invoice_date', $response['Data']['InvoiceDate']); + $order->update_meta_data('_wooecpay_invoice_random_number', $response['Data']['RandomNumber']); + + $order->update_meta_data('_wooecpay_invoice_process', 1); // 執行開立完成 + $order->update_meta_data('_wooecpay_invoice_issue_type', 1); // 開立類型 1.立即開立 2.延遲開立 + + $order->add_order_note('發票開立成功:狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + $order->save(); + + ecpay_log('立即開立發票成功', 'C00006', $order->get_id()); + } else { + $order->add_order_note('發票開立失敗:狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + $order->save(); + + ecpay_log('立即開立發票失敗', 'C00007', $order->get_id()); + } + } else { + $order->add_order_note('發票開立失敗:狀態:' . $response['TransMsg'] . '(' . $response['TransCode'] . ')'); + $order->save(); + + ecpay_log('立即開立發票失敗', 'C00008', $order->get_id()); + } + } catch (RtnException $e) { + ecpay_log('[Exception] (' . $e->getCode() . ')' . $e->getMessage(), 'C90005', $order->get_id()); + echo wp_kses_post('(' . $e->getCode() . ')' . $e->getMessage()) . PHP_EOL; + } + } else { + // 延遲開立 + $api_payment_info = $this->get_ecpay_invoice_api_info('delay_issue'); + $relateNumber = $this->get_relate_number($order->get_id(), get_option('wooecpay_invoice_prefix')); + + try { + $factory = new Factory([ + 'hashKey' => $api_payment_info['hashKey'], + 'hashIv' => $api_payment_info['hashIv'], + ]); + + $postService = $factory->create('PostWithAesJsonResponseService'); + + $items = []; + + foreach ($order->get_items() as $item) { + + $items[] = [ + 'ItemName' => mb_substr($item->get_name(), 0, 100), + 'ItemCount' => $item->get_quantity(), + 'ItemWord' => '批', + 'ItemPrice' => round($item->get_total() / $item->get_quantity(), 4), + 'ItemTaxType' => '1', + 'ItemAmount' => round($item->get_total(), 2), + ]; + } + + // 物流費用 + $shipping_fee = $order->get_shipping_total(); + if ($shipping_fee != 0) { + $items[] = [ + 'ItemName' => __('Shipping fee', 'ecpay-ecommerce-for-woocommerce'), + 'ItemCount' => 1, + 'ItemWord' => '批', + 'ItemPrice' => $shipping_fee, + 'ItemTaxType' => '1', + 'ItemAmount' => $shipping_fee, + ]; + } + + $country = $order->get_billing_country(); + $countries = WC()->countries->get_countries(); + $full_country = ($country && isset($countries[$country])) ? $countries[$country] : $country; + + $state = $order->get_billing_state(); + $states = WC()->countries->get_states($country); + $full_state = ($state && isset($states[$state])) ? $states[$state] : $state; + + $data = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RelateNumber' => $relateNumber, + 'CustomerID' => '', + 'CustomerName' => $order->get_billing_last_name() . $order->get_billing_first_name(), + 'CustomerAddr' => $full_country . $full_state . $order->get_billing_city() . $order->get_billing_address_1() . $order->get_billing_address_2(), + 'CustomerPhone' => $order->get_billing_phone(), + 'CustomerEmail' => $order->get_billing_email(), + 'Print' => '0', + 'Donation' => '0', + 'LoveCode' => '', + 'CarrierType' => '', + 'CarrierNum' => '', + 'TaxType' => '1', + 'SalesAmount' => intval(round($order->get_total(), 0)), + 'Items' => $items, + 'InvType' => '07', + + 'DelayFlag' => '1', + 'DelayDay' => $wooecpay_invoice_dalay_date, + 'Tsr' => $relateNumber, + 'PayType' => '2', + 'PayAct' => 'ECPAY', + 'NotifyURL' => WC()->api_request_url('wooecpay_invoice_delay_issue_callback', true), + ]; + + // 記錄發票備註,卡號末四碼 + if (in_array($payment_method, array('Wooecpay_Gateway_Credit_Installment', 'Wooecpay_Gateway_Credit', 'Wooecpay_Gateway_Dca'))) { + $data['InvoiceRemark'] = '信用卡末四碼' . $order->get_meta('_ecpay_card4no', true); + } + + $wooecpay_invoice_type = $order->get_meta('_wooecpay_invoice_type', true); + $wooecpay_invoice_carruer_type = $order->get_meta('_wooecpay_invoice_carruer_type', true); + + switch ($wooecpay_invoice_type) { + case self::INVOICE_TYPE_PERSONAL: + switch ($wooecpay_invoice_carruer_type) { + case self::INVOICE_CARRUER_TYPE_CLOUD: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_CLOUD; + break; + case self::INVOICE_CARRUER_TYPE_NATURAL_PERSON_ID: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_NATURAL_PERSON_ID; + $data['CarrierNum'] = $order->get_meta('_wooecpay_invoice_carruer_num', true); + break; + case self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE: + $data['CarrierType'] = self::INVOICE_CARRUER_TYPE_MOBILE_BARCODE; + $data['CarrierNum'] = $order->get_meta('_wooecpay_invoice_carruer_num', true); + break; + default: + $data['Print'] = '1'; + break; + } + break; + case self::INVOICE_TYPE_COMPANY: + $data['Print'] = '1'; + $data['CustomerIdentifier'] = $order->get_meta('_wooecpay_invoice_customer_identifier', true); + $company = $order->get_meta('_wooecpay_invoice_customer_company', true); + if ($company) { + $data['CustomerName'] = $company; + } + break; + case self::INVOICE_TYPE_DONATE: + $data['Donation'] = '1'; + $data['LoveCode'] = $order->get_meta('_wooecpay_invoice_love_code', true); + break; + } + + $input = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RqHeader' => [ + 'Timestamp' => time(), + 'Revision' => '3.0.0', + ], + 'Data' => $data, + ]; + + ecpay_log('送出延遲開立發票請求 ' . print_r(ecpay_log_replace_symbol('invoice', $input), true), 'C00009', $order->get_id()); + + $response = $postService->post($input, $api_payment_info['action']); + + ecpay_log('延遲開立發票結果回傳 ' . print_r($response, true), 'C00021', $order->get_id()); + + if ($response['TransCode'] == 1) { + if ($response['Data']['RtnCode'] == 1) { + // 更新訂單 + $order->update_meta_data('_wooecpay_invoice_relate_number', $relateNumber); + $order->update_meta_data('_wooecpay_invoice_RtnCode', $response['Data']['RtnCode']); + $order->update_meta_data('_wooecpay_invoice_RtnMsg', $response['Data']['RtnMsg']); + + $order->update_meta_data('_wooecpay_invoice_process', 1); // 執行開立完成 + $order->update_meta_data('_wooecpay_invoice_issue_type', 2); // 開立類型 1.立即開立 2.延遲開立 + $order->update_meta_data('_wooecpay_invoice_tsr', $relateNumber); // 交易單號 + + $order->add_order_note('發票開立成功:狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + $order->save(); + + ecpay_log('延遲開立發票成功', 'C00010', $order->get_id()); + } else { + $order->add_order_note('發票開立失敗:狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + $order->save(); + + ecpay_log('延遲開立發票失敗', 'C00011', $order->get_id()); + } + } else { + $order->add_order_note('發票開立失敗:狀態:' . $response['TransMsg'] . '(' . $response['TransCode'] . ')'); + $order->save(); + + ecpay_log('延遲開立發票失敗', 'C00012', $order->get_id()); + } + } catch (RtnException $e) { + ecpay_log('[Exception] (' . $e->getCode() . ')' . $e->getMessage(), 'C90009', $order->get_id()); + echo wp_kses_post('(' . $e->getCode() . ')' . $e->getMessage()) . PHP_EOL; + } + } + } + } + + /** + * 作廢發票程序 + * + * @param WC_Order $order + * @return void + */ + public function invoice_invalid($order) { + // 判斷發票是否存在,存在則才可以執行作廢 + $wooecpay_invoice_process = $order->get_meta('_wooecpay_invoice_process', true); + + if ($wooecpay_invoice_process == 1) { + // 取得開立類型(1.立即開立 2.延遲開立) + $wooecpay_invoice_issue_type = $order->get_meta('_wooecpay_invoice_issue_type', true); + + if ($wooecpay_invoice_issue_type == 1) { + $api_payment_info = $this->get_ecpay_invoice_api_info('invalid'); + + $wooecpay_invoice_no = $order->get_meta('_wooecpay_invoice_no', true); + $wooecpay_invoice_date = $order->get_meta('_wooecpay_invoice_date', true); + + // 作廢發票 + try { + $factory = new Factory([ + 'hashKey' => $api_payment_info['hashKey'], + 'hashIv' => $api_payment_info['hashIv'], + ]); + + $postService = $factory->create('PostWithAesJsonResponseService'); + + $data = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'InvoiceNo' => $wooecpay_invoice_no, + 'InvoiceDate' => $wooecpay_invoice_date, + 'Reason' => __('Invalid invoice', 'ecpay-ecommerce-for-woocommerce'), + ]; + + $input = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RqHeader' => [ + 'Timestamp' => time(), + 'Revision' => '3.0.0', + ], + 'Data' => $data, + ]; + + ecpay_log('送出立即開立發票作廢請求 ' . print_r(ecpay_log_replace_symbol('invoice', $input), true), 'C00013', $order->get_id()); + + $response = $postService->post($input, $api_payment_info['action']); + + ecpay_log('立即開立發票作廢結果回傳 ' . print_r(ecpay_log_replace_symbol('invoice', $response), true), 'C00022', $order->get_id()); + + if ($response['Data']['RtnCode'] == 1 || $response['Data']['RtnCode'] == 5070453) { + // 更新訂單 + $order->update_meta_data('_wooecpay_invoice_relate_number', ''); + $order->update_meta_data('_wooecpay_invoice_RtnCode', ''); + $order->update_meta_data('_wooecpay_invoice_RtnMsg', ''); + $order->update_meta_data('_wooecpay_invoice_no', ''); + $order->update_meta_data('_wooecpay_invoice_date', ''); + $order->update_meta_data('_wooecpay_invoice_random_number', ''); + + $order->update_meta_data('_wooecpay_invoice_process', 0); // 執行開立完成 + $order->update_meta_data('_wooecpay_invoice_issue_type', ''); // 開立類型 1.立即開立 2.延遲開立 + + $order->add_order_note('發票作廢成功: 發票號碼:' . $wooecpay_invoice_no . ' 狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + $order->save(); + + ecpay_log('立即開立發票作廢成功', 'C00014', $order->get_id()); + } else { + $order->add_order_note('發票作廢失敗:狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + $order->save(); + + ecpay_log('立即開立發票作廢失敗', 'C00015', $order->get_id()); + } + } catch (RtnException $e) { + ecpay_log('[Exception] (' . $e->getCode() . ')' . $e->getMessage(), 'C90013', $order->get_id()); + echo wp_kses_post('(' . $e->getCode() . ')' . $e->getMessage()) . PHP_EOL; + } + } else if ($wooecpay_invoice_issue_type == 2) { + $api_payment_info = $this->get_ecpay_invoice_api_info('cancel_delay_issue'); + $wooecpay_invoice_tsr = $order->get_meta('_wooecpay_invoice_tsr', true); + + try { + $factory = new Factory([ + 'hashKey' => $api_payment_info['hashKey'], + 'hashIv' => $api_payment_info['hashIv'], + ]); + + $postService = $factory->create('PostWithAesJsonResponseService'); + $data = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'Tsr' => $wooecpay_invoice_tsr, + ]; + + $input = [ + 'MerchantID' => $api_payment_info['merchant_id'], + 'RqHeader' => [ + 'Timestamp' => time(), + 'Revision' => '3.0.0', + ], + 'Data' => $data, + ]; + + ecpay_log('送出延遲開立發票作廢請求 ' . print_r(ecpay_log_replace_symbol('invoice', $input), true), 'C00016', $order->get_id()); + + $response = $postService->post($input, $api_payment_info['action']); + + ecpay_log('延遲開立發票作廢結果回傳 ' . print_r(ecpay_log_replace_symbol('invoice', $input), true), 'C00023', $order->get_id()); + + if ($response['Data']['RtnCode'] == 1) { + // 更新訂單 + $order->update_meta_data('_wooecpay_invoice_relate_number', ''); + $order->update_meta_data('_wooecpay_invoice_RtnCode', ''); + $order->update_meta_data('_wooecpay_invoice_RtnMsg', ''); + $order->update_meta_data('_wooecpay_invoice_no', ''); + $order->update_meta_data('_wooecpay_invoice_date', ''); + $order->update_meta_data('_wooecpay_invoice_random_number', ''); + $order->update_meta_data('_wooecpay_invoice_tsr', ''); // 交易單號 + + $order->update_meta_data('_wooecpay_invoice_process', 0); // 執行開立完成 + $order->update_meta_data('_wooecpay_invoice_issue_type', ''); // 開立類型 1.立即開立 2.延遲開立 + + $order->add_order_note('發票作廢成功: 交易單號:' . $wooecpay_invoice_tsr . ' 狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + + $order->save(); + + ecpay_log('延遲開立發票作廢成功', 'C00017', $order->get_id()); + } else { + $order->add_order_note('發票作廢失敗:狀態:' . $response['Data']['RtnMsg'] . '(' . $response['Data']['RtnCode'] . ')'); + $order->save(); + + ecpay_log('延遲開立發票作廢失敗', 'C00018', $order->get_id()); + } + } catch (RtnException $e) { + ecpay_log('[Exception] (' . $e->getCode() . ')' . $e->getMessage(), 'C90016', $order->get_id()); + echo wp_kses_post('(' . $e->getCode() . ')' . $e->getMessage()) . PHP_EOL; + } + } + } + } +} diff --git a/ecpay-ecommerce-for-woocommerce/includes/services/helpers/logger/ecpay-logger.php b/ecpay-ecommerce-for-woocommerce/includes/services/helpers/logger/ecpay-logger.php new file mode 100644 index 0000000..1cbfac1 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/services/helpers/logger/ecpay-logger.php @@ -0,0 +1,90 @@ +getMessage(), true)); + } + } + + /** + * 清理 Log + * + * @return bool + */ + public function clear_log(){ + if (WP_Filesystem()) { + global $wp_filesystem; + + if ($wp_filesystem->is_dir(WOOECPAY_PLUGIN_LOG_DIR)) { + // Delete the folder and its contents + $wp_filesystem->rmdir(WOOECPAY_PLUGIN_LOG_DIR, true); + + return true; + } + + return false; + } + } + + /** + * Log 內容隱碼處理 + * + * @param string $type + * @param string|array $data + * @return string|array $data + */ + public function replace_symbol($type, $data) { + switch ($type) { + case 'logistic': + if (isset($data['SenderName'])) $data['SenderName'] = '*'; + if (isset($data['SenderCellPhone'])) $data['SenderCellPhone'] = '*'; + if (isset($data['ReceiverName'])) $data['ReceiverName'] = '*'; + if (isset($data['ReceiverCellPhone'])) $data['ReceiverCellPhone'] = '*'; + break; + case 'invoice': + if (isset($data['Data']['CustomerName'])) $data['Data']['CustomerName'] = '*'; + if (isset($data['Data']['CustomerAddr'])) $data['Data']['CustomerAddr'] = '*'; + if (isset($data['Data']['CustomerPhone'])) $data['Data']['CustomerPhone'] = '*'; + if (isset($data['Data']['CustomerEmail'])) $data['Data']['CustomerEmail'] = '*'; + break; + } + + return $data; + } +} \ No newline at end of file diff --git a/ecpay-ecommerce-for-woocommerce/includes/services/helpers/payment/ecpay-payment-helper.php b/ecpay-ecommerce-for-woocommerce/includes/services/helpers/payment/ecpay-payment-helper.php new file mode 100644 index 0000000..1c9e209 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/services/helpers/payment/ecpay-payment-helper.php @@ -0,0 +1,491 @@ + 0) { + return $order_id; + } + } + + return false; + } + + public function get_ecpay_payment_api_info($action = '') + { + $api_payment_info = [ + 'merchant_id' => '', + 'hashKey' => '', + 'hashIv' => '', + 'action' => '', + ]; + + if ('yes' === get_option('wooecpay_enabled_payment_stage', 'yes')) { + + $api_payment_info = [ + 'merchant_id' => '3002607', + 'hashKey' => 'pwFHCqoQZGmho4w6', + 'hashIv' => 'EkRm7iFT261dpevs', + ]; + + } else { + + $merchant_id = get_option('wooecpay_payment_mid'); + $hash_key = get_option('wooecpay_payment_hashkey'); + $hash_iv = get_option('wooecpay_payment_hashiv'); + + $api_payment_info = [ + 'merchant_id' => $merchant_id, + 'hashKey' => $hash_key, + 'hashIv' => $hash_iv, + ]; + } + + // URL位置判斷 + if ('yes' === get_option('wooecpay_enabled_payment_stage', 'yes')) { + + switch ($action) { + + case 'QueryTradeInfo': + $api_payment_info['action'] = 'https://payment-stage.ecpay.com.tw/Cashier/QueryTradeInfo/V5'; + break; + + case 'AioCheckOut': + $api_payment_info['action'] = 'https://payment-stage.ecpay.com.tw/Cashier/AioCheckOut/V5'; + break; + + default: + break; + } + + } else { + + switch ($action) { + + case 'QueryTradeInfo': + $api_payment_info['action'] = 'https://payment.ecpay.com.tw/Cashier/QueryTradeInfo/V5'; + break; + + case 'AioCheckOut': + $api_payment_info['action'] = 'https://payment.ecpay.com.tw/Cashier/AioCheckOut/V5'; + break; + + default: + break; + } + } + + return $api_payment_info; + } + + public function get_item_name($order) + { + $item_name = ''; + + if (count($order->get_items())) { + + foreach ($order->get_items() as $item) { + $item_name .= str_replace('#', '', trim($item->get_name())) . '#'; + } + } + + $item_name = rtrim($item_name, '#'); + + return $item_name; + } + + public function add_type_info($input, $order) + { + $payment_type = $this->get_ChoosePayment($order->get_payment_method()); + + switch ($payment_type) { + + case 'Credit': + + // 信用卡分期 + $number_of_periods = (int) $order->get_meta('_ecpay_payment_number_of_periods', true); + if (in_array($number_of_periods, [3, 6, 12, 18, 24, 30])) { + $input['CreditInstallment'] = ($number_of_periods == 30) ? '30N' : $number_of_periods; + $order->add_order_note(sprintf(__('Credit installment to %d', 'ecpay-ecommerce-for-woocommerce'), $number_of_periods)); + + $order->save(); + } + + // 定期定額 + $dca = $order->get_meta('_ecpay_payment_dca'); + $dcaInfo = explode('_', $dca); + if (count($dcaInfo) > 1) { + $input['PeriodAmount'] = $input['TotalAmount']; + $input['PeriodType'] = $dcaInfo[0]; + $input['Frequency'] = (int)$dcaInfo[1]; + $input['ExecTimes'] = (int)$dcaInfo[2]; + $input['PeriodReturnURL'] = $input['ReturnURL']; + } + + break; + + case 'ATM': + + $settings = get_option('woocommerce_Wooecpay_Gateway_Atm_settings', false); + + if(isset($settings['expire_date'])){ + $expire_date = (int)$settings['expire_date']; + } else { + $expire_date = 3; + } + + $input['ExpireDate'] = $expire_date; + + break; + + case 'BARCODE': + + $settings = get_option('woocommerce_Wooecpay_Gateway_Barcode_settings', false); + + if(isset($settings['expire_date'])){ + $expire_date = (int)$settings['expire_date']; + } else { + $expire_date = 3; + } + + $input['StoreExpireDate'] = $expire_date; + + break; + + case 'CVS': + + $settings = get_option('woocommerce_Wooecpay_Gateway_Cvs_settings', false); + + if(isset($settings['expire_date'])){ + $expire_date = (int)$settings['expire_date']; + } else { + $expire_date = 10080; + } + + $input['StoreExpireDate'] = $expire_date; + + break; + } + + return $input; + } + + public function get_ChoosePayment($payment_method) + { + $choose_payment = ''; + + switch ($payment_method) { + case 'Wooecpay_Gateway_Credit': + case 'Wooecpay_Gateway_Credit_Installment': + case 'Wooecpay_Gateway_Dca': + $choose_payment = 'Credit'; + break; + case 'Wooecpay_Gateway_Webatm': + $choose_payment = 'WebATM'; + break; + case 'Wooecpay_Gateway_Atm': + $choose_payment = 'ATM'; + break; + case 'Wooecpay_Gateway_Cvs': + $choose_payment = 'CVS'; + break; + case 'Wooecpay_Gateway_Barcode': + $choose_payment = 'BARCODE'; + break; + case 'Wooecpay_Gateway_Applepay': + $choose_payment = 'ApplePay'; + break; + case 'Wooecpay_Gateway_Twqr': + $choose_payment = 'TWQR'; + break; + case 'Wooecpay_Gateway_Bnpl': + $choose_payment = 'BNPL'; + break; + } + + return $choose_payment; + } + + /** + * 新增訂單付款資訊 + * + * @param int $order_id + * @param string $payment_method + * @param string $merchant_trade_no + * @param int $payment_status + * @return void + */ + public function insert_ecpay_orders_payment_status($order_id, $payment_method, $merchant_trade_no, $payment_status = 0) + { + global $wpdb; + + $is_exist = false; + $table_name = $wpdb->prefix . 'ecpay_orders_payment_status'; + $isTableExists = $wpdb->get_var( "SHOW TABLES LIKE '$table_name'" ) === $table_name; + + // Table 存在才能新增資料 + if ($isTableExists) { + + // 檢查資料是否存在 + if ($payment_method === 'cod') { + $is_exist = $this->is_cod_payment_status_exist($order_id); + } else { + $is_exist = $this->is_ecpay_orders_payment_status_exist($order_id, $merchant_trade_no); + } + + // 資料存在不新增 + if (!$is_exist) { + $insert = [ + 'order_id' => $order_id, + 'payment_method' => $payment_method, + 'merchant_trade_no' => $merchant_trade_no, + 'payment_status' => $payment_status + ]; + + $format = [ + '%d', + '%s', + '%s', + '%d' + ]; + + $wpdb->insert($table_name, $insert, $format); + } + } + } + + /** + * 取得重複付款訂單的綠界金流特店交易編號 + * + * @param string $order_id + * @return array + */ + public function get_duplicate_payment_orders_merchant_trade_no($order_id) { + global $wpdb; + $table_name = $wpdb->prefix . 'ecpay_orders_payment_status'; + + $results = $wpdb->get_results( + $wpdb->prepare( + "SELECT merchant_trade_no + FROM $table_name + WHERE order_id = %d AND payment_status = 1 AND is_completed_duplicate = 0 + ORDER BY id DESC", + $order_id + ) + ); + + if (!empty($results)) { + $merchant_trade_no_list = []; + foreach ($results as $result) { + array_push($merchant_trade_no_list, $result->merchant_trade_no); + } + return $merchant_trade_no_list; + } else { + return []; + } + } + + /** + * 檢查是否已存在貨到付款紀錄 + * + * @param string $order_id + * @return bool + */ + public function is_cod_payment_status_exist($order_id) { + global $wpdb; + $table_name = $wpdb->prefix . 'ecpay_orders_payment_status'; + + $count = (int) $wpdb->get_var( + $wpdb->prepare( + "SELECT COUNT(merchant_trade_no) + FROM $table_name + WHERE order_id = %d AND payment_method = %s", + $order_id, + 'cod' + ) + ); + + return ($count > 0); + } + + /** + * 檢查綠界金流特店交易編號是否已存在 + * + * @param string $order_id + * @param string $merchant_trade_no + * @return bool + */ + public function is_ecpay_orders_payment_status_exist($order_id, $merchant_trade_no) { + global $wpdb; + $table_name = $wpdb->prefix . 'ecpay_orders_payment_status'; + + $count = (int) $wpdb->get_var( + $wpdb->prepare( + "SELECT COUNT(merchant_trade_no) + FROM $table_name + WHERE order_id = %d AND merchant_trade_no = %s", + $order_id, $merchant_trade_no + ) + ); + + return ($count > 0); + } + + /** + * 檢查綠界金流特店交易編號是否已付款 + * + * @param string $order_id + * @param string $merchant_trade_no + * @return bool + */ + public function is_ecpay_order_paid($order_id, $merchant_trade_no) { + global $wpdb; + $table_name = $wpdb->prefix . 'ecpay_orders_payment_status'; + + $results = $wpdb->get_results( + $wpdb->prepare( + "SELECT payment_status + FROM $table_name + WHERE order_id = %d AND merchant_trade_no = %s + LIMIT 1", + $order_id, $merchant_trade_no + ) + ); + + if (!empty($results)) { + return ($results[0]->payment_status === 1); + } else { + return false; + } + } + + /** + * 標示重複付款訂單已處理 + * + * @param string $order_id + * @return array|object|null + */ + public function update_order_ecpay_orders_payment_status_complete($order_id) { + global $wpdb; + $table_name = $wpdb->prefix . 'ecpay_orders_payment_status'; + + $result = $wpdb->get_results( + $wpdb->prepare( + "UPDATE $table_name + SET is_completed_duplicate = 1, updated_at = CURRENT_TIMESTAMP + WHERE order_id = %d AND is_completed_duplicate = 0", + $order_id + ) + ); + + return $result; + } + + /** + * 更新訂單付款結果 + * + * @param string $order_id + * @param array $info + * @return void + */ + public function update_order_ecpay_orders_payment_status($order_id, $info) { + global $wpdb; + $table_name = $wpdb->prefix . 'ecpay_orders_payment_status'; + + // 模擬付款不更新付款狀態 + if (isset($info['SimulatePaid']) && $info['SimulatePaid'] == 0) { + $wpdb->get_results( + $wpdb->prepare( + "UPDATE $table_name + SET payment_status = %d, updated_at = CURRENT_TIMESTAMP + WHERE order_id = %d AND merchant_trade_no = %s AND is_completed_duplicate = 0", + $info['RtnCode'], + $order_id, + $info['MerchantTradeNo'], + ) + ); + } + } + + /** + * 取得綠界金流 + * + * @return array + */ + public function get_ecpay_payment_method() + { + return [ + 'Wooecpay_Gateway_Credit', + 'Wooecpay_Gateway_Credit_Installment', + 'Wooecpay_Gateway_Webatm', + 'Wooecpay_Gateway_Atm', + 'Wooecpay_Gateway_Cvs', + 'Wooecpay_Gateway_Barcode', + 'Wooecpay_Gateway_Applepay', + 'Wooecpay_Gateway_Dca', + 'Wooecpay_Gateway_Twqr', + 'Wooecpay_Gateway_Bnpl' + ]; + } + + /** + * 判斷是否為綠界金流 + * + * @param string $payment_method + * @return bool + */ + public function is_ecpay_payment_method($payment_method) + { + return in_array($payment_method, $this->get_ecpay_payment_method()); + } + + /** + * 檢查訂單是否重複付款 + * + * @param WC_Order $order + * @return array + */ + public function check_order_is_duplicate_payment($order) + { + $is_duplicate_payment = 0; // 0:沒有重複付款紀錄、1:有重複付款紀錄 + $merchant_trade_no_list = []; + + // 取得訂單付款方式 + $payment_method = $order->get_meta('_payment_method', true); + + // 取得重複付款訂單的綠界金流特店交易編號 + $merchant_trade_no_list = $this->get_duplicate_payment_orders_merchant_trade_no($order->get_id()); + $count_merchant_trade_no = count($merchant_trade_no_list); + + // 僅檢查付款方式是綠界金流或貨到付款的訂單 + if ($this->is_ecpay_payment_method($payment_method) || $payment_method === 'cod') { + // 超過 1 筆已付款的紀錄 + if ($count_merchant_trade_no > 1) { + $is_duplicate_payment = 1; + } + } + + return [ + 'code' => $is_duplicate_payment, + 'merchant_trade_no' => $merchant_trade_no_list + ]; + } +} diff --git a/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-bnpl.php b/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-bnpl.php new file mode 100644 index 0000000..69db334 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-bnpl.php @@ -0,0 +1,78 @@ +id = 'Wooecpay_Gateway_Bnpl'; + $this->payment_type = 'BNPL'; + $this->icon = plugins_url('images/icon.png', dirname(dirname( __FILE__ )) ); + $this->has_fields = false; + $this->method_title = __('ECPay BNPL', 'ecpay-ecommerce-for-woocommerce'); + $this->method_description = '使用綠界無卡分期付款'; + + $this->title = $this->get_option('title'); + $this->description = $this->get_option('description'); + $this->min_amount = (int) $this->get_option('min_amount', 0); + $this->max_amount = (int) $this->get_option('max_amount', 0); + + $this->form_fields = include WOOECPAY_PLUGIN_INCLUDE_DIR . '/config/payment/settings-gateway-bnpl.php' ; + $this->init_settings(); + + parent::__construct(); + + add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']); + } + + // 後台參數設定後端驗證 + public function process_admin_options() + { + // 最小值判斷 + $_POST['woocommerce_' . $this->id . '_min_amount'] = (int) $_POST['woocommerce_' . $this->id . '_min_amount']; + + if ($_POST['woocommerce_' . $this->id . '_min_amount'] < 3000) { + $_POST['woocommerce_' . $this->id . '_min_amount'] = 3000; + WC_Admin_Settings::add_error(sprintf(__('%s minimum amount out of range. Set as default value.', 'ecpay-ecommerce-for-woocommerce'), $this->method_title)); + } + + parent::process_admin_options(); + } + + // 購物車金流顯示判斷 + public function is_available() + { + if ('yes' == $this->enabled && WC()->cart) { + $total = $this->get_order_total(); + + if ($total > 0) { + // 訂單金額至少 3000 才開放無卡分期 + if ($this->min_amount > 0 and ($total < $this->min_amount || $total < 3000)) { + return false; + } + + if ($this->max_amount > 0 && $total > $this->max_amount) { + return false; + } + } + } + + return parent::is_available(); + } + + // 處理點擊結帳按鈕後的行為 + public function process_payment($order_id) + { + $order = wc_get_order($order_id); + $order->add_order_note(__('Pay via ECPay BNPL', 'ecpay-ecommerce-for-woocommerce')); + wc_maybe_reduce_stock_levels($order_id); + wc_release_stock_for_order($order); + + return [ + 'result' => 'success', + 'redirect' => $order->get_checkout_payment_url(true), + ]; + } +} diff --git a/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-dca.php b/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-dca.php new file mode 100644 index 0000000..8955293 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-dca.php @@ -0,0 +1,333 @@ +id = 'Wooecpay_Gateway_Dca'; + $this->payment_type = 'Credit'; + $this->icon = plugins_url('images/icon.png', dirname(dirname( __FILE__ ))); + $this->has_fields = true; + $this->method_title = __('ECPay DCA', 'ecpay-ecommerce-for-woocommerce'); + $this->method_description = '使用綠界定期定額付款'; + + $this->enabled = $this->get_option('enabled'); + $this->title = $this->get_option('title'); + $this->description = $this->get_option('description'); + $this->min_amount = (int) $this->get_option('min_amount', 0); + $this->max_amount = (int) $this->get_option('max_amount', 0); + + $this->form_fields = include WOOECPAY_PLUGIN_INCLUDE_DIR . '/config/payment/settings-gateway-dca.php' ; + + // 預設情定額付款方式 + $this->ecpay_dca_payment = $this->get_ecpay_dca_payment(); + $this->ecpay_dca_options = get_option('woocommerce_ecpay_dca', + array( + array( + 'periodType' => $this->get_option('periodType'), + 'frequency' => $this->get_option('frequency'), + 'execTimes' => $this->get_option('execTimes'), + ), + ) + ); + + $this->init_settings(); + + parent::__construct(); + + add_action('admin_enqueue_scripts' , array($this, 'wooecpay_register_scripts')); + add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']); + add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'save_dca_details')); + } + + public function process_admin_options() + { + parent::process_admin_options(); + } + + /** + * 前台 - 顯示定期定額付款選項 + */ + public function is_available() + { + if ('yes' == $this->enabled && WC()->cart) { + $total = $this->get_order_total(); + if ($total > 0) { + if ($this->min_amount > 0 && $total < $this->min_amount) { + return false; + } + if ($this->max_amount > 0 && $total > $this->max_amount) { + return false; + } + } + } + + return parent::is_available(); + } + + /** + * 前台 - 顯示定期定額付款方式select + */ + public function payment_fields() + { + parent::payment_fields(); + $total = $this->get_order_total(); + + if (is_checkout() && !is_wc_endpoint_url('order-pay') ) { + $data = array( + 'ecpay_dca_options' => get_option('woocommerce_ecpay_dca', []), + 'cart_total' => $total + ); + echo $this->show_ecpay_dca_payment_fields($data); + } + } + + /** + * 前台 - 結帳定期定額付款選項 + * + * @param array $data + * @return void + */ + public function show_ecpay_dca_payment_fields($data) + { + // 宣告變數 + $ecpay_dca_options = $data['ecpay_dca_options']; + $cart_total = $data['cart_total']; + $periodTypeMethod = [ + 'Y' => ' ' . __('year', 'ecpay-ecommerce-for-woocommerce'), + 'M' => ' ' . __('month', 'ecpay-ecommerce-for-woocommerce'), + 'D' => ' ' . __('day', 'ecpay-ecommerce-for-woocommerce') + ]; + + // Html + $szHtml = ''; + $szHtml .= ''; + + $szHtml .= '
'; + $szHtml .= '
'; + $szHtml .= '

'; + $szHtml .= '你將使用綠界科技定期定額信用卡付款,請留意你所購買的商品為非單次扣款商品。'; + $szHtml .= '

'; + + return $szHtml; + } + + /** + * 前台 - 整理定期定額付款選項option格式 + * + * @param string $value + * @param string $data + * @return string $szHtml + */ + private function generate_option($value, $data) + { + $szHtml = ''; + $szHtml .= ''; + + return $szHtml; + } + + /** + * 後台 - 載入定期定額JS後產生後台設定表格 + * + * @return void + */ + public function generate_ecpay_dca_html() + { + ob_start(); + + // 指定到 settings-gateway-dca.php 的欄位 type(ecpay_dca) + $data = array( + 'ecpay_dca_options' => $this->ecpay_dca_options + ); + echo $this->show_ecpay_dca_table($data); + + return ob_get_clean(); + } + + /** + * 後台 - 載入js + * + * @return void + */ + public function wooecpay_register_scripts() + { + wp_register_script( + 'wooecpay_dca', + WOOECPAY_PLUGIN_URL . 'public/js/wooecpay-dca.js', + array(), + '1.0.0', + true + ); + wp_enqueue_script('wooecpay_dca'); + } + + /** + * 後台 - 定期定額設定頁表格 + * + * @param array $data + * @return void + */ + public function show_ecpay_dca_table($data) + { + // 宣告參數 + $options = $data['ecpay_dca_options']; + ?> + + + + + + + + + + + + + + + "Y", + 'frequency' => "1", + 'execTimes' => "6", + ], + [ + 'periodType' => "M", + 'frequency' => "1", + 'execTimes' => "12", + ], + ]; + } + + $i = -1; + if ( is_array($options) ) { + foreach ( $options as $option ) { + $i++; + echo ' + + + + + '; + } + } + ?> + + + + + + +
 
+ + +
+

+ + + + $name) { + if (!isset($periodTypes[$i])) { + continue; + } + + $ecpayDcaOptions[] = array( + 'periodType' => sanitize_text_field($periodTypes[$i]), + 'frequency' => sanitize_text_field($frequencys[$i]), + 'execTimes' => sanitize_text_field($execTimes[$i]), + ); + } + } + + update_option('woocommerce_ecpay_dca', $ecpayDcaOptions); + } + + /** + * 整理定期定額參數成 Array + * + * @param array $data + * @return void + */ + public function get_ecpay_dca_payment() + { + $ecpayDcaOptions = get_option('woocommerce_ecpay_dca'); + $dcaPaymentList = []; + if (is_array($ecpayDcaOptions)) { + foreach ($ecpayDcaOptions as $option) { + array_push($dcaPaymentList, $option['periodType'] . '_' . $option['frequency'] . '_' . $option['execTimes']); + } + } + + return $dcaPaymentList; + } + + public function process_payment($order_id) + { + $order = wc_get_order($order_id); + $order->add_order_note(__('Pay via ECPay DCA', 'ecpay-ecommerce-for-woocommerce')); + + if (isset($_POST['ecpay_dca_payment'])) { + $order->update_meta_data('_ecpay_payment_dca', $_POST['ecpay_dca_payment']); + } + $order->save(); + + return array( + 'result' => 'success', + 'redirect' => $order->get_checkout_payment_url(true) + ); + } +} diff --git a/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-twqr.php b/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-twqr.php new file mode 100644 index 0000000..a5f4350 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/includes/services/payment/ecpay-gateway-twqr.php @@ -0,0 +1,75 @@ +id = 'Wooecpay_Gateway_Twqr'; + $this->payment_type = 'TWQR'; + $this->icon = plugins_url('images/icon.png', dirname(dirname( __FILE__ )) ); + $this->has_fields = false; + $this->method_title = __('ECPay TWQR', 'ecpay-ecommerce-for-woocommerce'); + $this->method_description = '使用綠界TWQR付款'; + + $this->title = $this->get_option('title'); + $this->description = $this->get_option('description'); + $this->min_amount = (int) $this->get_option('min_amount', 0); + $this->max_amount = (int) $this->get_option('max_amount', 0); + + $this->form_fields = include WOOECPAY_PLUGIN_INCLUDE_DIR . '/config/payment/settings-gateway-twqr.php' ; + $this->init_settings(); + + parent::__construct(); + + add_action('woocommerce_update_options_payment_gateways_' . $this->id, [$this, 'process_admin_options']); + } + + // 後台參數設定後端驗證 + public function process_admin_options() + { + // 最小值判斷 + $_POST['woocommerce_' . $this->id . '_min_amount'] = (int) $_POST['woocommerce_' . $this->id . '_min_amount']; + + if ($_POST['woocommerce_' . $this->id . '_min_amount'] < 0) { + $_POST['woocommerce_' . $this->id . '_min_amount'] = 0; + WC_Admin_Settings::add_error(sprintf(__('%s minimum amount out of range. Set as default value.', 'ecpay-ecommerce-for-woocommerce'), $this->method_title)); + } + + parent::process_admin_options(); + } + + // 購物車金流顯示判斷 + public function is_available() + { + if ('yes' == $this->enabled && WC()->cart) { + $total = $this->get_order_total(); + if ($total > 0) { + if ($this->min_amount > 0 && $total < $this->min_amount) { + return false; + } + if ($this->max_amount > 0 && $total > $this->max_amount) { + return false; + } + } + } + + return parent::is_available(); + } + + // 處理點擊結帳按鈕後的行為 + public function process_payment($order_id) + { + $order = wc_get_order($order_id); + $order->add_order_note(__('Pay via ECPay TWQR', 'ecpay-ecommerce-for-woocommerce')); + wc_maybe_reduce_stock_levels($order_id); + wc_release_stock_for_order($order); + + return [ + 'result' => 'success', + 'redirect' => $order->get_checkout_payment_url(true), + ]; + } +} diff --git a/ecpay-ecommerce-for-woocommerce/public/js/wooecpay-dca.js b/ecpay-ecommerce-for-woocommerce/public/js/wooecpay-dca.js new file mode 100644 index 0000000..bd5a359 --- /dev/null +++ b/ecpay-ecommerce-for-woocommerce/public/js/wooecpay-dca.js @@ -0,0 +1,102 @@ +jQuery(function() { + jQuery('#ecpay_dca').on('click', 'a.add', function() { + var size = jQuery('#ecpay_dca').find('tbody .account').length; + + jQuery('\ + \ + \ + \ + \ + ').appendTo('#ecpay_dca table tbody'); + + return false; + }); + + jQuery('#ecpay_dca').on('blur', 'input', function() { + let field = this.value.trim(); + let indexStart = this.name.search(/[[]/g); + let indexEnd = this.name.search(/[\]]/g); + let fieldIndex = this.name.substring(indexStart + 1, indexEnd); + let fieldPeriodType = document.getElementsByName('periodType[' + fieldIndex + ']')[0].value; + + if ((validateFields.periodType(field) === false && this.className === 'fieldPeriodType') || + (validateFields.frequency(fieldPeriodType, field) === false && this.className === 'fieldFrequency') || + (validateFields.execTimes(fieldPeriodType, field) === false && this.className === 'fieldExecTimes')) { + this.value = ''; + } + }); + + jQuery('#ecpay_dca').on('blur', 'tbody', function() { + fields.process(); + }); + + jQuery('body').on('click', '#mainform', function() { + fields.process(); + }); +}); + +var data = { + periodType: ['D', 'M', 'Y'], + frequency: ['365', '12', '1'], + execTimes: ['999', '99', '9'], +}; + +var fields = { + get: function() { + var field = jQuery('#ecpay_dca').find('tbody .account td input'); + var fieldsInput = []; + var fieldsTmp = []; + var i = 0; + Object.keys(field).forEach(function(key) { + if (field[key].value != null) { + i++; + if (i % 3 == 0) { + fieldsTmp.push(field[key].value); + fieldsInput.push(fieldsTmp); + fieldsTmp = []; + } else { + fieldsTmp.push(field[key].value); + } + } + }); + + return fieldsInput; + }, + check: function(inputs) { + var errorFlag = 0; + inputs.forEach(function(key1, index1) { + inputs.forEach(function(key2, index2) { + if (index1 !== index2) { + if (key1[0] === key2[0] && key1[1] === key2[1] && key1[2] === key2[2]) { + errorFlag++; + } + } + }) + }); + + return errorFlag; + }, + process: function() { + if (fields.check(fields.get()) > 0) { + document.getElementById('fieldsNotification').style = 'color: #ff0000;'; + document.querySelector('input[name="save"]').disabled = true; + } else { + document.getElementById('fieldsNotification').style = 'display: none;'; + document.querySelector('input[name="save"]').disabled = false; + } + } +} + +var validateFields = { + periodType: function(field) { + return (data.periodType.indexOf(field) !== -1); + }, + frequency: function(periodType, field) { + let maxFrequency = parseInt(data.frequency[data.periodType.indexOf(periodType)], 10); + return ((field > 0) && ((maxFrequency + 1) > field)); + }, + execTimes: function(periodType, field) { + let maxExecTimes = parseInt(data.execTimes[data.periodType.indexOf(periodType)], 10); + return ((field > 1) && ((maxExecTimes + 1) > field)); + } +}; \ No newline at end of file