Plugin Directory

Changeset 3325437


Ignore:
Timestamp:
07/10/2025 07:55:08 AM (9 months ago)
Author:
sepayteam
Message:

fix token refresh bug again for BIDV, OCB, MSB, KLB

Location:
sepay-gateway
Files:
5 deleted
7 edited
11 copied

Legend:

Unmodified
Added
Removed
  • sepay-gateway/tags/1.1.16/assets/css/sepay.css

    r3254400 r3325437  
    535535}
    536536
     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
    537563@media (max-width: 480px) {
    538564    .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  
    1515            loadingSpinner.show();
    1616           
    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);
    1820           
    1921            if (requiresSubAccount) {
     
    137139                if (response.success && response.data.length > 0) {
    138140                    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>`;
    140142                    });
    141143                }
     
    181183    bankAccountField.on('change', function () {
    182184        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();
    183188
    184189        if (!selectedBankAccountId) {
    185190            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);
    186192            return;
    187193        }
    188194
     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);
    189205        subAccountField.html(loadingMessage);
    190206
     
    198214            success: function (response) {
    199215                let options = [];
    200                 options.push('<option value="">-- Chọn tài khoản ảo --</option>');
    201216                if (response.success && response.data.length > 0) {
     217                    options.push('<option value="">-- Chọn tài khoản ảo --</option>');
    202218                    response.data.map(function (subAccount) {
    203219                        options.push(`<option value="${subAccount.account_number}">${subAccount.account_number}${subAccount.label ? ` - ${subAccount.label}` : ''}</option>`);
    204220                    });
     221                } else {
     222                    options.push('<option value="">Không có tài khoản VA nào</option>');
    205223                }
    206224                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                }
    207234            },
    208235            error: function () {
     
    220247    }
    221248
     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
    222264    function update_account_number_field_ui() {
    223265      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)) {
    226270          jQuery('label[for=woocommerce_sepay_bank_account_number]').html('Số VA');
    227271          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  
    167167        }
    168168
    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            }
    172199        }
    173200
     
    265292                $this->api->refresh_token();
    266293            } catch (Exception $e) {
    267                 WC_Admin_Settings::add_error('Không thể làm mới token. Vui lòng thử lại sau.');
    268294                $this->init_old_form_fields();
    269295                return;
     
    317343            $sub_account_options = [];
    318344
    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                    }
    328361                }
    329362            }
    330363
    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            }
    339401        }
    340402
     
    616678            $bank_account_id = $this->get_option('bank_account');
    617679            $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
    619693            $account_holder_name = $this->cached_bank_account_data['account_holder_name'];
    620694            $bank_bin = $this->cached_bank_account_data['bank']['bin'];
     
    622696            $displayed_bank_name = $this->displayed_bank_name;
    623697        } 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');
    625702            $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];
    629703
    630704            if ($bank_info) {
     
    670744
    671745        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            }
    673757        } 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');
    675759        }
    676760
     
    835919        );
    836920    }
     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    }
    837943}
  • sepay-gateway/tags/1.1.16/includes/class-wc-sepay-api.php

    r3322376 r3325437  
    349349    }
    350350
    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);
    358358
    359359        $api_path = 'sepay-gateway/v2/add-payment';
     
    494494    {
    495495        $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank'];
     496        $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank'];
    496497        $bank_accounts = $bank_accounts ?? $this->get_bank_accounts();
    497498
     
    506507        reset($bank_account);
    507508        $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)) {
    519512            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);
    543516    }
    544517
  • sepay-gateway/tags/1.1.16/readme.txt

    r3322376 r3325437  
    44 - Tags: woocommerce, payment gateway, vietqr, ngan hang, thanh toan
    55 - Requires WooCommerce at least: 2.1
    6  - Stable Tag: 1.1.15
    7  - Version: 1.1.15
     6 - Stable Tag: 1.1.16
     7 - Version: 1.1.16
    88 - Tested up to: 6.6
    99 - Requires at least: 5.6
     
    5353== CHANGELOG ==
    5454
     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
    5561**Version 1.1.14** - 04/07/2025:
    5662- [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  
    66 * Author: SePay Team
    77 * Author URI: https://sepay.vn/
    8  * Version: 1.1.15
     8 * Version: 1.1.16
    99 * Requires Plugins: woocommerce
    1010 * Text Domain: sepay-gateway
     
    127127        $webhook_id = isset($webhooks[0]['id']) ? $webhooks[0]['id'] : null;
    128128
    129         $response = $api->create_webhook($bank_account_id, $webhook_id);
     129        $response = $api->create_webhook($bank_account_id, $webhook_id, $api_token);
    130130
    131131        if ($response['status'] !== 'success') {
     
    263263        $sepay_gateway = $payment_gateways->payment_gateways()['sepay'];
    264264
    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');
    266266
    267267        if ($api_key !== $webhook_api_key) {
  • sepay-gateway/trunk/assets/css/sepay.css

    r3254400 r3325437  
    535535}
    536536
     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
    537563@media (max-width: 480px) {
    538564    .sepay-pay-info .manual-box .bank-info .bank-info-value span:first-child {
  • sepay-gateway/trunk/assets/js/main.js

    r3253697 r3325437  
    1515            loadingSpinner.show();
    1616           
    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);
    1820           
    1921            if (requiresSubAccount) {
     
    137139                if (response.success && response.data.length > 0) {
    138140                    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>`;
    140142                    });
    141143                }
     
    181183    bankAccountField.on('change', function () {
    182184        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();
    183188
    184189        if (!selectedBankAccountId) {
    185190            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);
    186192            return;
    187193        }
    188194
     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);
    189205        subAccountField.html(loadingMessage);
    190206
     
    198214            success: function (response) {
    199215                let options = [];
    200                 options.push('<option value="">-- Chọn tài khoản ảo --</option>');
    201216                if (response.success && response.data.length > 0) {
     217                    options.push('<option value="">-- Chọn tài khoản ảo --</option>');
    202218                    response.data.map(function (subAccount) {
    203219                        options.push(`<option value="${subAccount.account_number}">${subAccount.account_number}${subAccount.label ? ` - ${subAccount.label}` : ''}</option>`);
    204220                    });
     221                } else {
     222                    options.push('<option value="">Không có tài khoản VA nào</option>');
    205223                }
    206224                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                }
    207234            },
    208235            error: function () {
     
    220247    }
    221248
     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
    222264    function update_account_number_field_ui() {
    223265      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)) {
    226270          jQuery('label[for=woocommerce_sepay_bank_account_number]').html('Số VA');
    227271          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  
    167167        }
    168168
    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            }
    172199        }
    173200
     
    265292                $this->api->refresh_token();
    266293            } catch (Exception $e) {
    267                 WC_Admin_Settings::add_error('Không thể làm mới token. Vui lòng thử lại sau.');
    268294                $this->init_old_form_fields();
    269295                return;
     
    317343            $sub_account_options = [];
    318344
    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                    }
    328361                }
    329362            }
    330363
    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            }
    339401        }
    340402
     
    616678            $bank_account_id = $this->get_option('bank_account');
    617679            $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
    619693            $account_holder_name = $this->cached_bank_account_data['account_holder_name'];
    620694            $bank_bin = $this->cached_bank_account_data['bank']['bin'];
     
    622696            $displayed_bank_name = $this->displayed_bank_name;
    623697        } 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');
    625702            $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];
    629703
    630704            if ($bank_info) {
     
    670744
    671745        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            }
    673757        } 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');
    675759        }
    676760
     
    835919        );
    836920    }
     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    }
    837943}
  • sepay-gateway/trunk/includes/class-wc-sepay-api.php

    r3322376 r3325437  
    349349    }
    350350
    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);
    358358
    359359        $api_path = 'sepay-gateway/v2/add-payment';
     
    494494    {
    495495        $required_sub_account_banks = ['BIDV', 'OCB', 'MSB', 'KienLongBank'];
     496        $excluded_sub_account_banks = ['TPBank', 'VPBank', 'VietinBank'];
    496497        $bank_accounts = $bank_accounts ?? $this->get_bank_accounts();
    497498
     
    506507        reset($bank_account);
    507508        $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)) {
    519512            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);
    543516    }
    544517
  • sepay-gateway/trunk/readme.txt

    r3322376 r3325437  
    44 - Tags: woocommerce, payment gateway, vietqr, ngan hang, thanh toan
    55 - Requires WooCommerce at least: 2.1
    6  - Stable Tag: 1.1.15
    7  - Version: 1.1.15
     6 - Stable Tag: 1.1.16
     7 - Version: 1.1.16
    88 - Tested up to: 6.6
    99 - Requires at least: 5.6
     
    5353== CHANGELOG ==
    5454
     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
    5561**Version 1.1.14** - 04/07/2025:
    5662- [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  
    66 * Author: SePay Team
    77 * Author URI: https://sepay.vn/
    8  * Version: 1.1.15
     8 * Version: 1.1.16
    99 * Requires Plugins: woocommerce
    1010 * Text Domain: sepay-gateway
     
    127127        $webhook_id = isset($webhooks[0]['id']) ? $webhooks[0]['id'] : null;
    128128
    129         $response = $api->create_webhook($bank_account_id, $webhook_id);
     129        $response = $api->create_webhook($bank_account_id, $webhook_id, $api_token);
    130130
    131131        if ($response['status'] !== 'success') {
     
    263263        $sepay_gateway = $payment_gateways->payment_gateways()['sepay'];
    264264
    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');
    266266
    267267        if ($api_key !== $webhook_api_key) {
Note: See TracChangeset for help on using the changeset viewer.