package store_test import ( "testing" "github.com/wangjia/pay/internal/model" "github.com/wangjia/pay/internal/store" ) func TestChargebackCreateIdempotent(t *testing.T) { s := store.NewChargebackStore(model.OpenTestDB(t)) cb := &model.Chargeback{ DisputeRef: "dp_1", OutTradeNo: "PAY-1", Channel: "stripe", ProviderPaymentRef: "pi_1", AmountMinor: 2999, Currency: "USD", Reason: "fraudulent", Status: "received", } created, err := s.Create(cb) if err != nil || !created { t.Fatalf("first create: created=%v err=%v", created, err) } // 同 dispute_ref 重投(Stripe 重投 charge.dispute.created)→ 幂等 no-op,不双记。 again, err := s.Create(&model.Chargeback{ DisputeRef: "dp_1", OutTradeNo: "PAY-1", Channel: "stripe", ProviderPaymentRef: "pi_1", AmountMinor: 2999, Currency: "USD", Reason: "fraudulent", Status: "received", }) if err != nil || again { t.Fatalf("dup create: again=%v err=%v", again, err) } } // 订阅拒付常无法解析出业务单号(PI 不带 out_trade_no metadata)——Chargeback 表对此 // 保持中立,OutTradeNo 空值也照常落一行留痕,不因空值而失败或跳过。 func TestChargebackCreateWithEmptyOutTradeNo(t *testing.T) { s := store.NewChargebackStore(model.OpenTestDB(t)) created, err := s.Create(&model.Chargeback{ DisputeRef: "dp_sub_1", OutTradeNo: "", Channel: "stripe", ProviderPaymentRef: "pi_sub_1", AmountMinor: 999, Currency: "USD", Reason: "fraudulent", Status: "received", }) if err != nil || !created { t.Fatalf("create with empty out_trade_no: created=%v err=%v", created, err) } }