Changeset 3325437
- Timestamp:
- 07/10/2025 07:55:08 AM (9 months ago)
- Location:
- sepay-gateway
- Files:
-
- 5 deleted
- 7 edited
- 11 copied
-
tags/1.1.16 (copied) (copied from sepay-gateway/trunk)
-
tags/1.1.16/assets/css/sepay.css (copied) (copied from sepay-gateway/trunk/assets/css/sepay.css) (1 diff)
-
tags/1.1.16/assets/js/block/checkout.js (copied) (copied from sepay-gateway/trunk/assets/js/block/checkout.js)
-
tags/1.1.16/assets/js/main.js (modified) (5 diffs)
-
tags/1.1.16/assets/js/sepay.js (copied) (copied from sepay-gateway/trunk/assets/js/sepay.js)
-
tags/1.1.16/css (deleted)
-
tags/1.1.16/imgs (deleted)
-
tags/1.1.16/includes/block (deleted)
-
tags/1.1.16/includes/class-sepay-woocommerce-block-checkout.php (deleted)
-
tags/1.1.16/includes/class-wc-gateway-sepay.php (copied) (copied from sepay-gateway/trunk/includes/class-wc-gateway-sepay.php) (7 diffs)
-
tags/1.1.16/includes/class-wc-sepay-api.php (copied) (copied from sepay-gateway/trunk/includes/class-wc-sepay-api.php) (3 diffs)
-
tags/1.1.16/includes/class-wc-sepay-blocks-support.php (copied) (copied from sepay-gateway/trunk/includes/class-wc-sepay-blocks-support.php)
-
tags/1.1.16/includes/views (copied) (copied from sepay-gateway/trunk/includes/views)
-
tags/1.1.16/includes/views/oauth2-connect.php (copied) (copied from sepay-gateway/trunk/includes/views/oauth2-connect.php)
-
tags/1.1.16/js (deleted)
-
tags/1.1.16/readme.txt (copied) (copied from sepay-gateway/trunk/readme.txt) (2 diffs)
-
tags/1.1.16/sepay-gateway.php (copied) (copied from sepay-gateway/trunk/sepay-gateway.php) (3 diffs)
-
trunk/assets/css/sepay.css (modified) (1 diff)
-
trunk/assets/js/main.js (modified) (5 diffs)
-
trunk/includes/class-wc-gateway-sepay.php (modified) (7 diffs)
-
trunk/includes/class-wc-sepay-api.php (modified) (3 diffs)
-
trunk/readme.txt (modified) (2 diffs)
-
trunk/sepay-gateway.php (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
-
sepay-gateway/tags/1.1.16/assets/css/sepay.css
r3254400 r3325437 535 535 } 536 536 537 .dynamic-sub-account:disabled { 538 background-color: #f5f5f5; 539 color: #999; 540 cursor: not-allowed; 541 } 542 543 .dynamic-sub-account:disabled option { 544 color: #999; 545 } 546 547 .dynamic-sub-account option[value=""] { 548 color: #666; 549 font-style: italic; 550 } 551 552 .dynamic-sub-account[disabled] { 553 background-color: #f5f5f5; 554 color: #999; 555 cursor: not-allowed; 556 opacity: 0.6; 557 } 558 559 .dynamic-sub-account[disabled] option { 560 color: #999; 561 } 562 537 563 @media (max-width: 480px) { 538 564 .sepay-pay-info .manual-box .bank-info .bank-info-value span:first-child { -
sepay-gateway/tags/1.1.16/assets/js/main.js
r3253697 r3325437 15 15 loadingSpinner.show(); 16 16 17 const requiresSubAccount = ['BIDV', 'MSB', 'KienLongBank', 'OCB'].includes(bankShortName); 17 const excludedSubAccountBanks = ['TPBank', 'VPBank', 'VietinBank']; 18 const requiredSubAccountBanks = ['BIDV', 'MSB', 'KienLongBank', 'OCB']; 19 const requiresSubAccount = requiredSubAccountBanks.includes(bankShortName) && !excludedSubAccountBanks.includes(bankShortName); 18 20 19 21 if (requiresSubAccount) { … … 137 139 if (response.success && response.data.length > 0) { 138 140 options = response.data.map(function (bankAccount) { 139 return `<option value="${bankAccount.id}">${bankAccount.bank. short_name} - ${bankAccount.account_number} - ${bankAccount.account_holder_name}</option>`;141 return `<option value="${bankAccount.id}">${bankAccount.bank.brand_name} - ${bankAccount.account_number} - ${bankAccount.account_holder_name}</option>`; 140 142 }); 141 143 } … … 181 183 bankAccountField.on('change', function () { 182 184 const selectedBankAccountId = jQuery(this).val(); 185 const selectedOption = jQuery(this).find('option:selected'); 186 const bankName = selectedOption.text().split(' - ')[0]; 187 const currentSubAccountValue = subAccountField.val(); 183 188 184 189 if (!selectedBankAccountId) { 185 190 subAccountField.html('<option value="">Vui lòng chọn tài khoản ngân hàng trước</option>'); 191 subAccountField.prop('disabled', true); 186 192 return; 187 193 } 188 194 195 const excludedSubAccountBanks = ['TPBank', 'VPBank', 'VietinBank']; 196 const requiredSubAccountBanks = ['BIDV', 'MSB', 'KienLongBank', 'OCB']; 197 198 if (excludedSubAccountBanks.includes(bankName)) { 199 subAccountField.html('<option value="">Ngân hàng ' + bankName + ' không hỗ trợ tài khoản VA</option>'); 200 subAccountField.prop('disabled', true); 201 return; 202 } 203 204 subAccountField.prop('disabled', false); 189 205 subAccountField.html(loadingMessage); 190 206 … … 198 214 success: function (response) { 199 215 let options = []; 200 options.push('<option value="">-- Chọn tài khoản ảo --</option>');201 216 if (response.success && response.data.length > 0) { 217 options.push('<option value="">-- Chọn tài khoản ảo --</option>'); 202 218 response.data.map(function (subAccount) { 203 219 options.push(`<option value="${subAccount.account_number}">${subAccount.account_number}${subAccount.label ? ` - ${subAccount.label}` : ''}</option>`); 204 220 }); 221 } else { 222 options.push('<option value="">Không có tài khoản VA nào</option>'); 205 223 } 206 224 subAccountField.html(options.join('')); 225 226 if (currentSubAccountValue && response.success && response.data.length > 0) { 227 const subAccountExists = response.data.some(function(subAccount) { 228 return subAccount.account_number === currentSubAccountValue; 229 }); 230 if (subAccountExists) { 231 subAccountField.val(currentSubAccountValue); 232 } 233 } 207 234 }, 208 235 error: function () { … … 220 247 } 221 248 249 if (bankAccountField.length && bankAccountField.val()) { 250 setTimeout(function() { 251 const savedSubAccountValue = subAccountField.val(); 252 bankAccountField.trigger('change'); 253 254 if (savedSubAccountValue) { 255 setTimeout(function() { 256 if (subAccountField.find(`option[value="${savedSubAccountValue}"]`).length) { 257 subAccountField.val(savedSubAccountValue); 258 } 259 }, 200); 260 } 261 }, 100); 262 } 263 222 264 function update_account_number_field_ui() { 223 265 const bank = jQuery('#woocommerce_sepay_bank_select').val() 224 225 if (['bidv', 'ocb', 'msb', 'kienlongbank'].includes(bank)) { 266 const excludedSubAccountBanks = ['tpbank', 'vpbank', 'vietinbank']; 267 const requiredSubAccountBanks = ['bidv', 'ocb', 'msb', 'kienlongbank']; 268 269 if (requiredSubAccountBanks.includes(bank) && !excludedSubAccountBanks.includes(bank)) { 226 270 jQuery('label[for=woocommerce_sepay_bank_account_number]').html('Số VA'); 227 271 jQuery('input[name=woocommerce_sepay_bank_account_number]').parent().find('.help-text').html('Vui lòng điền chính xác <strong>số VA</strong> để nhận được biến động giao dịch.') -
sepay-gateway/tags/1.1.16/includes/class-wc-gateway-sepay.php
r3322376 r3325437 167 167 } 168 168 169 if ($this->api->is_required_sub_account($bank_account_id, $this->bank_accounts) && empty($sub_account)) { 170 WC_Admin_Settings::add_error('Ngân hàng đang chọn yêu cầu tài khoản VA. Vui lòng chọn tài khoản VA trước khi lưu.'); 171 return false; 169 $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank']; 170 $bank_account = array_filter($this->bank_accounts, function ($account) use ($bank_account_id) { 171 return $account['id'] == $bank_account_id; 172 }); 173 174 if (!empty($bank_account)) { 175 reset($bank_account); 176 $key = key($bank_account); 177 $bank_short_name = $bank_account[$key]['bank']['short_name']; 178 179 if (in_array($bank_short_name, $excluded_sub_account_banks) && !empty($sub_account)) { 180 WC_Admin_Settings::add_error('Ngân hàng ' . $bank_short_name . ' không hỗ trợ tài khoản VA. Vui lòng bỏ chọn tài khoản VA.'); 181 return false; 182 } 183 } 184 185 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 186 $bank_account = array_filter($this->bank_accounts, function ($account) use ($bank_account_id) { 187 return $account['id'] == $bank_account_id; 188 }); 189 190 if (!empty($bank_account)) { 191 reset($bank_account); 192 $key = key($bank_account); 193 $bank_short_name = $bank_account[$key]['bank']['short_name']; 194 195 if (in_array($bank_short_name, $required_sub_account_banks) && empty($sub_account)) { 196 WC_Admin_Settings::add_error('Ngân hàng ' . $bank_short_name . ' yêu cầu phải chọn tài khoản VA. Vui lòng chọn tài khoản VA trước khi lưu.'); 197 return false; 198 } 172 199 } 173 200 … … 265 292 $this->api->refresh_token(); 266 293 } catch (Exception $e) { 267 WC_Admin_Settings::add_error('Không thể làm mới token. Vui lòng thử lại sau.');268 294 $this->init_old_form_fields(); 269 295 return; … … 317 343 $sub_account_options = []; 318 344 319 $sub_accounts = $this->api->get_bank_sub_accounts($selected_bank_account); 320 321 $sub_account_options = [ 322 '' => '-- Chọn tài khoản ảo --', 323 ]; 324 325 if (! empty($sub_accounts)) { 326 foreach ($sub_accounts as $sub_account) { 327 $sub_account_options[$sub_account['account_number']] = $sub_account['account_number'] . ($sub_account['label'] ? " - {$sub_account['label']}" : ''); 345 $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank']; 346 $show_sub_account_field = true; 347 348 if (!empty($selected_bank_account)) { 349 $bank_account = array_filter($this->bank_accounts, function ($account) use ($selected_bank_account) { 350 return $account['id'] == $selected_bank_account; 351 }); 352 353 if (!empty($bank_account)) { 354 reset($bank_account); 355 $key = key($bank_account); 356 $bank_short_name = $bank_account[$key]['bank']['short_name']; 357 358 if (in_array($bank_short_name, $excluded_sub_account_banks)) { 359 $show_sub_account_field = false; 360 } 328 361 } 329 362 } 330 363 331 $form_fields['sub_account'] = [ 332 'title' => 'Tài khoản VA', 333 'type' => 'select', 334 'description' => 'Tài khoản ngân hàng bạn chọn yêu cầu chọn tài khoản VA để nhận thanh toán <br> (Lưu ý: Bạn không thể sử dụng tài khoản VA để nhận thanh toán đối với các ngân hàng TPBank, VPBank và VietinBank).', 335 'options' => $sub_account_options, 336 'class' => 'dynamic-sub-account', 337 'default' => '', 338 ]; 364 if ($show_sub_account_field) { 365 $sub_accounts = $this->api->get_bank_sub_accounts($selected_bank_account); 366 367 $sub_account_options = []; 368 369 if (! empty($sub_accounts)) { 370 $sub_account_options[''] = '-- Chọn tài khoản ảo --'; 371 foreach ($sub_accounts as $sub_account) { 372 $sub_account_options[$sub_account['account_number']] = $sub_account['account_number'] . ($sub_account['label'] ? " - {$sub_account['label']}" : ''); 373 } 374 } else { 375 $sub_account_options[''] = '-- Không có tài khoản VA nào --'; 376 } 377 378 $form_fields['sub_account'] = [ 379 'title' => 'Tài khoản VA', 380 'type' => 'select', 381 'description' => 'Chọn tài khoản VA để nhận thanh toán (nếu có). Một số ngân hàng yêu cầu phải chọn tài khoản VA. <br> (Lưu ý: TPBank, VPBank và VietinBank không hỗ trợ tài khoản VA).', 382 'options' => $sub_account_options, 383 'class' => 'dynamic-sub-account', 384 'default' => $this->get_option('sub_account'), 385 ]; 386 } else { 387 $form_fields['sub_account'] = [ 388 'title' => 'Tài khoản VA', 389 'type' => 'select', 390 'description' => 'Ngân hàng này không hỗ trợ tài khoản VA.', 391 'options' => [ 392 '' => '-- Không hỗ trợ tài khoản VA --', 393 ], 394 'class' => 'dynamic-sub-account', 395 'default' => '', 396 'custom_attributes' => [ 397 'disabled' => 'disabled', 398 ], 399 ]; 400 } 339 401 } 340 402 … … 616 678 $bank_account_id = $this->get_option('bank_account'); 617 679 $bank_account = $this->api->get_bank_account($bank_account_id); 618 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $bank_account['account_number']; 680 681 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 682 $bank_short_name = $this->cached_bank_account_data['bank']['short_name']; 683 684 if (in_array($bank_short_name, $required_sub_account_banks)) { 685 $account_number = $this->get_option('sub_account'); 686 if (empty($account_number)) { 687 $account_number = $bank_account['account_number']; 688 } 689 } else { 690 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $bank_account['account_number']; 691 } 692 619 693 $account_holder_name = $this->cached_bank_account_data['account_holder_name']; 620 694 $bank_bin = $this->cached_bank_account_data['bank']['bin']; … … 622 696 $displayed_bank_name = $this->displayed_bank_name; 623 697 } else { 624 $account_number = $this->get_option('bank_account_number'); 698 $bank_select = $this->get_option('bank_select'); 699 $bank_info = $this->get_bank_info($bank_select); 700 701 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $this->get_option('bank_account_number'); 625 702 $account_holder_name = $this->get_option('bank_account_holder'); 626 627 $bank_select = $this->get_option('bank_select');628 $bank_info = $this->get_bank_data()[$bank_select];629 703 630 704 if ($bank_info) { … … 670 744 671 745 if ($this->api->is_connected()) { 672 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : ($this->cached_bank_account_data['account_number'] ?? $this->get_option('bank_account_number')); 746 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 747 $bank_short_name = $this->cached_bank_account_data['bank']['short_name'] ?? ''; 748 749 if (in_array($bank_short_name, $required_sub_account_banks)) { 750 $account_number = $this->get_option('sub_account'); 751 if (empty($account_number)) { 752 $account_number = $this->cached_bank_account_data['account_number'] ?? $this->get_option('bank_account_number'); 753 } 754 } else { 755 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : ($this->cached_bank_account_data['account_number'] ?? $this->get_option('bank_account_number')); 756 } 673 757 } else { 674 $account_number = $this->get_option(' bank_account_number');758 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $this->get_option('bank_account_number'); 675 759 } 676 760 … … 835 919 ); 836 920 } 921 922 private function get_bank_info($identifier) 923 { 924 $bank_data = $this->get_bank_data(); 925 926 if (isset($bank_data[$identifier])) { 927 return $bank_data[$identifier]; 928 } 929 930 foreach ($bank_data as $key => $bank) { 931 if ( 932 strtolower($bank['code']) === strtolower($identifier) || 933 $bank['bin'] === $identifier || 934 $bank['short_name'] === $identifier || 935 strtolower($bank['short_name']) === strtolower($identifier) 936 ) { 937 return $bank; 938 } 939 } 940 941 return null; 942 } 837 943 } -
sepay-gateway/tags/1.1.16/includes/class-wc-sepay-api.php
r3322376 r3325437 349 349 } 350 350 351 public function create_webhook($bank_account_id, $webhook_id = null )352 { 353 if (!$this->is_connected()) { 354 return null; 355 } 356 357 $api_key = wp_generate_password(32, false);351 public function create_webhook($bank_account_id, $webhook_id = null, $api_key = null) 352 { 353 if (!$this->is_connected()) { 354 return null; 355 } 356 357 $api_key = $api_key ?: wp_generate_password(32, false); 358 358 359 359 $api_path = 'sepay-gateway/v2/add-payment'; … … 494 494 { 495 495 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 496 $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank']; 496 497 $bank_accounts = $bank_accounts ?? $this->get_bank_accounts(); 497 498 … … 506 507 reset($bank_account); 507 508 $key = key($bank_account); 508 509 return in_array($bank_account[$key]['bank']['short_name'], $required_sub_account_banks); 510 } 511 512 public function check_connection_health() 513 { 514 try { 515 $response = $this->make_request('me'); 516 if ($response && isset($response['data'])) { 517 return true; 518 } 509 $bank_short_name = $bank_account[$key]['bank']['short_name']; 510 511 if (in_array($bank_short_name, $excluded_sub_account_banks)) { 519 512 return false; 520 } catch (Exception $e) { 521 $this->log_error('Health check failed', [ 522 'error' => $e->getMessage() 523 ]); 524 return false; 525 } 526 } 527 528 public function get_connection_status() 529 { 530 $access_token = get_option('wc_sepay_access_token'); 531 $refresh_token = get_option('wc_sepay_refresh_token'); 532 $token_expires = get_option('wc_sepay_token_expires'); 533 $last_connected_at = get_option('wc_sepay_last_connected_at'); 534 535 $status = [ 536 'is_connected' => !empty($access_token) && !empty($refresh_token), 537 'token_expires_in' => $token_expires ? ($token_expires - time()) : 0, 538 'last_connected_at' => $last_connected_at, 539 'health_check' => $this->check_connection_health() 540 ]; 541 542 return $status; 513 } 514 515 return in_array($bank_short_name, $required_sub_account_banks); 543 516 } 544 517 -
sepay-gateway/tags/1.1.16/readme.txt
r3322376 r3325437 4 4 - Tags: woocommerce, payment gateway, vietqr, ngan hang, thanh toan 5 5 - Requires WooCommerce at least: 2.1 6 - Stable Tag: 1.1.1 57 - Version: 1.1.1 56 - Stable Tag: 1.1.16 7 - Version: 1.1.16 8 8 - Tested up to: 6.6 9 9 - Requires at least: 5.6 … … 53 53 == CHANGELOG == 54 54 55 **Version 1.1.16** - 10/07/2025: 56 - [Fix lỗi] Sửa lỗi API key bị thay đổi khi kết nối lại OAuth2 57 - [Cải thiện] Tối ưu hóa hiển thị tài khoản VA cho các ngân hàng yêu cầu VA (BIDV, OCB, MSB, KienLongBank) 58 - [Cải thiện] Tự động lưu và khôi phục tài khoản VA đã chọn khi cấu hình 59 - [Fix lỗi] Sửa lỗi hiển thị tài khoản VA khi chuyển đổi giữa các ngân hàng 60 55 61 **Version 1.1.14** - 04/07/2025: 56 62 - [Cải thiện] Thêm User-Agent và thông tin phiên bản plugin vào header API requests để SePay có thể theo dõi và hỗ trợ tốt hơn -
sepay-gateway/tags/1.1.16/sepay-gateway.php
r3322376 r3325437 6 6 * Author: SePay Team 7 7 * Author URI: https://sepay.vn/ 8 * Version: 1.1.1 58 * Version: 1.1.16 9 9 * Requires Plugins: woocommerce 10 10 * Text Domain: sepay-gateway … … 127 127 $webhook_id = isset($webhooks[0]['id']) ? $webhooks[0]['id'] : null; 128 128 129 $response = $api->create_webhook($bank_account_id, $webhook_id );129 $response = $api->create_webhook($bank_account_id, $webhook_id, $api_token); 130 130 131 131 if ($response['status'] !== 'success') { … … 263 263 $sepay_gateway = $payment_gateways->payment_gateways()['sepay']; 264 264 265 $webhook_api_key = $api->is_connected() ? get_option('wc_sepay_webhook_api_key') : $sepay_gateway->get_option('api_key');265 $webhook_api_key = get_option('wc_sepay_webhook_api_key') ? get_option('wc_sepay_webhook_api_key') : $sepay_gateway->get_option('api_key'); 266 266 267 267 if ($api_key !== $webhook_api_key) { -
sepay-gateway/trunk/assets/css/sepay.css
r3254400 r3325437 535 535 } 536 536 537 .dynamic-sub-account:disabled { 538 background-color: #f5f5f5; 539 color: #999; 540 cursor: not-allowed; 541 } 542 543 .dynamic-sub-account:disabled option { 544 color: #999; 545 } 546 547 .dynamic-sub-account option[value=""] { 548 color: #666; 549 font-style: italic; 550 } 551 552 .dynamic-sub-account[disabled] { 553 background-color: #f5f5f5; 554 color: #999; 555 cursor: not-allowed; 556 opacity: 0.6; 557 } 558 559 .dynamic-sub-account[disabled] option { 560 color: #999; 561 } 562 537 563 @media (max-width: 480px) { 538 564 .sepay-pay-info .manual-box .bank-info .bank-info-value span:first-child { -
sepay-gateway/trunk/assets/js/main.js
r3253697 r3325437 15 15 loadingSpinner.show(); 16 16 17 const requiresSubAccount = ['BIDV', 'MSB', 'KienLongBank', 'OCB'].includes(bankShortName); 17 const excludedSubAccountBanks = ['TPBank', 'VPBank', 'VietinBank']; 18 const requiredSubAccountBanks = ['BIDV', 'MSB', 'KienLongBank', 'OCB']; 19 const requiresSubAccount = requiredSubAccountBanks.includes(bankShortName) && !excludedSubAccountBanks.includes(bankShortName); 18 20 19 21 if (requiresSubAccount) { … … 137 139 if (response.success && response.data.length > 0) { 138 140 options = response.data.map(function (bankAccount) { 139 return `<option value="${bankAccount.id}">${bankAccount.bank. short_name} - ${bankAccount.account_number} - ${bankAccount.account_holder_name}</option>`;141 return `<option value="${bankAccount.id}">${bankAccount.bank.brand_name} - ${bankAccount.account_number} - ${bankAccount.account_holder_name}</option>`; 140 142 }); 141 143 } … … 181 183 bankAccountField.on('change', function () { 182 184 const selectedBankAccountId = jQuery(this).val(); 185 const selectedOption = jQuery(this).find('option:selected'); 186 const bankName = selectedOption.text().split(' - ')[0]; 187 const currentSubAccountValue = subAccountField.val(); 183 188 184 189 if (!selectedBankAccountId) { 185 190 subAccountField.html('<option value="">Vui lòng chọn tài khoản ngân hàng trước</option>'); 191 subAccountField.prop('disabled', true); 186 192 return; 187 193 } 188 194 195 const excludedSubAccountBanks = ['TPBank', 'VPBank', 'VietinBank']; 196 const requiredSubAccountBanks = ['BIDV', 'MSB', 'KienLongBank', 'OCB']; 197 198 if (excludedSubAccountBanks.includes(bankName)) { 199 subAccountField.html('<option value="">Ngân hàng ' + bankName + ' không hỗ trợ tài khoản VA</option>'); 200 subAccountField.prop('disabled', true); 201 return; 202 } 203 204 subAccountField.prop('disabled', false); 189 205 subAccountField.html(loadingMessage); 190 206 … … 198 214 success: function (response) { 199 215 let options = []; 200 options.push('<option value="">-- Chọn tài khoản ảo --</option>');201 216 if (response.success && response.data.length > 0) { 217 options.push('<option value="">-- Chọn tài khoản ảo --</option>'); 202 218 response.data.map(function (subAccount) { 203 219 options.push(`<option value="${subAccount.account_number}">${subAccount.account_number}${subAccount.label ? ` - ${subAccount.label}` : ''}</option>`); 204 220 }); 221 } else { 222 options.push('<option value="">Không có tài khoản VA nào</option>'); 205 223 } 206 224 subAccountField.html(options.join('')); 225 226 if (currentSubAccountValue && response.success && response.data.length > 0) { 227 const subAccountExists = response.data.some(function(subAccount) { 228 return subAccount.account_number === currentSubAccountValue; 229 }); 230 if (subAccountExists) { 231 subAccountField.val(currentSubAccountValue); 232 } 233 } 207 234 }, 208 235 error: function () { … … 220 247 } 221 248 249 if (bankAccountField.length && bankAccountField.val()) { 250 setTimeout(function() { 251 const savedSubAccountValue = subAccountField.val(); 252 bankAccountField.trigger('change'); 253 254 if (savedSubAccountValue) { 255 setTimeout(function() { 256 if (subAccountField.find(`option[value="${savedSubAccountValue}"]`).length) { 257 subAccountField.val(savedSubAccountValue); 258 } 259 }, 200); 260 } 261 }, 100); 262 } 263 222 264 function update_account_number_field_ui() { 223 265 const bank = jQuery('#woocommerce_sepay_bank_select').val() 224 225 if (['bidv', 'ocb', 'msb', 'kienlongbank'].includes(bank)) { 266 const excludedSubAccountBanks = ['tpbank', 'vpbank', 'vietinbank']; 267 const requiredSubAccountBanks = ['bidv', 'ocb', 'msb', 'kienlongbank']; 268 269 if (requiredSubAccountBanks.includes(bank) && !excludedSubAccountBanks.includes(bank)) { 226 270 jQuery('label[for=woocommerce_sepay_bank_account_number]').html('Số VA'); 227 271 jQuery('input[name=woocommerce_sepay_bank_account_number]').parent().find('.help-text').html('Vui lòng điền chính xác <strong>số VA</strong> để nhận được biến động giao dịch.') -
sepay-gateway/trunk/includes/class-wc-gateway-sepay.php
r3322376 r3325437 167 167 } 168 168 169 if ($this->api->is_required_sub_account($bank_account_id, $this->bank_accounts) && empty($sub_account)) { 170 WC_Admin_Settings::add_error('Ngân hàng đang chọn yêu cầu tài khoản VA. Vui lòng chọn tài khoản VA trước khi lưu.'); 171 return false; 169 $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank']; 170 $bank_account = array_filter($this->bank_accounts, function ($account) use ($bank_account_id) { 171 return $account['id'] == $bank_account_id; 172 }); 173 174 if (!empty($bank_account)) { 175 reset($bank_account); 176 $key = key($bank_account); 177 $bank_short_name = $bank_account[$key]['bank']['short_name']; 178 179 if (in_array($bank_short_name, $excluded_sub_account_banks) && !empty($sub_account)) { 180 WC_Admin_Settings::add_error('Ngân hàng ' . $bank_short_name . ' không hỗ trợ tài khoản VA. Vui lòng bỏ chọn tài khoản VA.'); 181 return false; 182 } 183 } 184 185 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 186 $bank_account = array_filter($this->bank_accounts, function ($account) use ($bank_account_id) { 187 return $account['id'] == $bank_account_id; 188 }); 189 190 if (!empty($bank_account)) { 191 reset($bank_account); 192 $key = key($bank_account); 193 $bank_short_name = $bank_account[$key]['bank']['short_name']; 194 195 if (in_array($bank_short_name, $required_sub_account_banks) && empty($sub_account)) { 196 WC_Admin_Settings::add_error('Ngân hàng ' . $bank_short_name . ' yêu cầu phải chọn tài khoản VA. Vui lòng chọn tài khoản VA trước khi lưu.'); 197 return false; 198 } 172 199 } 173 200 … … 265 292 $this->api->refresh_token(); 266 293 } catch (Exception $e) { 267 WC_Admin_Settings::add_error('Không thể làm mới token. Vui lòng thử lại sau.');268 294 $this->init_old_form_fields(); 269 295 return; … … 317 343 $sub_account_options = []; 318 344 319 $sub_accounts = $this->api->get_bank_sub_accounts($selected_bank_account); 320 321 $sub_account_options = [ 322 '' => '-- Chọn tài khoản ảo --', 323 ]; 324 325 if (! empty($sub_accounts)) { 326 foreach ($sub_accounts as $sub_account) { 327 $sub_account_options[$sub_account['account_number']] = $sub_account['account_number'] . ($sub_account['label'] ? " - {$sub_account['label']}" : ''); 345 $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank']; 346 $show_sub_account_field = true; 347 348 if (!empty($selected_bank_account)) { 349 $bank_account = array_filter($this->bank_accounts, function ($account) use ($selected_bank_account) { 350 return $account['id'] == $selected_bank_account; 351 }); 352 353 if (!empty($bank_account)) { 354 reset($bank_account); 355 $key = key($bank_account); 356 $bank_short_name = $bank_account[$key]['bank']['short_name']; 357 358 if (in_array($bank_short_name, $excluded_sub_account_banks)) { 359 $show_sub_account_field = false; 360 } 328 361 } 329 362 } 330 363 331 $form_fields['sub_account'] = [ 332 'title' => 'Tài khoản VA', 333 'type' => 'select', 334 'description' => 'Tài khoản ngân hàng bạn chọn yêu cầu chọn tài khoản VA để nhận thanh toán <br> (Lưu ý: Bạn không thể sử dụng tài khoản VA để nhận thanh toán đối với các ngân hàng TPBank, VPBank và VietinBank).', 335 'options' => $sub_account_options, 336 'class' => 'dynamic-sub-account', 337 'default' => '', 338 ]; 364 if ($show_sub_account_field) { 365 $sub_accounts = $this->api->get_bank_sub_accounts($selected_bank_account); 366 367 $sub_account_options = []; 368 369 if (! empty($sub_accounts)) { 370 $sub_account_options[''] = '-- Chọn tài khoản ảo --'; 371 foreach ($sub_accounts as $sub_account) { 372 $sub_account_options[$sub_account['account_number']] = $sub_account['account_number'] . ($sub_account['label'] ? " - {$sub_account['label']}" : ''); 373 } 374 } else { 375 $sub_account_options[''] = '-- Không có tài khoản VA nào --'; 376 } 377 378 $form_fields['sub_account'] = [ 379 'title' => 'Tài khoản VA', 380 'type' => 'select', 381 'description' => 'Chọn tài khoản VA để nhận thanh toán (nếu có). Một số ngân hàng yêu cầu phải chọn tài khoản VA. <br> (Lưu ý: TPBank, VPBank và VietinBank không hỗ trợ tài khoản VA).', 382 'options' => $sub_account_options, 383 'class' => 'dynamic-sub-account', 384 'default' => $this->get_option('sub_account'), 385 ]; 386 } else { 387 $form_fields['sub_account'] = [ 388 'title' => 'Tài khoản VA', 389 'type' => 'select', 390 'description' => 'Ngân hàng này không hỗ trợ tài khoản VA.', 391 'options' => [ 392 '' => '-- Không hỗ trợ tài khoản VA --', 393 ], 394 'class' => 'dynamic-sub-account', 395 'default' => '', 396 'custom_attributes' => [ 397 'disabled' => 'disabled', 398 ], 399 ]; 400 } 339 401 } 340 402 … … 616 678 $bank_account_id = $this->get_option('bank_account'); 617 679 $bank_account = $this->api->get_bank_account($bank_account_id); 618 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $bank_account['account_number']; 680 681 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 682 $bank_short_name = $this->cached_bank_account_data['bank']['short_name']; 683 684 if (in_array($bank_short_name, $required_sub_account_banks)) { 685 $account_number = $this->get_option('sub_account'); 686 if (empty($account_number)) { 687 $account_number = $bank_account['account_number']; 688 } 689 } else { 690 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $bank_account['account_number']; 691 } 692 619 693 $account_holder_name = $this->cached_bank_account_data['account_holder_name']; 620 694 $bank_bin = $this->cached_bank_account_data['bank']['bin']; … … 622 696 $displayed_bank_name = $this->displayed_bank_name; 623 697 } else { 624 $account_number = $this->get_option('bank_account_number'); 698 $bank_select = $this->get_option('bank_select'); 699 $bank_info = $this->get_bank_info($bank_select); 700 701 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $this->get_option('bank_account_number'); 625 702 $account_holder_name = $this->get_option('bank_account_holder'); 626 627 $bank_select = $this->get_option('bank_select');628 $bank_info = $this->get_bank_data()[$bank_select];629 703 630 704 if ($bank_info) { … … 670 744 671 745 if ($this->api->is_connected()) { 672 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : ($this->cached_bank_account_data['account_number'] ?? $this->get_option('bank_account_number')); 746 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 747 $bank_short_name = $this->cached_bank_account_data['bank']['short_name'] ?? ''; 748 749 if (in_array($bank_short_name, $required_sub_account_banks)) { 750 $account_number = $this->get_option('sub_account'); 751 if (empty($account_number)) { 752 $account_number = $this->cached_bank_account_data['account_number'] ?? $this->get_option('bank_account_number'); 753 } 754 } else { 755 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : ($this->cached_bank_account_data['account_number'] ?? $this->get_option('bank_account_number')); 756 } 673 757 } else { 674 $account_number = $this->get_option(' bank_account_number');758 $account_number = $this->get_option('sub_account') ? $this->get_option('sub_account') : $this->get_option('bank_account_number'); 675 759 } 676 760 … … 835 919 ); 836 920 } 921 922 private function get_bank_info($identifier) 923 { 924 $bank_data = $this->get_bank_data(); 925 926 if (isset($bank_data[$identifier])) { 927 return $bank_data[$identifier]; 928 } 929 930 foreach ($bank_data as $key => $bank) { 931 if ( 932 strtolower($bank['code']) === strtolower($identifier) || 933 $bank['bin'] === $identifier || 934 $bank['short_name'] === $identifier || 935 strtolower($bank['short_name']) === strtolower($identifier) 936 ) { 937 return $bank; 938 } 939 } 940 941 return null; 942 } 837 943 } -
sepay-gateway/trunk/includes/class-wc-sepay-api.php
r3322376 r3325437 349 349 } 350 350 351 public function create_webhook($bank_account_id, $webhook_id = null )352 { 353 if (!$this->is_connected()) { 354 return null; 355 } 356 357 $api_key = wp_generate_password(32, false);351 public function create_webhook($bank_account_id, $webhook_id = null, $api_key = null) 352 { 353 if (!$this->is_connected()) { 354 return null; 355 } 356 357 $api_key = $api_key ?: wp_generate_password(32, false); 358 358 359 359 $api_path = 'sepay-gateway/v2/add-payment'; … … 494 494 { 495 495 $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank']; 496 $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank']; 496 497 $bank_accounts = $bank_accounts ?? $this->get_bank_accounts(); 497 498 … … 506 507 reset($bank_account); 507 508 $key = key($bank_account); 508 509 return in_array($bank_account[$key]['bank']['short_name'], $required_sub_account_banks); 510 } 511 512 public function check_connection_health() 513 { 514 try { 515 $response = $this->make_request('me'); 516 if ($response && isset($response['data'])) { 517 return true; 518 } 509 $bank_short_name = $bank_account[$key]['bank']['short_name']; 510 511 if (in_array($bank_short_name, $excluded_sub_account_banks)) { 519 512 return false; 520 } catch (Exception $e) { 521 $this->log_error('Health check failed', [ 522 'error' => $e->getMessage() 523 ]); 524 return false; 525 } 526 } 527 528 public function get_connection_status() 529 { 530 $access_token = get_option('wc_sepay_access_token'); 531 $refresh_token = get_option('wc_sepay_refresh_token'); 532 $token_expires = get_option('wc_sepay_token_expires'); 533 $last_connected_at = get_option('wc_sepay_last_connected_at'); 534 535 $status = [ 536 'is_connected' => !empty($access_token) && !empty($refresh_token), 537 'token_expires_in' => $token_expires ? ($token_expires - time()) : 0, 538 'last_connected_at' => $last_connected_at, 539 'health_check' => $this->check_connection_health() 540 ]; 541 542 return $status; 513 } 514 515 return in_array($bank_short_name, $required_sub_account_banks); 543 516 } 544 517 -
sepay-gateway/trunk/readme.txt
r3322376 r3325437 4 4 - Tags: woocommerce, payment gateway, vietqr, ngan hang, thanh toan 5 5 - Requires WooCommerce at least: 2.1 6 - Stable Tag: 1.1.1 57 - Version: 1.1.1 56 - Stable Tag: 1.1.16 7 - Version: 1.1.16 8 8 - Tested up to: 6.6 9 9 - Requires at least: 5.6 … … 53 53 == CHANGELOG == 54 54 55 **Version 1.1.16** - 10/07/2025: 56 - [Fix lỗi] Sửa lỗi API key bị thay đổi khi kết nối lại OAuth2 57 - [Cải thiện] Tối ưu hóa hiển thị tài khoản VA cho các ngân hàng yêu cầu VA (BIDV, OCB, MSB, KienLongBank) 58 - [Cải thiện] Tự động lưu và khôi phục tài khoản VA đã chọn khi cấu hình 59 - [Fix lỗi] Sửa lỗi hiển thị tài khoản VA khi chuyển đổi giữa các ngân hàng 60 55 61 **Version 1.1.14** - 04/07/2025: 56 62 - [Cải thiện] Thêm User-Agent và thông tin phiên bản plugin vào header API requests để SePay có thể theo dõi và hỗ trợ tốt hơn -
sepay-gateway/trunk/sepay-gateway.php
r3322376 r3325437 6 6 * Author: SePay Team 7 7 * Author URI: https://sepay.vn/ 8 * Version: 1.1.1 58 * Version: 1.1.16 9 9 * Requires Plugins: woocommerce 10 10 * Text Domain: sepay-gateway … … 127 127 $webhook_id = isset($webhooks[0]['id']) ? $webhooks[0]['id'] : null; 128 128 129 $response = $api->create_webhook($bank_account_id, $webhook_id );129 $response = $api->create_webhook($bank_account_id, $webhook_id, $api_token); 130 130 131 131 if ($response['status'] !== 'success') { … … 263 263 $sepay_gateway = $payment_gateways->payment_gateways()['sepay']; 264 264 265 $webhook_api_key = $api->is_connected() ? get_option('wc_sepay_webhook_api_key') : $sepay_gateway->get_option('api_key');265 $webhook_api_key = get_option('wc_sepay_webhook_api_key') ? get_option('wc_sepay_webhook_api_key') : $sepay_gateway->get_option('api_key'); 266 266 267 267 if ($api_key !== $webhook_api_key) {
Note: See TracChangeset
for help on using the changeset viewer.