diff --git a/src/model/service/task_service.go b/src/model/service/task_service.go
index 8e6c0d2..85498bc 100644
--- a/src/model/service/task_service.go
+++ b/src/model/service/task_service.go
@@ -450,6 +450,18 @@ func TryProcessEvmERC20Transfer(chainNetwork string, contract common.Address, to
}
func sendPaymentNotification(order *mdb.Orders) {
+ if order == nil {
+ return
+ }
+ if strings.TrimSpace(order.TradeId) != "" {
+ latest, err := data.GetOrderInfoByTradeId(order.TradeId)
+ if err != nil {
+ log.Sugar.Warnf("[notify] reload order failed trade_id=%s err=%v", order.TradeId, err)
+ } else if latest != nil && latest.TradeId != "" {
+ order = latest
+ }
+ }
+
msg := fmt.Sprintf(
"🎉 收款成功通知\n\n"+
"💰 金额信息\n"+
@@ -472,7 +484,7 @@ func sendPaymentNotification(order *mdb.Orders) {
networkDisplay(order.Network),
order.ReceiveAddress,
order.CreatedAt.ToDateTimeString(),
- carbon.Now().ToDateTimeString(),
+ order.UpdatedAt.ToDateTimeString(),
)
notify.Dispatch(mdb.NotifyEventPaySuccess, msg)
}
diff --git a/src/model/service/task_service_test.go b/src/model/service/task_service_test.go
new file mode 100644
index 0000000..6a2134a
--- /dev/null
+++ b/src/model/service/task_service_test.go
@@ -0,0 +1,79 @@
+package service
+
+import (
+ "strings"
+ "testing"
+ "time"
+
+ "github.com/GMWalletApp/epusdt/internal/testutil"
+ "github.com/GMWalletApp/epusdt/model/dao"
+ "github.com/GMWalletApp/epusdt/model/mdb"
+ "github.com/GMWalletApp/epusdt/notify"
+)
+
+func TestSendPaymentNotificationUsesLatestOrderUpdatedAt(t *testing.T) {
+ cleanup := testutil.SetupTestDatabases(t)
+ defer cleanup()
+
+ const channelType = "test-pay-success-time"
+ 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",
+ Config: "{}",
+ Events: `{"pay_success":true}`,
+ Enabled: true,
+ }).Error; err != nil {
+ t.Fatalf("seed notification channel: %v", err)
+ }
+
+ order := &mdb.Orders{
+ TradeId: "T202604270001",
+ OrderId: "ORD202604270001",
+ Amount: 100,
+ Currency: "cny",
+ ActualAmount: 14.28,
+ Token: "USDT",
+ Network: mdb.NetworkTron,
+ ReceiveAddress: "TTestAddress",
+ Status: mdb.StatusWaitPay,
+ }
+ if err := dao.Mdb.Create(order).Error; err != nil {
+ t.Fatalf("seed order: %v", err)
+ }
+
+ const createdAt = "2026-04-27 09:00:00"
+ const staleUpdatedAt = "2026-04-27 09:01:00"
+ const paidAt = "2026-04-27 10:20:30"
+ if err := dao.Mdb.Exec("UPDATE orders SET created_at = ?, updated_at = ? WHERE trade_id = ?", createdAt, staleUpdatedAt, order.TradeId).Error; err != nil {
+ t.Fatalf("set initial timestamps: %v", err)
+ }
+
+ var staleOrderModel mdb.Orders
+ if err := dao.Mdb.Where("trade_id = ?", order.TradeId).Take(&staleOrderModel).Error; err != nil {
+ t.Fatalf("load stale order: %v", err)
+ }
+
+ if err := dao.Mdb.Exec("UPDATE orders SET status = ?, updated_at = ? WHERE trade_id = ?", mdb.StatusPaySuccess, paidAt, order.TradeId).Error; err != nil {
+ t.Fatalf("set paid timestamp: %v", err)
+ }
+
+ sendPaymentNotification(&staleOrderModel)
+
+ select {
+ case text := <-got:
+ if !strings.Contains(text, "支付时间:"+paidAt) {
+ t.Fatalf("notification payment time = %q, want %s", text, paidAt)
+ }
+ if strings.Contains(text, "支付时间:"+staleUpdatedAt) {
+ t.Fatalf("notification used stale payment time: %q", text)
+ }
+ case <-time.After(2 * time.Second):
+ t.Fatal("timed out waiting for notification")
+ }
+}