Files

144 lines
5.6 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package payment
import (
"testing"
"time"
"hfb_sys/backend/internal/model"
"hfb_sys/backend/internal/modules/distribution"
)
// TestUpdateOrderRefundStatusUsesCumulativeRefundedAmount 断言同一订单多笔退款时,
// 单笔回调传入的金额不会把订单累计退款额写小,分销财务快照按合计口径重算。
func TestUpdateOrderRefundStatusUsesCumulativeRefundedAmount(t *testing.T) {
db := setupPaymentTestDB(t)
repo := NewRepository(db, nil, nil)
now := time.Now()
site := model.DistributionSite{
SiteCode: "cum_site", SiteName: "累计退款站", Domain: "cum.dist.com",
Status: "active", DisplayAccountEnabled: true,
}
if err := db.Create(&site).Error; err != nil {
t.Fatal(err)
}
rule := model.DistributionRuleVersion{
SiteID: &site.ID, Mode: distribution.ModeTwoPartyPlatformReceive, Version: 1, Status: "active",
PlatformReceiveRatio: 35, DistributorSellRatio: 40, ServiceFeeValue: 0,
ServiceFeeUnit: distribution.ServiceFeeUnitFixedAmount, PaymentFeeBPS: 0,
EffectiveFrom: now.Add(-time.Hour),
}
if err := db.Create(&rule).Error; err != nil {
t.Fatal(err)
}
order := model.RentalOrder{
OrderNo: "ORD-CUM-REFUND", ListingID: 1, AccountID: 1, OwnerID: 1, RenterID: 2,
Status: "completed", RentAmountCent: 10000, OwnerRentAmountCent: 6000,
DistributionSiteID: &site.ID, DistributionRuleVersionID: &rule.ID,
}
if err := db.Create(&order).Error; err != nil {
t.Fatal(err)
}
if err := distribution.SnapshotPaidOrderTx(db, order.ID, 10000); err != nil {
t.Fatal(err)
}
// 两笔已退款成功流水:300 + 700 = 1000。
refunds := []model.PaymentOrder{
{PaymentNo: "REF-CUM-1", OrderID: order.ID, OrderNo: order.OrderNo, UserID: order.RenterID, Provider: "mock", ThirdOrderID: "REF-CUM-1", AmountCent: 300, BizType: "admin_refund", Status: "refunded"},
{PaymentNo: "REF-CUM-2", OrderID: order.ID, OrderNo: order.OrderNo, UserID: order.RenterID, Provider: "mock", ThirdOrderID: "REF-CUM-2", AmountCent: 700, BizType: "rent_refund", Status: "refunded"},
}
if err := db.Create(&refunds).Error; err != nil {
t.Fatal(err)
}
// 只传其中一笔金额调用:累计口径应取两笔合计 1000。
if err := repo.updateOrderRefundStatus(t.Context(), order.ID, 300, "admin_refund"); err != nil {
t.Fatal(err)
}
var saved model.RentalOrder
if err := db.First(&saved, order.ID).Error; err != nil {
t.Fatal(err)
}
if saved.RefundAmountCent != 1000 {
t.Fatalf("order.RefundAmountCent = %d, want 1000(两笔退款合计)", saved.RefundAmountCent)
}
if saved.RefundStatus != "refunded" {
t.Fatalf("order.RefundStatus = %s, want refunded", saved.RefundStatus)
}
var financial model.DistributionOrderFinancial
if err := db.Where("order_id = ?", order.ID).First(&financial).Error; err != nil {
t.Fatal(err)
}
if financial.RefundAmountCent != 1000 || financial.NetPaidAmountCent != 9000 || financial.SplitBaseAmountCent != 3000 {
t.Fatalf("分销快照未按累计退款重算:refund=%d netPaid=%d splitBase=%d",
financial.RefundAmountCent, financial.NetPaidAmountCent, financial.SplitBaseAmountCent)
}
var party model.DistributionOrderParty
if err := db.Where("order_id = ? AND party_role = ?", order.ID, "distributor_sell").First(&party).Error; err != nil {
t.Fatal(err)
}
if party.IncomeAmountCent != 1200 {
t.Fatalf("分站份额 = %d, want 1200(利润 3000 的 40%%)", party.IncomeAmountCent)
}
// 退款结果查询重复回调不应把累计额写小。
if err := repo.updateOrderRefundStatus(t.Context(), order.ID, 300, "admin_refund"); err != nil {
t.Fatal(err)
}
if err := db.First(&saved, order.ID).Error; err != nil {
t.Fatal(err)
}
if saved.RefundAmountCent != 1000 {
t.Fatalf("重复回调后 order.RefundAmountCent = %d, want 1000(单调不回退)", saved.RefundAmountCent)
}
}
// TestMarkOrderRefundingAndFailedPreserveCumulativeRefund 断言已成功退款的订单
// 发生后续退款中或退款失败时,累计退款额不会被单笔处理金额冲减缩小。
func TestMarkOrderRefundingAndFailedPreserveCumulativeRefund(t *testing.T) {
db := setupPaymentTestDB(t)
repo := NewRepository(db, nil, nil)
order := model.RentalOrder{
OrderNo: "ORD-REF-PRESERVE", ListingID: 1, AccountID: 1, OwnerID: 1, RenterID: 2,
Status: "completed", RentAmountCent: 10000, OwnerRentAmountCent: 6000,
}
if err := db.Create(&order).Error; err != nil {
t.Fatal(err)
}
// 先前已成功退款 5000。
prevRefund := model.PaymentOrder{
PaymentNo: "REF-PREV-1", OrderID: order.ID, OrderNo: order.OrderNo, UserID: order.RenterID,
Provider: "mock", ThirdOrderID: "REF-PREV-1", AmountCent: 5000, BizType: "admin_refund", Status: "refunded",
}
if err := db.Create(&prevRefund).Error; err != nil {
t.Fatal(err)
}
// 此时发起了另一笔 2000 的退款中:累计额应为 max(2000, 5000) = 5000。
if err := repo.markOrderRefunding(t.Context(), order.ID, 2000); err != nil {
t.Fatal(err)
}
var saved model.RentalOrder
if err := db.First(&saved, order.ID).Error; err != nil {
t.Fatal(err)
}
if saved.RefundStatus != "refunding" || saved.RefundAmountCent != 5000 {
t.Fatalf("markOrderRefunding 后状态 = %s/%d, want refunding/5000", saved.RefundStatus, saved.RefundAmountCent)
}
// 该笔 2000 退款最终失败:累计退款额还原为已成功流水合计 5000,而不是单笔 2000。
if err := repo.markOrderRefundFailed(t.Context(), order.ID, 2000); err != nil {
t.Fatal(err)
}
if err := db.First(&saved, order.ID).Error; err != nil {
t.Fatal(err)
}
if saved.RefundStatus != "failed" || saved.RefundAmountCent != 5000 {
t.Fatalf("markOrderRefundFailed 后状态 = %s/%d, want failed/5000", saved.RefundStatus, saved.RefundAmountCent)
}
}