|
@@ -264,6 +264,50 @@ func recommendArrearsAssertions(c Case, lg, tg *SideResult) ([]Diff, []Assertion
|
|
|
e.Row.RemainderReceivableCents, c.AmountCents),
|
|
e.Row.RemainderReceivableCents, c.AmountCents),
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
+ // ---- 每人各自的核销上限 = m,且 Σ核销 ≤ m ----
|
|
|
|
|
+ //
|
|
|
|
|
+ // 为什么按**用户**汇总而不是全局汇总:两个 CALL 的上限各自都是 `activityMoney`,
|
|
|
|
|
+ // 全局汇总(Σ = 2m)会把"某人被核了两次 / 另一人没被核"算成正确。
|
|
|
|
|
+ type userSum struct{ l, t, want int64 }
|
|
|
|
|
+ sums := make(map[int64]*userSum, len(c.Arrears.ByUser))
|
|
|
|
|
+ for _, u := range c.Arrears.userIDs() {
|
|
|
|
|
+ sums[u] = &userSum{}
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, e := range c.Arrears.flatRows() {
|
|
|
|
|
+ w := want[e.Row.BizNo]
|
|
|
|
|
+ sums[e.User].l += lgD[e.Row.BizNo].NetDelta
|
|
|
|
|
+ sums[e.User].t += tgD[e.Row.BizNo].NetDelta
|
|
|
|
|
+ sums[e.User].want += w.NetDelta
|
|
|
|
|
+ }
|
|
|
|
|
+ for _, u := range c.Arrears.userIDs() {
|
|
|
|
|
+ s5 := sums[u]
|
|
|
|
|
+ asserts = append(asserts, Assertion{Kind: AssertionBusiness,
|
|
|
|
|
+ Name: fmt.Sprintf("W4-C 用户 %d 的核销总额 = m 且 ≤ m(每人各自一份额度,不与另一人共享)", u),
|
|
|
|
|
+ Pass: s5.l == s5.want && s5.t == s5.want && s5.l <= c.AmountCents && s5.t <= c.AmountCents,
|
|
|
|
|
+ Detail: fmt.Sprintf("legacy Σ=%+d | target Σ=%+d | 期望 %+d | 本人上限 m=%d。"+
|
|
|
|
|
+ "`<= m` 挡「核销无上限」,`= m` 挡「额度没被用满」,按用户汇总挡「两人串成一份」",
|
|
|
|
|
+ s5.l, s5.t, s5.want, c.AmountCents)})
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ---- 跨用户不干扰(W4-C 独有维度)----
|
|
|
|
|
+ //
|
|
|
|
|
+ // 两条 CALL 是同一个 SP、同一个学校/校区,**只差第一个实参**。
|
|
|
|
|
+ // "实参串了"(把推荐人的 id 传成被推荐人的)在终态上的表现是:
|
|
|
|
|
+ // 一个人的行被核两次(Σ = 2m),另一个人的行完全没动(Σ = 0)。
|
|
|
|
|
+ // 若只断言"两人各有一行 +5000",而期望表恰好也是"两人各 5000",总额仍然对得上 ——
|
|
|
|
|
+ // 所以必须**按用户分别**比对,这一条才抓得住它。
|
|
|
|
|
+ if len(c.Arrears.ByUser) == 2 {
|
|
|
|
|
+ ids := c.Arrears.userIDs()
|
|
|
|
|
+ a, b := sums[ids[0]], sums[ids[1]]
|
|
|
|
|
+ asserts = append(asserts, Assertion{Kind: AssertionBusiness,
|
|
|
|
|
+ Name: "W4-C 跨用户不干扰:两次 CALL **各动各自的行**(不是把同一个 id 传两次)",
|
|
|
|
|
+ Pass: a.l == a.want && b.l == b.want && a.t == a.want && b.t == b.want &&
|
|
|
|
|
+ a.want > 0 && b.want > 0,
|
|
|
|
|
+ Detail: fmt.Sprintf("user %d:legacy %+d / target %+d(期望 %+d)| user %d:legacy %+d / target %+d(期望 %+d)。"+
|
|
|
|
|
+ "若某人 Σ=2m 而另一人 Σ=0 ⇒ 两次 CALL 的**第一个实参是同一个 id**",
|
|
|
|
|
+ ids[0], a.l, a.t, a.want, ids[1], b.l, b.t, b.want)})
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// 正向断言:**两个用户各核了一笔**。少了它,"两侧都 0"会全绿 ——
|
|
// 正向断言:**两个用户各核了一笔**。少了它,"两侧都 0"会全绿 ——
|
|
|
// 而那正是"第二个 CALL 没执行"或"两个用户共用一个额度"的形态。
|
|
// 而那正是"第二个 CALL 没执行"或"两个用户共用一个额度"的形态。
|
|
|
asserts = append(asserts, Assertion{Kind: AssertionBusiness,
|
|
asserts = append(asserts, Assertion{Kind: AssertionBusiness,
|