fix(payment): 结算货币旧小写值导致枚举校验失败无法保存

paypal_currency/stripe_currency 由自由文本改为 select 后,旧存储值(如
stripe_currency=usd 小写)不通过枚举校验,收款接口页保存被 422 拦截。
为两个货币字段增加 case_insensitive 归一化:读取时归一为选项规范写法、
写入时归一化、校验时大小写不敏感放行,匹配不到回退默认 USD。
This commit is contained in:
2026-09-16 19:56:51 +08:00
parent 14f9534651
commit ff11f3b156
3 changed files with 41 additions and 6 deletions
+37 -2
View File
@@ -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'] ?? []));
}