fix(payment): 结算货币旧小写值导致枚举校验失败无法保存
paypal_currency/stripe_currency 由自由文本改为 select 后,旧存储值(如 stripe_currency=usd 小写)不通过枚举校验,收款接口页保存被 422 拦截。 为两个货币字段增加 case_insensitive 归一化:读取时归一为选项规范写法、 写入时归一化、校验时大小写不敏感放行,匹配不到回退默认 USD。
This commit is contained in:
@@ -282,7 +282,7 @@ export const gatewaySchema = {
|
||||
},
|
||||
{ key: 'paypal_client_id', label: 'Client ID', type: 'input', default: '' },
|
||||
{ key: 'paypal_client_secret', label: 'Client Secret', type: 'input', default: '' },
|
||||
{ key: 'paypal_currency', label: '结算货币', type: 'select', default: 'USD', options: currencyOptions },
|
||||
{ key: 'paypal_currency', label: '结算货币', type: 'select', case_insensitive: true, default: 'USD', options: currencyOptions },
|
||||
{ key: 'paypal_rates', label: '货币汇率', type: 'input', default: '0.14', help: '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137' },
|
||||
{ key: 'paypal_sandbox', label: '沙盒调试模式', type: 'switch', default: false, help: '沙箱模式(Sandbox)是PayPal支付的测试环境。开启后请使用沙箱环境生成的收款账户和付款账户进行测试。' },
|
||||
],
|
||||
@@ -306,7 +306,7 @@ export const gatewaySchema = {
|
||||
{ key: 'stripe_secret_key', label: '私钥Secret Key', type: 'input', default: '', help: 'Stripe Dashboard → Developers → API keys → Secret key' },
|
||||
{ key: 'stripe_publishable_key', label: 'Publishable Key', type: 'input', default: '' },
|
||||
{ key: 'stripe_webhook_secret', label: '签名密钥Webhook Secret', type: 'input', default: '', help: 'Developers → Webhooks → 端点 → Signing secret(whsec_ 开头)' },
|
||||
{ key: 'stripe_currency', label: '结算货币', type: 'select', default: 'USD', options: currencyOptions },
|
||||
{ key: 'stripe_currency', label: '结算货币', type: 'select', case_insensitive: true, default: 'USD', options: currencyOptions },
|
||||
{ key: 'stripe_rates', label: '货币汇率', type: 'input', default: '0.14', help: '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137' },
|
||||
{ key: 'stripe_test_mode', label: '测试模式', type: 'switch', default: false, help: '如果使用的测试开放模式,则请使用 sk_test_ 测试密钥与 Stripe 测试卡进行配置' },
|
||||
],
|
||||
|
||||
@@ -469,7 +469,7 @@ class SchemaPayment {
|
||||
['key' => 'paypal_notice', 'label' => '', 'type' => 'content', 'ui_only' => true, 'content' => '<ul style="margin:0 0 0 18px;line-height:1.9"><li>PayPal(贝宝)是常见的海外支付接口</li><li>如果您的收款账户为中国大陆地区,则账户类型必须是企业,且只能收取非中国大陆区的PayPal付款</li><li>REST 应用申请:https://developer.paypal.com/dashboard/applications</li></ul>'],
|
||||
['key' => 'paypal_client_id', 'label' => 'Client ID', 'type' => 'input', 'default' => ''],
|
||||
['key' => 'paypal_client_secret', 'label' => 'Client Secret', 'type' => 'input', 'default' => ''],
|
||||
['key' => 'paypal_currency', 'label' => '结算货币', 'type' => 'select', 'default' => 'USD', 'options' => self::currency_options()],
|
||||
['key' => 'paypal_currency', 'label' => '结算货币', 'type' => 'select', 'case_insensitive' => true, 'default' => 'USD', 'options' => self::currency_options()],
|
||||
['key' => 'paypal_rates', 'label' => '货币汇率', 'type' => 'input', 'default' => '0.14', 'help' => '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137'],
|
||||
['key' => 'paypal_sandbox', 'label' => '沙盒调试模式', 'type' => 'switch', 'default' => false, 'help' => '沙箱模式(Sandbox)是PayPal支付的测试环境。开启后请使用沙箱环境生成的收款账户和付款账户进行测试。'],
|
||||
]],
|
||||
@@ -478,7 +478,7 @@ class SchemaPayment {
|
||||
['key' => 'stripe_secret_key', 'label' => '私钥Secret Key', 'type' => 'input', 'default' => '', 'help' => 'Stripe Dashboard → Developers → API keys → Secret key'],
|
||||
['key' => 'stripe_publishable_key', 'label' => 'Publishable Key', 'type' => 'input', 'default' => ''],
|
||||
['key' => 'stripe_webhook_secret', 'label' => '签名密钥Webhook Secret', 'type' => 'input', 'default' => '', 'help' => 'Developers → Webhooks → 端点 → Signing secret(whsec_ 开头)'],
|
||||
['key' => 'stripe_currency', 'label' => '结算货币', 'type' => 'select', 'default' => 'USD', 'options' => self::currency_options()],
|
||||
['key' => 'stripe_currency', 'label' => '结算货币', 'type' => 'select', 'case_insensitive' => true, 'default' => 'USD', 'options' => self::currency_options()],
|
||||
['key' => 'stripe_rates', 'label' => '货币汇率', 'type' => 'input', 'default' => '0.14', 'help' => '根据你选择的货币类型与您定价货币的汇率进行填写,例如1元人民币兑换0.137美元(USD),则此处填0.137'],
|
||||
['key' => 'stripe_test_mode', 'label' => '测试模式', 'type' => 'switch', 'default' => false, 'help' => '如果使用的测试开放模式,则请使用 sk_test_ 测试密钥与 Stripe 测试卡进行配置'],
|
||||
]],
|
||||
|
||||
@@ -237,12 +237,14 @@ class SchemaProvider {
|
||||
// (legacy / SPA may still use type=select multiple).
|
||||
if (!empty($field['multiple']) && is_array($value)) {
|
||||
foreach ($value as $item) {
|
||||
if (!in_array($item, $valid_values, true)) {
|
||||
if (!in_array($item, $valid_values, true)
|
||||
&& (empty($field['case_insensitive']) || $this->normalize_case_insensitive_option($item, (array) $field['options']) === null)) {
|
||||
$errors[] = sprintf('%s has an invalid value', $field['label'] ?? $key);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} elseif (!in_array($value, $valid_values, true)) {
|
||||
} elseif (!in_array($value, $valid_values, true)
|
||||
&& (empty($field['case_insensitive']) || $this->normalize_case_insensitive_option($value, (array) $field['options']) === null)) {
|
||||
$errors[] = sprintf('%s has an invalid value', $field['label'] ?? $key);
|
||||
}
|
||||
}
|
||||
@@ -545,6 +547,12 @@ class SchemaProvider {
|
||||
if ($has_stored) {
|
||||
$data[$field['key']] = $stored[$field['key']];
|
||||
}
|
||||
// 大小写不敏感字段:存储值归一化为选项规范写法;匹配不到回退默认,
|
||||
// 避免旧自由文本值(如小写货币代码)导致枚举校验失败。
|
||||
if (!empty($field['case_insensitive']) && in_array($field_type, ['select', 'radio'], true) && !empty($field['options'])) {
|
||||
$normalized = $this->normalize_case_insensitive_option($data[$field['key']] ?? '', (array) $field['options']);
|
||||
$data[$field['key']] = $normalized !== null ? $normalized : ($field['default'] ?? ($data[$field['key']] ?? ''));
|
||||
}
|
||||
if (($field['sanitize_type'] ?? '') === 'money_decimal' && array_key_exists($field['key'], $data)) {
|
||||
$normalized = $this->normalize_money_decimal($data[$field['key']]);
|
||||
if ($normalized !== '') {
|
||||
@@ -855,6 +863,27 @@ class SchemaProvider {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 对大小写不敏感字段(case_insensitive),把值归一化为选项中的规范写法;
|
||||
* 匹配不到返回 null。
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param array<int,mixed> $options
|
||||
*/
|
||||
private function normalize_case_insensitive_option($value, array $options): ?string {
|
||||
if (!is_string($value) || $value === '') {
|
||||
return null;
|
||||
}
|
||||
$lower = strtolower(trim($value));
|
||||
foreach ($options as $opt) {
|
||||
$opt_value = is_array($opt) ? ($opt['value'] ?? null) : $opt;
|
||||
if (is_string($opt_value) && strtolower($opt_value) === $lower) {
|
||||
return $opt_value;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private function sanitize_field_value($value, array $field) {
|
||||
if (!empty($field['captcha_provider'])) {
|
||||
return function_exists('aksrt_captcha_sanitize_provider_config')
|
||||
@@ -874,6 +903,12 @@ class SchemaProvider {
|
||||
return $this->sanitize_value($value, 'attachment_ids');
|
||||
}
|
||||
|
||||
if (in_array($type, ['select', 'radio'], true) && !empty($field['case_insensitive']) && !empty($field['options'])) {
|
||||
// 旧自由文本值(如小写货币代码)归一化为选项规范写法。
|
||||
$normalized = $this->normalize_case_insensitive_option($value, (array) $field['options']);
|
||||
return $normalized !== null ? $normalized : (string) ($field['default'] ?? '');
|
||||
}
|
||||
|
||||
if (in_array($type, ['fieldset', 'accordion'], true)) {
|
||||
return $this->sanitize_object_fields($value, (array) ($field['fields'] ?? []));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user