package distribution import "testing" func TestDefaultRules(t *testing.T) { cases := []struct { mode string check func(Rule) bool }{ {ModeTwoPartyDistributorReceive, func(r Rule) bool { return r.DistributorReceiveRatio == 3.5 && r.PlatformSellRatio == 4 }}, {ModeTwoPartyPlatformReceive, func(r Rule) bool { return r.PlatformReceiveRatio == 3.5 && r.DistributorSellRatio == 4 }}, {ModeThreeParty, func(r Rule) bool { return r.DistributorARatio == 3.5 && r.DistributorBRatio == 4 }}, } for _, item := range cases { rule, err := DefaultRule(item.mode) if err != nil || !item.check(rule) || rule.ServiceFeeValue != 2.5 || rule.PaymentFeeBPS != 50 { 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) } } func TestCalculateSettlementDeductsFeeBeforeSplit(t *testing.T) { rule := Rule{ServiceFeeValue: 0, ServiceFeeUnit: ServiceFeeUnitFixedAmount, PaymentFeeBPS: 50} got, err := CalculateSettlement(rule, SettlementInput{GrossPaidAmountCent: 10001, RefundAmountCent: 1000, MarkupAmountCent: 300}) if err != nil { t.Fatal(err) } if got.NetPaidAmountCent != 9001 || got.PaymentFeeCent != 45 || got.SplitBaseAmountCent != 8956 { t.Fatalf("unexpected settlement: %#v", got) } } func TestCalculateSettlementTaxesEachPositivePartyProfit(t *testing.T) { rule := Rule{ServiceFeeUnit: ServiceFeeUnitFixedAmount, PaymentFeeBPS: 0, TaxEnabled: true, TaxRateBPS: 100} got, err := CalculateSettlement(rule, SettlementInput{ GrossPaidAmountCent: 10000, GrossProfitByParty: []PartyProfitInput{ {PartyRole: "distributor_a", IncomeAmountCent: 1000, CostAmountCent: 400}, {PartyRole: "distributor_b", IncomeAmountCent: 500, CostAmountCent: 700}, }, }) if err != nil { t.Fatal(err) } if got.TaxAmountCent != 6 || len(got.TaxByParty) != 2 || got.TaxByParty[0].TaxAmountCent != 6 || got.TaxByParty[1].TaxAmountCent != 0 { t.Fatalf("unexpected tax result: %#v", got) } } func TestCalculateSettlementRejectsRefundOverPayment(t *testing.T) { _, err := CalculateSettlement(Rule{ServiceFeeUnit: ServiceFeeUnitFixedAmount}, SettlementInput{GrossPaidAmountCent: 1, RefundAmountCent: 2}) if err != ErrInvalidAmount { t.Fatalf("err = %v", err) } } func TestSplitSettlementTwoPartyDistributorReceive(t *testing.T) { rule := Rule{Mode: ModeTwoPartyDistributorReceive, DistributorReceiveRatio: 3.5, PlatformSellRatio: 4} splits := SplitSettlement(rule, 10000, 0) if len(splits) != 2 { t.Fatalf("splits = %#v", splits) } if splits[0].PartyRole != "distributor_receive" || splits[0].AmountCent != 350 { t.Fatalf("distributor split = %#v", splits[0]) } if splits[1].PartyRole != "platform_sell" || splits[1].AmountCent != 400 { t.Fatalf("platform split = %#v", splits[1]) } if got := SplitRemainderCent(10000, splits); got != 9250 { t.Fatalf("remainder = %d, want 9250", got) } } func TestSplitSettlementMarkupGoesToSeller(t *testing.T) { // 两方-分销收号模式:卖出方是主站(platform_sell)。 rule := Rule{Mode: ModeTwoPartyDistributorReceive, DistributorReceiveRatio: 3.5, PlatformSellRatio: 4} splits := SplitSettlement(rule, 10000, 300) if splits[1].AmountCent != 700 { t.Fatalf("platform split with markup = %d, want 700", splits[1].AmountCent) } // 两方-分销卖出模式:卖出方是分销网(distributor_sell)。 ruleSell := Rule{Mode: ModeTwoPartyPlatformReceive, DistributorSellRatio: 4, PlatformReceiveRatio: 3.5} splitsSell := SplitSettlement(ruleSell, 10000, 300) if splitsSell[0].PartyRole != "distributor_sell" || splitsSell[0].AmountCent != 700 { t.Fatalf("distributor sell split with markup = %#v", splitsSell[0]) } if got := SplitRemainderCent(10000, splitsSell); got != 8950 { t.Fatalf("remainder = %d, want 8950", got) } } func TestSplitSettlementThreeParty(t *testing.T) { rule := Rule{Mode: ModeThreeParty, DistributorARatio: 3.5, DistributorBRatio: 4} splits := SplitSettlement(rule, 10001, 0) if len(splits) != 2 || splits[0].AmountCent != 350 || splits[1].AmountCent != 400 { t.Fatalf("splits = %#v", splits) } // 尾差归平台:10001 - 750 = 9251。 if got := SplitRemainderCent(10001, splits); got != 9251 { t.Fatalf("remainder = %d, want 9251", got) } }