fix(payment): allow periods in EasyPay upstream types

This commit is contained in:
chihao.ou
2026-09-11 14:51:34 +08:00
parent 9c30951e4a
commit c3b3072a6f
7 changed files with 37 additions and 15 deletions
@@ -202,7 +202,7 @@ func TestEasyPayCustomMethodsUseConfiguredUpstreamType(t *testing.T) {
"notifyUrl": "https://example.com/notify",
"returnUrl": "https://example.com/return",
"paymentMode": paymentModePopup,
"customMethods": `[{"type":"ldc","upstreamType":"epay","displayName":"LDC"},{"type":"usdt_trc20","upstreamType":"usdt","displayName":"USDT-TRC20"}]`,
"customMethods": `[{"type":"ldc","upstreamType":"epay","displayName":"LDC"},{"type":"usdt_trc20","upstreamType":"usdt.trc20","displayName":"USDT-TRC20"}]`,
})
if err != nil {
t.Fatalf("NewEasyPay: %v", err)
@@ -221,8 +221,8 @@ func TestEasyPayCustomMethodsUseConfiguredUpstreamType(t *testing.T) {
if err != nil {
t.Fatalf("parse pay url: %v", err)
}
if got := payURL.Query().Get("type"); got != "usdt" {
t.Fatalf("pay url type = %q, want usdt (%s)", got, resp.PayURL)
if got := payURL.Query().Get("type"); got != "usdt.trc20" {
t.Fatalf("pay url type = %q, want usdt.trc20 (%s)", got, resp.PayURL)
}
}
@@ -224,6 +224,7 @@ func validateProviderRequest(providerKey, name, supportedTypes string) error {
}
var easyPayCustomMethodCodePattern = regexp.MustCompile(`^[a-z0-9_-]+$`)
var easyPayUpstreamMethodCodePattern = regexp.MustCompile(`^[a-z0-9_.-]+$`)
type easyPayCustomMethodConfig struct {
Type string `json:"type"`
@@ -253,8 +254,8 @@ func validateEasyPayCustomMethods(config map[string]string, supportedTypes strin
if !easyPayCustomMethodCodePattern.MatchString(method.Type) {
return infraerrors.BadRequest("VALIDATION_ERROR", "customMethods type may only contain lowercase letters, digits, underscores, and hyphens")
}
if !easyPayCustomMethodCodePattern.MatchString(method.UpstreamType) {
return infraerrors.BadRequest("VALIDATION_ERROR", "customMethods upstreamType may only contain lowercase letters, digits, underscores, and hyphens")
if !easyPayUpstreamMethodCodePattern.MatchString(method.UpstreamType) {
return infraerrors.BadRequest("VALIDATION_ERROR", "customMethods upstreamType may only contain lowercase letters, digits, periods, underscores, and hyphens")
}
if easyPayCustomMethodTypeConflictsWithBuiltin(method.Type) {
return infraerrors.BadRequest("VALIDATION_ERROR", "customMethods type cannot start with alipay or wxpay")
@@ -128,6 +128,23 @@ func TestValidateEasyPayCustomMethods(t *testing.T) {
config: map[string]string{"customMethods": `[{"type":"ldc","upstreamType":"epay","displayName":"LDC"}]`},
supportedTypes: "alipay,wxpay,ldc",
},
{
name: "upstream type allows periods",
config: map[string]string{"customMethods": `[{"type":"usdt_trc20","upstreamType":"usdt.trc20"}]`},
supportedTypes: "alipay,wxpay,usdt_trc20",
},
{
name: "custom type still rejects periods",
config: map[string]string{"customMethods": `[{"type":"usdt.trc20","upstreamType":"usdt.trc20"}]`},
supportedTypes: "alipay,wxpay,usdt.trc20",
wantErr: "customMethods type may only contain lowercase letters",
},
{
name: "upstream type still rejects slashes",
config: map[string]string{"customMethods": `[{"type":"usdt_trc20","upstreamType":"usdt/trc20"}]`},
supportedTypes: "alipay,wxpay,usdt_trc20",
wantErr: "customMethods upstreamType may only contain lowercase letters",
},
{
name: "malformed custom methods json",
config: map[string]string{"customMethods": `not-json`},
@@ -759,7 +759,7 @@ function validateEasyPayCustomMethods(): string | null {
if (!/^[a-z0-9_-]+$/.test(method.type)) {
return t('admin.settings.payment.validationEasyPayCustomMethodTypeInvalid')
}
if (!/^[a-z0-9_-]+$/.test(method.upstreamType)) {
if (!/^[a-z0-9_.-]+$/.test(method.upstreamType)) {
return t('admin.settings.payment.validationEasyPayCustomMethodUpstreamTypeInvalid')
}
if ((PROVIDER_SUPPORTED_TYPES.easypay || []).includes(method.type)) {
@@ -166,7 +166,7 @@ describe('PaymentProviderDialog payment guide', () => {
expect(payload.config.accountId).toBe('')
})
it('serializes EasyPay custom methods and adds them to supported_types', async () => {
it.each(['epay', 'usdt.trc20'])('serializes EasyPay upstream type %s and adds the local type to supported_types', async (upstreamType) => {
const provider = providerFactory({
provider_key: 'easypay',
name: 'EasyPay',
@@ -197,7 +197,7 @@ describe('PaymentProviderDialog payment guide', () => {
}
await ldcTypeInput.setValue('ldc')
await upstreamTypeInput.setValue('epay')
await upstreamTypeInput.setValue(upstreamType)
await displayNameInput.setValue('LDC')
await wrapper.find('form').trigger('submit.prevent')
@@ -205,11 +205,15 @@ describe('PaymentProviderDialog payment guide', () => {
config: Record<string, string>
supported_types: string[]
}
expect(payload.config.customMethods).toBe('[{"type":"ldc","upstreamType":"epay","displayName":"LDC"}]')
expect(JSON.parse(payload.config.customMethods)).toEqual([{ type: 'ldc', upstreamType, displayName: 'LDC' }])
expect(payload.supported_types).toEqual(['alipay', 'wxpay', 'ldc'])
})
it('rejects custom EasyPay method types with built-in payment prefixes', async () => {
it.each([
['alipay_hk', 'hkpay'],
['usdt.trc20', 'usdt.trc20'],
['usdt_trc20', 'usdt/trc20'],
])('rejects invalid EasyPay mapping %s to %s', async (type, upstreamType) => {
const provider = providerFactory({
provider_key: 'easypay',
name: 'EasyPay',
@@ -239,9 +243,9 @@ describe('PaymentProviderDialog payment guide', () => {
throw new Error('custom method inputs not found')
}
await typeInput.setValue('alipay_hk')
await upstreamTypeInput.setValue('hkpay')
await displayNameInput.setValue('Hong Kong Alipay')
await typeInput.setValue(type)
await upstreamTypeInput.setValue(upstreamType)
await displayNameInput.setValue('Custom payment')
await wrapper.find('form').trigger('submit.prevent')
expect(wrapper.emitted('save')).toBeUndefined()
@@ -759,7 +759,7 @@ export default {
validationFieldRequired: '{field} is required',
validationEasyPayCustomMethodRequired: 'Each custom EasyPay method requires both a payment type and an upstream type',
validationEasyPayCustomMethodTypeInvalid: 'Custom EasyPay payment types may only contain lowercase letters, digits, underscores, and hyphens',
validationEasyPayCustomMethodUpstreamTypeInvalid: 'EasyPay upstream types may only contain lowercase letters, digits, underscores, and hyphens',
validationEasyPayCustomMethodUpstreamTypeInvalid: 'EasyPay upstream types may only contain lowercase letters, digits, periods, underscores, and hyphens',
validationEasyPayCustomMethodReserved: 'Custom EasyPay payment types cannot use built-in alipay or wxpay',
validationEasyPayCustomMethodPrefixReserved: 'Custom EasyPay payment types cannot start with alipay or wxpay',
validationEasyPayCustomMethodDuplicate: 'Custom EasyPay payment types must be unique',
@@ -754,7 +754,7 @@ export default {
validationFieldRequired: '{field} 不能为空',
validationEasyPayCustomMethodRequired: '每个易支付自定义方式都必须填写支付方式和上游 type',
validationEasyPayCustomMethodTypeInvalid: '易支付自定义支付方式只能包含小写字母、数字、下划线和短横线',
validationEasyPayCustomMethodUpstreamTypeInvalid: '易支付上游 type 只能包含小写字母、数字、下划线和短横线',
validationEasyPayCustomMethodUpstreamTypeInvalid: '易支付上游 type 只能包含小写字母、数字、点号、下划线和短横线',
validationEasyPayCustomMethodReserved: '易支付自定义支付方式不能使用内置的 alipay 或 wxpay',
validationEasyPayCustomMethodPrefixReserved: '易支付自定义支付方式不能以 alipay 或 wxpay 开头',
validationEasyPayCustomMethodDuplicate: '易支付自定义支付方式不能重复',