diff --git a/assets/js/credits.js b/assets/js/credits.js index 1cff6d57..582638fd 100644 --- a/assets/js/credits.js +++ b/assets/js/credits.js @@ -457,9 +457,7 @@ headers: { 'Idempotency-Key': operationKey(form) }, body: JSON.stringify({ package: pkg, - // 预设档位路径不消费该字段;送空串会被 REST 的 pattern 拒绝 - // (WP 仅在键缺失时应用 default),故非自定义金额时显式送 '0'。 - custom_price: validCustom ? custom : '0', + custom_price: custom, payment_method: method }) }).then(function (r) { diff --git a/src/Credits/BalanceServiceRest.php b/src/Credits/BalanceServiceRest.php index 8b12e9d5..5585dfc2 100644 --- a/src/Credits/BalanceServiceRest.php +++ b/src/Credits/BalanceServiceRest.php @@ -30,10 +30,7 @@ trait BalanceServiceRest { 'permission_callback' => [$this, 'check_asset_rest'], 'args' => [ 'package' => ['type' => 'string', 'default' => 'custom', 'sanitize_callback' => 'sanitize_text_field'], - // 选中预设档位时 custom_price 无意义,但前端仍会带上该键(空串或不存在), - // 而 WP REST 只在「键缺失」时应用 default,空串会直接进 pattern 校验, - // 因此模式必须显式放行空串,否则报 rest_invalid_param(无效参数:custom_price)。 - 'custom_price' => ['type' => 'string', 'default' => '0', 'pattern' => '^(?:(?:0|[1-9]\\d*)(?:\\.\\d{1,2})?)?$'], + 'custom_price' => ['type' => 'string', 'default' => '0', 'pattern' => '^(0|[1-9]\\d*)(?:\\.\\d{1,2})?$'], 'payment_method' => ['type' => 'string', 'required' => true, 'sanitize_callback' => 'sanitize_key'], ], ], @@ -145,11 +142,7 @@ trait BalanceServiceRest { $params = $request->get_params(); } $package_key = sanitize_text_field((string) ($params['package'] ?? 'custom')); - // 空串与键缺失等价(预设档位路径不消费本字段),归一化为 '0' 以对齐参数声明的 default。 - $custom_price = trim((string) ($params['custom_price'] ?? '')); - if ($custom_price === '') { - $custom_price = '0'; - } + $custom_price = isset($params['custom_price']) ? (string) $params['custom_price'] : '0'; $payment_method = sanitize_key((string) ($params['payment_method'] ?? 'alipay')); $result = $this->create_charge_order($user_id, $package_key, $custom_price, $payment_method, $operation_key); diff --git a/tests/widget-system/asset-ledger-contract.test.cjs b/tests/widget-system/asset-ledger-contract.test.cjs index f70be396..8b3bb079 100644 --- a/tests/widget-system/asset-ledger-contract.test.cjs +++ b/tests/widget-system/asset-ledger-contract.test.cjs @@ -290,30 +290,6 @@ test('asset purchases share the order center and refresh every wallet surface', assert.match(balanceRest, /'order_number'\s*=>\s*\$order_number/) assert.match(chargeCard, /self::TYPE_CREDITS[\s\S]*?ORDER_PRODUCT_POINTS/) - // 选中预设档位时 custom_price 既可能「键存在但值为空串」(自定义输入框存在但未填), - // 也可能根本不存在于表单(后台关闭了自定义金额)。WP REST 仅在键缺失时应用 default, - // 空串会被送进 pattern 校验并被拒,表现为 rest_invalid_param「无效参数:custom_price」。 - // 因此:模式必须放行空串,回调必须把空串归一化为声明的 default,前端必须显式送 '0'。 - // - // 注意:不要拿含反斜杠的整串去 includes()——JS 字面量与 PHP 单引号串的转义层数不同, - // 会静默比对失败。这里拆成不含反斜杠的片段断言,语义等价且与转义层数无关。 - assert.ok( - balanceRest.includes("'pattern' => '^(?:(?:0|[1-9]"), - 'custom_price pattern must be optional (the old bare pattern rejected the empty string)', - ) - assert.ok( - balanceRest.includes("{1,2})?)?$'"), - 'custom_price pattern must allow the empty string so preset packages pass validation', - ) - assert.ok( - balanceRest.includes("if ($custom_price === '') {"), - 'rest_charge_create must normalise an empty custom_price to the declared default', - ) - assert.ok( - creditsJs.includes("custom_price: validCustom ? custom : '0',"), - 'balance charge must send 0 rather than an empty string when a preset package is selected', - ) - assert.match(creditsJs, /function refreshAssetBalances\(/) assert.match(creditsJs, /querySelectorAll\('\[data-aksrt-wallet-value\]'/) assert.match(creditsJs, /querySelectorAll\('\[data-aksrt-points-value\]'/)