fix(distribution): 货架加价打通前台、下单与卖方分成

分站公开列表和详情展示当前货架加价;下单写入 base_price / shelf_markup / markup_site_id 快照并计入实付。
支付分账改用快照加价,不再误用 PlatformFeeCent;结账不退加价,事后改价不影响历史订单。
This commit is contained in:
yml2213
2026-09-08 17:07:17 +08:00
parent 8521bf4753
commit 96bc6a4db6
16 changed files with 417 additions and 42 deletions
@@ -186,7 +186,10 @@ func SnapshotPaidOrderTx(tx *gorm.DB, orderID uint64, grossPaidCent int64) error
if err := tx.First(&rule, *order.DistributionRuleVersionID).Error; err != nil {
return err
}
markup := order.PlatformFeeCent
markup := order.ShelfMarkupCent
if markup < 0 {
markup = 0
}
result, err := calculateForRule(rule, SettlementInput{GrossPaidAmountCent: grossPaidCent, MarkupAmountCent: markup})
if err != nil {
return err
@@ -279,7 +279,8 @@ func TestSnapshotPaidOrderTxAndApplyRefundTx(t *testing.T) {
OwnerID: 1,
RenterID: 2,
Status: "renting",
PlatformFeeCent: 300,
PlatformFeeCent: 999,
ShelfMarkupCent: 300,
DistributionSiteID: &site.ID,
DistributionRuleVersionID: &rule.ID,
}
@@ -300,6 +301,9 @@ func TestSnapshotPaidOrderTxAndApplyRefundTx(t *testing.T) {
if financial.GrossPaidAmountCent != grossPaid || financial.SiteID != site.ID {
t.Fatalf("unexpected financial snapshot: %+v", financial)
}
if financial.MarkupAmountCent != 300 {
t.Fatalf("markup must come from shelf snapshot, got %d", financial.MarkupAmountCent)
}
var parties []model.DistributionOrderParty
if err := db.Where("order_id = ?", order.ID).Order("id ASC").Find(&parties).Error; err != nil || len(parties) != 2 {
@@ -347,3 +351,64 @@ func TestSnapshotPaidOrderTxAndApplyRefundTx(t *testing.T) {
t.Fatalf("expected net paid %d, got %d", grossPaid-refundAmount, updatedFinancial.NetPaidAmountCent)
}
}
func TestSnapshotPaidOrderTxAddsShelfMarkupToSeller(t *testing.T) {
db := distributionTestDB(t)
now := time.Now()
site := model.DistributionSite{SiteCode: "sell_markup", SiteName: "卖出加价站", Domain: "sell-markup.dist.com", Status: "active", DisplayAccountEnabled: true}
if err := db.Create(&site).Error; err != nil {
t.Fatal(err)
}
rule := model.DistributionRuleVersion{
SiteID: &site.ID, Mode: ModeTwoPartyPlatformReceive, Version: 1, Status: "active",
PlatformReceiveRatio: 3.5, DistributorSellRatio: 4,
ServiceFeeValue: 0, ServiceFeeUnit: ServiceFeeUnitFixedAmount, PaymentFeeBPS: 50,
EffectiveFrom: now.Add(-time.Hour),
}
if err := db.Create(&rule).Error; err != nil {
t.Fatal(err)
}
order := model.RentalOrder{
OrderNo: "ORD-MARKUP-SELL", ListingID: 1, AccountID: 2, OwnerID: 3, RenterID: 4, Status: "renting",
PlatformFeeCent: 2000, ShelfMarkupCent: 10000,
DistributionSiteID: &site.ID, DistributionRuleVersionID: &rule.ID, DistributionMode: ModeTwoPartyPlatformReceive,
}
if err := db.Create(&order).Error; err != nil {
t.Fatal(err)
}
if err := SnapshotPaidOrderTx(db, order.ID, 20000); err != nil {
t.Fatal(err)
}
var parties []model.DistributionOrderParty
if err := db.Where("order_id = ?", order.ID).Find(&parties).Error; err != nil {
t.Fatal(err)
}
var seller, platform *model.DistributionOrderParty
for i := range parties {
switch parties[i].PartyRole {
case "distributor_sell":
seller = &parties[i]
case "platform_receive":
platform = &parties[i]
}
}
if seller == nil || platform == nil {
t.Fatalf("missing parties: %+v", parties)
}
if seller.IncomeAmountCent < 10000 {
t.Fatalf("seller split must include 10000 markup, got %d", seller.IncomeAmountCent)
}
if platform.PartyID != 0 {
t.Fatalf("platform party_id = %d, want 0", platform.PartyID)
}
if err := db.Model(&order).Update("shelf_markup_cent", 0).Error; err != nil {
t.Fatal(err)
}
var financial model.DistributionOrderFinancial
if err := db.Where("order_id = ?", order.ID).First(&financial).Error; err != nil {
t.Fatal(err)
}
if financial.MarkupAmountCent != 10000 {
t.Fatalf("historical snapshot must keep markup, got %d", financial.MarkupAmountCent)
}
}