feat(distribution): 补齐退款加价回退、本站自卖与开通默认规则

退款时压缩卖方加价,人工/自动批次仅完结单可入账,号主收入进主站钱包;仲裁后重算释放并支持作废未入账 DS。开通时四种模式按默认生效,对外口径合并为 35/40/25,不再单独展示通道费。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yml2213
2026-09-10 18:13:46 +08:00
co-authored by Cursor
parent e621722218
commit 768902f2f7
28 changed files with 627 additions and 263 deletions
@@ -10,6 +10,7 @@ func TestDefaultRules(t *testing.T) {
{ModeTwoPartyDistributorReceive, func(r Rule) bool { return r.DistributorReceiveRatio == 35 && r.PlatformSellRatio == 40 }},
{ModeTwoPartyPlatformReceive, func(r Rule) bool { return r.PlatformReceiveRatio == 35 && r.DistributorSellRatio == 40 }},
{ModeThreeParty, func(r Rule) bool { return r.DistributorARatio == 35 && r.DistributorBRatio == 40 }},
{ModeSiteSelfSell, func(r Rule) bool { return r.DistributorSellRatio == 75 && r.ServiceFeeValue == 25 }},
}
for _, item := range cases {
rule, err := DefaultRule(item.mode)
@@ -17,8 +18,8 @@ func TestDefaultRules(t *testing.T) {
t.Fatalf("default rule %s = %#v, err=%v", item.mode, rule, err)
}
}
if _, err := DefaultRule(ModeSiteSelfSell); err != ErrUnsupportedMode {
t.Fatalf("site self-sell must not have a default split, err=%v", err)
if _, err := DefaultRule("unknown_mode"); err != ErrUnsupportedMode {
t.Fatalf("unknown mode must be unsupported, err=%v", err)
}
}
@@ -116,3 +117,54 @@ func TestSplitSettlementThreeParty(t *testing.T) {
t.Fatalf("splits = %#v", splits)
}
}
func TestCalculateSettlementClampsMarkupToRemainingNetPaid(t *testing.T) {
rule := Rule{ServiceFeeValue: 25, ServiceFeeUnit: ServiceFeeUnitPercent, PaymentFeeBPS: 50}
got, err := CalculateSettlement(rule, SettlementInput{
GrossPaidAmountCent: 10000, RefundAmountCent: 10000, OwnerRentAmountCent: 6000, MarkupAmountCent: 3000,
})
if err != nil {
t.Fatal(err)
}
if got.MarkupAmountCent != 0 || got.SplitBaseAmountCent != 0 || got.NetPaidAmountCent != 0 {
t.Fatalf("full refund must zero markup and profit: %#v", got)
}
partial, err := CalculateSettlement(rule, SettlementInput{
GrossPaidAmountCent: 10000, RefundAmountCent: 2000, OwnerRentAmountCent: 6000, MarkupAmountCent: 3000,
})
if err != nil {
t.Fatal(err)
}
if partial.NetPaidAmountCent != 8000 || partial.MarkupAmountCent != 2000 || partial.SplitBaseAmountCent != 0 {
t.Fatalf("partial refund should clamp markup to remainder: %#v", partial)
}
}
func TestSplitSettlementSiteSelfSell(t *testing.T) {
rule, err := DefaultRule(ModeSiteSelfSell)
if err != nil {
t.Fatal(err)
}
splits := SplitSettlement(rule, 10000, 2000)
if len(splits) != 1 || splits[0].PartyRole != "distributor_sell" || splits[0].AmountCent != 9500 {
t.Fatalf("self-sell split = %#v, want 7500+2000", splits)
}
}
func TestValidateRuleRequiresPercentSum(t *testing.T) {
rule, err := DefaultRule(ModeTwoPartyDistributorReceive)
if err != nil {
t.Fatal(err)
}
if err := ValidateRule(rule); err != nil {
t.Fatalf("default rule should be valid: %v", err)
}
rule.DistributorReceiveRatio = 10
if err := ValidateRule(rule); err != ErrInvalidRate {
t.Fatalf("invalid percent sum err = %v", err)
}
if err := ValidateRule(Rule{Mode: "not_a_mode", ServiceFeeUnit: ServiceFeeUnitPercent}); err != ErrUnsupportedMode {
t.Fatalf("unsupported mode err = %v", err)
}
}