diff --git a/src/model/service/okpay_service.go b/src/model/service/okpay_service.go index 77efa1c..4d4b910 100644 --- a/src/model/service/okpay_service.go +++ b/src/model/service/okpay_service.go @@ -268,10 +268,14 @@ func HandleOkPayNotify(form map[string]string, rawFormData string) error { TradeId: order.TradeId, BlockTransactionId: payload.OrderID, }) + processed := err == nil if err != nil && err != constant.OrderBlockAlreadyProcess { return err } + if processed { + sendPaymentNotification(order) + } if err = data.MarkProviderOrderPaid(payload.UniqueID, order.PayProvider, payload.RawFormData); err != nil { return err } diff --git a/src/model/service/okpay_service_test.go b/src/model/service/okpay_service_test.go new file mode 100644 index 0000000..cb9258e --- /dev/null +++ b/src/model/service/okpay_service_test.go @@ -0,0 +1,120 @@ +package service + +import ( + "strings" + "testing" + "time" + + "github.com/GMWalletApp/epusdt/internal/testutil" + "github.com/GMWalletApp/epusdt/model/dao" + "github.com/GMWalletApp/epusdt/model/data" + "github.com/GMWalletApp/epusdt/model/mdb" + "github.com/GMWalletApp/epusdt/notify" +) + +func TestHandleOkPayNotifySendsPaymentNotificationOnSuccess(t *testing.T) { + cleanup := testutil.SetupTestDatabases(t) + defer cleanup() + + const ( + channelType = "test-okpay-pay-success" + shopID = "okpay-shop-notify" + shopToken = "okpay-shop-token" + tradeID = "okpay-notify-success-001" + orderID = "merchant-okpay-notify-success-001" + providerOrderID = "okpay-provider-success-001" + rawFormData = "raw-okpay-form" + ) + + got := make(chan string, 1) + notify.RegisterSender(channelType, func(config, text string) error { + got <- text + return nil + }) + + if err := dao.Mdb.Create(&mdb.NotificationChannel{ + Type: channelType, + Name: "test okpay pay success", + Config: "{}", + Events: `{"pay_success":true}`, + Enabled: true, + }).Error; err != nil { + t.Fatalf("seed notification channel: %v", err) + } + if err := data.SetSetting(mdb.SettingGroupOkPay, mdb.SettingKeyOkPayShopID, shopID, mdb.SettingTypeString); err != nil { + t.Fatalf("seed okpay shop id: %v", err) + } + if err := data.SetSetting(mdb.SettingGroupOkPay, mdb.SettingKeyOkPayShopToken, shopToken, mdb.SettingTypeString); err != nil { + t.Fatalf("seed okpay shop token: %v", err) + } + + order := &mdb.Orders{ + TradeId: tradeID, + OrderId: orderID, + Amount: 1, + Currency: "CNY", + ActualAmount: 0.15, + ReceiveAddress: "OKPAY", + Token: "USDT", + Network: mdb.NetworkTron, + Status: mdb.StatusWaitPay, + PaymentType: mdb.PaymentTypeEpay, + PayProvider: mdb.PaymentProviderOkPay, + } + if err := dao.Mdb.Create(order).Error; err != nil { + t.Fatalf("seed order: %v", err) + } + if err := dao.Mdb.Create(&mdb.ProviderOrder{ + TradeId: tradeID, + Provider: mdb.PaymentProviderOkPay, + ProviderOrderID: providerOrderID, + Amount: 0.15, + Coin: "USDT", + Status: mdb.ProviderOrderStatusPending, + }).Error; err != nil { + t.Fatalf("seed provider order: %v", err) + } + + form := okPayNotifyTestForm(shopID, shopToken, providerOrderID, tradeID, "0.15000000", "USDT") + if err := HandleOkPayNotify(form, rawFormData); err != nil { + t.Fatalf("handle okpay notify: %v", err) + } + + select { + case text := <-got: + if !strings.Contains(text, tradeID) { + t.Fatalf("notification text = %q, want trade id %s", text, tradeID) + } + if !strings.Contains(text, orderID) { + t.Fatalf("notification text = %q, want order id %s", text, orderID) + } + case <-time.After(2 * time.Second): + t.Fatal("timed out waiting for payment notification") + } + + if err := HandleOkPayNotify(form, rawFormData); err != nil { + t.Fatalf("handle duplicate okpay notify: %v", err) + } + select { + case text := <-got: + t.Fatalf("duplicate notification sent: %q", text) + case <-time.After(200 * time.Millisecond): + } +} + +func okPayNotifyTestForm(shopID, shopToken, providerOrderID, tradeID, amount, coin string) map[string]string { + form := map[string]string{ + "code": "200", + "id": shopID, + "status": "success", + "data[order_id]": providerOrderID, + "data[unique_id]": tradeID, + "data[pay_user_id]": "123456789", + "data[amount]": amount, + "data[coin]": coin, + "data[status]": "1", + "data[type]": "deposit", + } + form["sign"] = okPayNotifySign(form, shopToken) + return form +}