修复(#16): 修复订单退款状态与后台恢复冲突 (#16)

Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
2026-06-09 11:31:31 -07:00
committed by GitHub
parent 21811f4d63
commit e74958e17f
9 changed files with 302 additions and 63 deletions
+23 -3
View File
@@ -7,9 +7,6 @@ import (
)
// HasRefundCommissionLog 判断指定订单号是否已写入 333 退款佣金日志。
// 用于 refund 主流程做幂等校验,以及 stuck-order recovery / activate worker
// 区分「已退款」(terminal)与「短暂 claimed」(transient)这两种共用 status=6
// 的语义。
//
// 实现细节:
// 1. type=33 + content LIKE '%"order_no":"<orderNo>"%' 先走索引粗筛;
@@ -36,3 +33,26 @@ func HasRefundCommissionLog(tx *gorm.DB, orderNo string) (bool, error) {
}
return false, nil
}
// HasOrderRefundLog 判断指定订单号是否已写入 24 订单退款审计日志。
func HasOrderRefundLog(tx *gorm.DB, orderNo string) (bool, error) {
if orderNo == "" {
return false, nil
}
var logs []SystemLog
if err := tx.Model(&SystemLog{}).
Where("type = ? AND content LIKE ?", TypeOrderRefund.Uint8(), fmt.Sprintf("%%\"order_no\":\"%s\"%%", orderNo)).
Find(&logs).Error; err != nil {
return false, fmt.Errorf("query order refund log failed: %w", err)
}
for _, item := range logs {
var content OrderRefund
if err := content.Unmarshal([]byte(item.Content)); err != nil {
continue
}
if content.OrderNo == orderNo {
return true, nil
}
}
return false, nil
}
+56
View File
@@ -140,6 +140,62 @@ func TestHasRefundCommissionLog(t *testing.T) {
})
}
func TestHasOrderRefundLog(t *testing.T) {
const orderNo = "ORD-REFUND-AUDIT-1"
t.Run("returns true when order refund audit log exists", func(t *testing.T) {
db, mock, cleanup := newRefundLogTestDB(t)
defer cleanup()
mock.ExpectQuery("FROM `system_logs`").
WithArgs(uint8(24), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)).
WillReturnRows(sqlmock.NewRows([]string{"id", "content"}).
AddRow(1, fmt.Sprintf(`{"order_id":100,"order_no":"%s","order_status_after":7}`, orderNo)))
got, err := HasOrderRefundLog(db, orderNo)
if err != nil {
t.Fatalf("HasOrderRefundLog error: %v", err)
}
if !got {
t.Fatalf("HasOrderRefundLog = false, want true")
}
assertRefundLogExpectations(t, mock)
})
t.Run("returns false when audit log order_no does not match", func(t *testing.T) {
db, mock, cleanup := newRefundLogTestDB(t)
defer cleanup()
mock.ExpectQuery("FROM `system_logs`").
WithArgs(uint8(24), fmt.Sprintf(`%%"order_no":"%s"%%`, orderNo)).
WillReturnRows(sqlmock.NewRows([]string{"id", "content"}).
AddRow(1, `{"order_id":100,"order_no":"OTHER","order_status_after":7}`))
got, err := HasOrderRefundLog(db, orderNo)
if err != nil {
t.Fatalf("HasOrderRefundLog error: %v", err)
}
if got {
t.Fatalf("HasOrderRefundLog = true, want false")
}
assertRefundLogExpectations(t, mock)
})
t.Run("returns false for empty order_no without querying", func(t *testing.T) {
db, mock, cleanup := newRefundLogTestDB(t)
defer cleanup()
got, err := HasOrderRefundLog(db, "")
if err != nil {
t.Fatalf("HasOrderRefundLog error: %v", err)
}
if got {
t.Fatalf("HasOrderRefundLog = true, want false")
}
assertRefundLogExpectations(t, mock)
})
}
func newRefundLogTestDB(t *testing.T) (*gorm.DB, sqlmock.Sqlmock, func()) {
t.Helper()