feat: add Airwallex payments and multi-currency support

This commit is contained in:
shaw
2026-05-11 11:17:26 +08:00
parent dbc8ae658c
commit b23055af5b
65 changed files with 3164 additions and 162 deletions
@@ -44,6 +44,13 @@ func TestValidateProviderRequest(t *testing.T) {
supportedTypes: "",
wantErr: false,
},
{
name: "valid airwallex provider",
providerKey: payment.TypeAirwallex,
providerName: "Airwallex Provider",
supportedTypes: payment.TypeAirwallex,
wantErr: false,
},
{
name: "valid alipay provider",
providerKey: "alipay",
@@ -120,6 +127,7 @@ func TestIsSensitiveProviderConfigField(t *testing.T) {
{"stripe", "webhookSecret", true},
{"stripe", "SecretKey", true}, // case-insensitive
{"stripe", "publishableKey", false},
{"stripe", "currency", false},
{"stripe", "appId", false},
// Alipay
@@ -142,6 +150,14 @@ func TestIsSensitiveProviderConfigField(t *testing.T) {
{"easypay", "pid", false},
{"easypay", "apiBase", false},
// Airwallex
{payment.TypeAirwallex, "apiKey", true},
{payment.TypeAirwallex, "webhookSecret", true},
{payment.TypeAirwallex, "clientId", false},
{payment.TypeAirwallex, "apiBase", false},
{payment.TypeAirwallex, "accountId", false},
{payment.TypeAirwallex, "currency", false},
// Unknown provider: never sensitive
{"unknown", "secretKey", false},
}
@@ -395,6 +411,42 @@ func TestUpdateProviderInstanceRejectsProtectedConfigChangesWhilePendingOrders(t
fieldName: "pid",
wantValue: "pid-test",
},
{
name: "stripe currency",
providerKey: payment.TypeStripe,
createConfig: validStripeProviderConfig,
supportedType: []string{payment.TypeStripe},
updateConfig: map[string]string{"currency": "HKD"},
fieldName: "currency",
wantValue: "CNY",
},
{
name: "airwallex accountId",
providerKey: payment.TypeAirwallex,
createConfig: validAirwallexProviderConfig,
supportedType: []string{payment.TypeAirwallex},
updateConfig: map[string]string{"accountId": "acct-updated"},
fieldName: "accountId",
wantValue: "acct-test",
},
{
name: "airwallex currency",
providerKey: payment.TypeAirwallex,
createConfig: validAirwallexProviderConfig,
supportedType: []string{payment.TypeAirwallex},
updateConfig: map[string]string{"currency": "HKD"},
fieldName: "currency",
wantValue: "CNY",
},
{
name: "airwallex webhookSecret",
providerKey: payment.TypeAirwallex,
createConfig: validAirwallexProviderConfig,
supportedType: []string{payment.TypeAirwallex},
updateConfig: map[string]string{"webhookSecret": "whsec-updated"},
fieldName: "webhookSecret",
wantValue: "whsec-test",
},
}
for _, tc := range tests {
@@ -506,6 +558,39 @@ func TestUpdateProviderInstanceAllowsSafeConfigChangesWhilePendingOrders(t *test
}
}
func TestUpdateProviderInstanceClearsAirwallexAccountID(t *testing.T) {
t.Parallel()
ctx := context.Background()
client := newPaymentConfigServiceTestClient(t)
svc := &PaymentConfigService{
entClient: client,
encryptionKey: []byte("0123456789abcdef0123456789abcdef"),
}
instance, err := svc.CreateProviderInstance(ctx, CreateProviderInstanceRequest{
ProviderKey: payment.TypeAirwallex,
Name: "airwallex-clear-account",
Config: validAirwallexProviderConfig(t),
SupportedTypes: []string{payment.TypeAirwallex},
Enabled: true,
})
require.NoError(t, err)
updated, err := svc.UpdateProviderInstance(ctx, instance.ID, UpdateProviderInstanceRequest{
Config: map[string]string{"accountId": ""},
})
require.NoError(t, err)
require.NotNil(t, updated)
saved, err := client.PaymentProviderInstance.Get(ctx, instance.ID)
require.NoError(t, err)
cfg, err := svc.decryptConfig(saved.Config)
require.NoError(t, err)
require.Empty(t, cfg["accountId"])
require.Equal(t, "client-id-test", cfg["clientId"])
}
func createPendingProviderConfigOrder(t *testing.T, ctx context.Context, client *dbent.Client, instance *dbent.PaymentProviderInstance) {
t.Helper()
@@ -545,11 +630,26 @@ func providerPendingOrderPaymentType(providerKey string) string {
return payment.TypeWxpay
case payment.TypeAlipay:
return payment.TypeAlipay
case payment.TypeAirwallex:
return payment.TypeAirwallex
case payment.TypeStripe:
return payment.TypeStripe
default:
return payment.TypeAlipay
}
}
func validStripeProviderConfig(t *testing.T) map[string]string {
t.Helper()
return map[string]string{
"secretKey": "sk_test_123",
"publishableKey": "pk_test_123",
"webhookSecret": "whsec-test",
"currency": "CNY",
}
}
func boolPtrValue(v bool) *bool {
return &v
}
@@ -577,6 +677,19 @@ func validEasyPayProviderConfig(t *testing.T) map[string]string {
}
}
func validAirwallexProviderConfig(t *testing.T) map[string]string {
t.Helper()
return map[string]string{
"clientId": "client-id-test",
"apiKey": "api-key-test",
"webhookSecret": "whsec-test",
"apiBase": "https://api-demo.airwallex.com/api/v1",
"accountId": "acct-test",
"currency": "CNY",
}
}
func validWxpayProviderConfig(t *testing.T) map[string]string {
t.Helper()