[BugFix] fix webhook process (#5047)
This commit is contained in:
@@ -103,8 +103,9 @@ func SubscriptionRequestWaffoPancakePay(c *gin.Context) {
|
|||||||
Amount: decimal.NewFromFloat(plan.PriceAmount).StringFixed(2),
|
Amount: decimal.NewFromFloat(plan.PriceAmount).StringFixed(2),
|
||||||
TaxCategory: "saas",
|
TaxCategory: "saas",
|
||||||
},
|
},
|
||||||
BuyerEmail: getWaffoPancakeBuyerEmail(user),
|
BuyerEmail: getWaffoPancakeBuyerEmail(user),
|
||||||
ExpiresInSeconds: &expiresInSeconds,
|
ExpiresInSeconds: &expiresInSeconds,
|
||||||
|
OrderMerchantExternalID: tradeNo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogError(c.Request.Context(), fmt.Sprintf("Waffo Pancake 订阅结账会话创建失败 user_id=%d plan_id=%d trade_no=%s error=%q", userId, plan.Id, tradeNo, err.Error()))
|
logger.LogError(c.Request.Context(), fmt.Sprintf("Waffo Pancake 订阅结账会话创建失败 user_id=%d plan_id=%d trade_no=%s error=%q", userId, plan.Id, tradeNo, err.Error()))
|
||||||
|
|||||||
@@ -96,9 +96,6 @@ func getWaffoPancakeBuyerEmail(user *model.User) string {
|
|||||||
if user != nil && strings.TrimSpace(user.Email) != "" {
|
if user != nil && strings.TrimSpace(user.Email) != "" {
|
||||||
return user.Email
|
return user.Email
|
||||||
}
|
}
|
||||||
if user != nil {
|
|
||||||
return fmt.Sprintf("%d@new-api.local", user.Id)
|
|
||||||
}
|
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,8 +405,9 @@ func RequestWaffoPancakePay(c *gin.Context) {
|
|||||||
Amount: formatWaffoPancakeAmount(payMoney),
|
Amount: formatWaffoPancakeAmount(payMoney),
|
||||||
TaxCategory: "saas",
|
TaxCategory: "saas",
|
||||||
},
|
},
|
||||||
BuyerEmail: getWaffoPancakeBuyerEmail(user),
|
BuyerEmail: getWaffoPancakeBuyerEmail(user),
|
||||||
ExpiresInSeconds: &expiresInSeconds,
|
ExpiresInSeconds: &expiresInSeconds,
|
||||||
|
OrderMerchantExternalID: tradeNo,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.LogError(c.Request.Context(), fmt.Sprintf("Waffo Pancake 创建结账会话失败 user_id=%d trade_no=%s error=%q", id, tradeNo, err.Error()))
|
logger.LogError(c.Request.Context(), fmt.Sprintf("Waffo Pancake 创建结账会话失败 user_id=%d trade_no=%s error=%q", id, tradeNo, err.Error()))
|
||||||
@@ -485,9 +483,9 @@ func WaffoPancakeWebhook(c *gin.Context) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Subscription vs top-up dispatch by trade_no prefix (written at
|
// Dispatch by trade_no prefix. OrderMerchantExternalID = our trade_no;
|
||||||
// session-creation time): WAFFO_PANCAKE_SUB- vs WAFFO_PANCAKE-.
|
// OrderID is Pancake's internal ORD_* (logs only).
|
||||||
rawTradeNo := strings.TrimSpace(event.Data.OrderID)
|
rawTradeNo := strings.TrimSpace(event.Data.OrderMerchantExternalID)
|
||||||
isSubscription := strings.HasPrefix(rawTradeNo, "WAFFO_PANCAKE_SUB-")
|
isSubscription := strings.HasPrefix(rawTradeNo, "WAFFO_PANCAKE_SUB-")
|
||||||
|
|
||||||
if isSubscription {
|
if isSubscription {
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ require (
|
|||||||
gorm.io/gorm v1.25.2
|
gorm.io/gorm v1.25.2
|
||||||
)
|
)
|
||||||
|
|
||||||
require github.com/waffo-com/waffo-pancake-sdk-go v0.2.0
|
require github.com/waffo-com/waffo-pancake-sdk-go v0.3.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/DmitriyVTitov/size v1.5.0 // indirect
|
github.com/DmitriyVTitov/size v1.5.0 // indirect
|
||||||
|
|||||||
@@ -312,6 +312,8 @@ github.com/waffo-com/waffo-pancake-sdk-go v0.1.1 h1:YOI7+3zTBlTB7Ou6+ZXnJV2JvW/a
|
|||||||
github.com/waffo-com/waffo-pancake-sdk-go v0.1.1/go.mod h1:5MBCGH/nqRRA5sHO/lQB/96r4BTAqy8QpWxn53m9htI=
|
github.com/waffo-com/waffo-pancake-sdk-go v0.1.1/go.mod h1:5MBCGH/nqRRA5sHO/lQB/96r4BTAqy8QpWxn53m9htI=
|
||||||
github.com/waffo-com/waffo-pancake-sdk-go v0.2.0 h1:cCSgccM66p7feTtgRqUUGT50tYQOhahsoPXavd+ib1U=
|
github.com/waffo-com/waffo-pancake-sdk-go v0.2.0 h1:cCSgccM66p7feTtgRqUUGT50tYQOhahsoPXavd+ib1U=
|
||||||
github.com/waffo-com/waffo-pancake-sdk-go v0.2.0/go.mod h1:5MBCGH/nqRRA5sHO/lQB/96r4BTAqy8QpWxn53m9htI=
|
github.com/waffo-com/waffo-pancake-sdk-go v0.2.0/go.mod h1:5MBCGH/nqRRA5sHO/lQB/96r4BTAqy8QpWxn53m9htI=
|
||||||
|
github.com/waffo-com/waffo-pancake-sdk-go v0.3.1 h1:ngQSN/oVB35xTwFPLfg++bxPC+SptcF145Mb6c62YCc=
|
||||||
|
github.com/waffo-com/waffo-pancake-sdk-go v0.3.1/go.mod h1:OB2MyFIQaefoPO0FV3J+yu9sDP8RVFQ+sbFsXqGuObc=
|
||||||
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||||
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
|
||||||
|
|||||||
+27
-19
@@ -17,14 +17,15 @@ type WaffoPancakePriceSnapshot struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WaffoPancakeCreateSessionParams is the input to CreateWaffoPancakeCheckoutSession.
|
// WaffoPancakeCreateSessionParams is the input to CreateWaffoPancakeCheckoutSession.
|
||||||
// BuyerIdentity (merchant-controlled, stable per user) is what survives the
|
// BuyerIdentity must be stable per user (see WaffoPancakeBuyerIdentityFromUserID).
|
||||||
// buyer editing email at checkout — see WaffoPancakeBuyerIdentityFromUserID.
|
// OrderMerchantExternalID = our trade_no; Pancake echoes it back in webhooks.
|
||||||
type WaffoPancakeCreateSessionParams struct {
|
type WaffoPancakeCreateSessionParams struct {
|
||||||
ProductID string
|
ProductID string
|
||||||
BuyerIdentity string
|
BuyerIdentity string
|
||||||
PriceSnapshot *WaffoPancakePriceSnapshot
|
PriceSnapshot *WaffoPancakePriceSnapshot
|
||||||
BuyerEmail string
|
BuyerEmail string
|
||||||
ExpiresInSeconds *int
|
ExpiresInSeconds *int
|
||||||
|
OrderMerchantExternalID string
|
||||||
}
|
}
|
||||||
|
|
||||||
// WaffoPancakeCheckoutSession is the response of CreateWaffoPancakeCheckoutSession.
|
// WaffoPancakeCheckoutSession is the response of CreateWaffoPancakeCheckoutSession.
|
||||||
@@ -52,7 +53,9 @@ type WaffoPancakeWebhookEvent struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WaffoPancakeWebhookData struct {
|
type WaffoPancakeWebhookData struct {
|
||||||
|
// OrderID = Pancake ORD_* (logs); OrderMerchantExternalID = our trade_no (lookup).
|
||||||
OrderID string
|
OrderID string
|
||||||
|
OrderMerchantExternalID string
|
||||||
BuyerEmail string
|
BuyerEmail string
|
||||||
Currency string
|
Currency string
|
||||||
Amount string
|
Amount string
|
||||||
@@ -107,10 +110,11 @@ func CreateWaffoPancakeCheckoutSession(ctx context.Context, params *WaffoPancake
|
|||||||
|
|
||||||
sdkParams := pancake.AuthenticatedCheckoutParams{
|
sdkParams := pancake.AuthenticatedCheckoutParams{
|
||||||
CreateCheckoutSessionParams: pancake.CreateCheckoutSessionParams{
|
CreateCheckoutSessionParams: pancake.CreateCheckoutSessionParams{
|
||||||
ProductID: params.ProductID,
|
ProductID: params.ProductID,
|
||||||
Currency: "USD",
|
Currency: "USD",
|
||||||
BuyerEmail: optionalString(params.BuyerEmail),
|
BuyerEmail: optionalString(params.BuyerEmail),
|
||||||
ExpiresInSeconds: params.ExpiresInSeconds,
|
ExpiresInSeconds: params.ExpiresInSeconds,
|
||||||
|
OrderMerchantExternalID: optionalString(params.OrderMerchantExternalID),
|
||||||
},
|
},
|
||||||
BuyerIdentity: params.BuyerIdentity,
|
BuyerIdentity: params.BuyerIdentity,
|
||||||
}
|
}
|
||||||
@@ -163,6 +167,10 @@ func VerifyConfiguredWaffoPancakeWebhook(payload string, signatureHeader string)
|
|||||||
if evt.Data.MerchantProvidedBuyerIdentity != nil {
|
if evt.Data.MerchantProvidedBuyerIdentity != nil {
|
||||||
identity = *evt.Data.MerchantProvidedBuyerIdentity
|
identity = *evt.Data.MerchantProvidedBuyerIdentity
|
||||||
}
|
}
|
||||||
|
externalID := ""
|
||||||
|
if evt.Data.OrderMerchantExternalID != nil {
|
||||||
|
externalID = *evt.Data.OrderMerchantExternalID
|
||||||
|
}
|
||||||
return &WaffoPancakeWebhookEvent{
|
return &WaffoPancakeWebhookEvent{
|
||||||
ID: evt.ID,
|
ID: evt.ID,
|
||||||
Timestamp: evt.Timestamp,
|
Timestamp: evt.Timestamp,
|
||||||
@@ -172,6 +180,7 @@ func VerifyConfiguredWaffoPancakeWebhook(payload string, signatureHeader string)
|
|||||||
Mode: string(evt.Mode),
|
Mode: string(evt.Mode),
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: evt.Data.OrderID,
|
OrderID: evt.Data.OrderID,
|
||||||
|
OrderMerchantExternalID: externalID,
|
||||||
BuyerEmail: evt.Data.BuyerEmail,
|
BuyerEmail: evt.Data.BuyerEmail,
|
||||||
Currency: evt.Data.Currency,
|
Currency: evt.Data.Currency,
|
||||||
Amount: evt.Data.Amount,
|
Amount: evt.Data.Amount,
|
||||||
@@ -183,19 +192,18 @@ func VerifyConfiguredWaffoPancakeWebhook(payload string, signatureHeader string)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ResolveWaffoPancakeTradeNo maps a verified webhook event to a local TopUp
|
// ResolveWaffoPancakeTradeNo maps a verified webhook event to a local TopUp
|
||||||
// trade_no, rejecting any payload whose buyer identity doesn't match the one
|
// trade_no via OrderMerchantExternalID, and rejects buyer-identity mismatches.
|
||||||
// we recorded at checkout — defence-in-depth on top of signature verification.
|
|
||||||
func ResolveWaffoPancakeTradeNo(event *WaffoPancakeWebhookEvent) (string, error) {
|
func ResolveWaffoPancakeTradeNo(event *WaffoPancakeWebhookEvent) (string, error) {
|
||||||
if event == nil {
|
if event == nil {
|
||||||
return "", fmt.Errorf("missing webhook event")
|
return "", fmt.Errorf("missing webhook event")
|
||||||
}
|
}
|
||||||
tradeNo := strings.TrimSpace(event.Data.OrderID)
|
tradeNo := strings.TrimSpace(event.Data.OrderMerchantExternalID)
|
||||||
if tradeNo == "" {
|
if tradeNo == "" {
|
||||||
return "", fmt.Errorf("missing webhook orderId")
|
return "", fmt.Errorf("missing webhook orderMerchantExternalId")
|
||||||
}
|
}
|
||||||
topUp := model.GetTopUpByTradeNo(tradeNo)
|
topUp := model.GetTopUpByTradeNo(tradeNo)
|
||||||
if topUp == nil || topUp.PaymentProvider != model.PaymentProviderWaffoPancake {
|
if topUp == nil || topUp.PaymentProvider != model.PaymentProviderWaffoPancake {
|
||||||
return "", fmt.Errorf("waffo pancake order not found for webhook orderId=%s", tradeNo)
|
return "", fmt.Errorf("waffo pancake order not found for tradeNo=%s", tradeNo)
|
||||||
}
|
}
|
||||||
expectedIdentity := WaffoPancakeBuyerIdentityFromUserID(topUp.UserId)
|
expectedIdentity := WaffoPancakeBuyerIdentityFromUserID(topUp.UserId)
|
||||||
actualIdentity := strings.TrimSpace(event.Data.MerchantProvidedBuyerIdentity)
|
actualIdentity := strings.TrimSpace(event.Data.MerchantProvidedBuyerIdentity)
|
||||||
@@ -216,13 +224,13 @@ func ResolveWaffoPancakeSubscriptionTradeNo(event *WaffoPancakeWebhookEvent) (st
|
|||||||
if event == nil {
|
if event == nil {
|
||||||
return "", fmt.Errorf("missing webhook event")
|
return "", fmt.Errorf("missing webhook event")
|
||||||
}
|
}
|
||||||
tradeNo := strings.TrimSpace(event.Data.OrderID)
|
tradeNo := strings.TrimSpace(event.Data.OrderMerchantExternalID)
|
||||||
if tradeNo == "" {
|
if tradeNo == "" {
|
||||||
return "", fmt.Errorf("missing webhook orderId")
|
return "", fmt.Errorf("missing webhook orderMerchantExternalId")
|
||||||
}
|
}
|
||||||
order := model.GetSubscriptionOrderByTradeNo(tradeNo)
|
order := model.GetSubscriptionOrderByTradeNo(tradeNo)
|
||||||
if order == nil || order.PaymentProvider != model.PaymentProviderWaffoPancake {
|
if order == nil || order.PaymentProvider != model.PaymentProviderWaffoPancake {
|
||||||
return "", fmt.Errorf("waffo pancake subscription order not found for webhook orderId=%s", tradeNo)
|
return "", fmt.Errorf("waffo pancake subscription order not found for tradeNo=%s", tradeNo)
|
||||||
}
|
}
|
||||||
expectedIdentity := WaffoPancakeBuyerIdentityFromUserID(order.UserId)
|
expectedIdentity := WaffoPancakeBuyerIdentityFromUserID(order.UserId)
|
||||||
actualIdentity := strings.TrimSpace(event.Data.MerchantProvidedBuyerIdentity)
|
actualIdentity := strings.TrimSpace(event.Data.MerchantProvidedBuyerIdentity)
|
||||||
|
|||||||
@@ -57,7 +57,8 @@ func TestResolveWaffoPancakeTradeNo_UsesWebhookOrderIDWhenLocalOrderExists(t *te
|
|||||||
|
|
||||||
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "ORD_5dXBtmF2HLlHfbPNm0Wcnz",
|
OrderID: "ORD_internal_pancake_id",
|
||||||
|
OrderMerchantExternalID: "ORD_5dXBtmF2HLlHfbPNm0Wcnz",
|
||||||
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(topUp.UserId),
|
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(topUp.UserId),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -84,7 +85,8 @@ func TestResolveWaffoPancakeTradeNo_RejectsBuyerIdentityMismatch(t *testing.T) {
|
|||||||
// crossed-wires bug or a tampered payload. Either way: reject.
|
// crossed-wires bug or a tampered payload. Either way: reject.
|
||||||
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "ORD_identity_mismatch_case",
|
OrderID: "ORD_internal_pancake_id",
|
||||||
|
OrderMerchantExternalID: "ORD_identity_mismatch_case",
|
||||||
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(99), // wrong user
|
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(99), // wrong user
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -113,7 +115,8 @@ func TestResolveWaffoPancakeTradeNo_RejectsMissingBuyerIdentity(t *testing.T) {
|
|||||||
// reject so that we never credit anonymous orders to a specific user.
|
// reject so that we never credit anonymous orders to a specific user.
|
||||||
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "ORD_missing_identity",
|
OrderID: "ORD_internal_pancake_id",
|
||||||
|
OrderMerchantExternalID: "ORD_missing_identity",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@@ -146,9 +149,10 @@ func TestResolveWaffoPancakeTradeNo_FailsWhenWebhookOrderIDIsUnknown(t *testing.
|
|||||||
|
|
||||||
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "ORD_unknown",
|
OrderID: "ORD_internal_pancake_id",
|
||||||
BuyerEmail: user.Email,
|
OrderMerchantExternalID: "WAFFO_PANCAKE-unknown",
|
||||||
Amount: "29.00",
|
BuyerEmail: user.Email,
|
||||||
|
Amount: "29.00",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@@ -177,7 +181,8 @@ func TestResolveWaffoPancakeSubscriptionTradeNo_UsesWebhookOrderIDWhenLocalOrder
|
|||||||
|
|
||||||
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "WAFFO_PANCAKE_SUB-1-1700000000-abc123",
|
OrderID: "ORD_internal_pancake_id",
|
||||||
|
OrderMerchantExternalID: "WAFFO_PANCAKE_SUB-1-1700000000-abc123",
|
||||||
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(order.UserId),
|
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(order.UserId),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -202,7 +207,8 @@ func TestResolveWaffoPancakeSubscriptionTradeNo_RejectsBuyerIdentityMismatch(t *
|
|||||||
|
|
||||||
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "WAFFO_PANCAKE_SUB-42-mismatch",
|
OrderID: "ORD_internal_pancake_id",
|
||||||
|
OrderMerchantExternalID: "WAFFO_PANCAKE_SUB-42-mismatch",
|
||||||
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(99), // wrong user
|
MerchantProvidedBuyerIdentity: WaffoPancakeBuyerIdentityFromUserID(99), // wrong user
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -228,7 +234,7 @@ func TestResolveWaffoPancakeSubscriptionTradeNo_RejectsMissingBuyerIdentity(t *t
|
|||||||
|
|
||||||
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "WAFFO_PANCAKE_SUB-7-missing-identity",
|
OrderMerchantExternalID: "WAFFO_PANCAKE_SUB-7-missing-identity",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@@ -253,7 +259,7 @@ func TestResolveWaffoPancakeSubscriptionTradeNo_FailsWhenWebhookOrderIDIsUnknown
|
|||||||
|
|
||||||
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
tradeNo, err := ResolveWaffoPancakeSubscriptionTradeNo(&WaffoPancakeWebhookEvent{
|
||||||
Data: WaffoPancakeWebhookData{
|
Data: WaffoPancakeWebhookData{
|
||||||
OrderID: "WAFFO_PANCAKE_SUB-unknown",
|
OrderMerchantExternalID: "WAFFO_PANCAKE_SUB-unknown",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
|
|||||||
@@ -304,6 +304,13 @@ const PaymentSetting = () => {
|
|||||||
hideSectionTitle
|
hideSectionTitle
|
||||||
/>
|
/>
|
||||||
</Tabs.TabPane>
|
</Tabs.TabPane>
|
||||||
|
<Tabs.TabPane tab={t('Waffo Pancake 设置')} itemKey='waffo-pancake'>
|
||||||
|
<SettingsPaymentGatewayWaffoPancake
|
||||||
|
options={inputs}
|
||||||
|
refresh={onRefresh}
|
||||||
|
hideSectionTitle
|
||||||
|
/>
|
||||||
|
</Tabs.TabPane>
|
||||||
<Tabs.TabPane tab={t('Waffo 设置')} itemKey='waffo'>
|
<Tabs.TabPane tab={t('Waffo 设置')} itemKey='waffo'>
|
||||||
<SettingsPaymentGatewayWaffo
|
<SettingsPaymentGatewayWaffo
|
||||||
options={inputs}
|
options={inputs}
|
||||||
|
|||||||
Reference in New Issue
Block a user