|
@@ -67,6 +67,13 @@ type ActivitySeed struct {
|
|
|
// 没有这些行,冲回**根本进不去循环**,那条 case 就成了"两侧都 no-op"的空过。
|
|
// 没有这些行,冲回**根本进不去循环**,那条 case 就成了"两侧都 no-op"的空过。
|
|
|
UsedLogs []UsedLogSeed
|
|
UsedLogs []UsedLogSeed
|
|
|
|
|
|
|
|
|
|
+ // Discounts 是要种的赠送额度行(`t_courses_activity_user_discount`)。
|
|
|
|
|
+ //
|
|
|
|
|
+ // `user_discount_use` 的游标是
|
|
|
|
|
+ // `WHERE userid=? AND activityid=?`(读 `discount_amount` / `discount_amount_used`),
|
|
|
|
|
+ // **没有这一行就进不去循环** ⇒ 两侧都 no-op ⇒ case 退化成空过。
|
|
|
|
|
+ Discounts []DiscountSeed
|
|
|
|
|
+
|
|
|
// Items 非 nil 时**整体替换** `C1ActivityPlan` 的默认矩阵(case 自定义构型)。
|
|
// Items 非 nil 时**整体替换** `C1ActivityPlan` 的默认矩阵(case 自定义构型)。
|
|
|
//
|
|
//
|
|
|
// `ID` 留 0 即可:由 `buildPlan` 按 `base+i` 分配。**case 里不许写死 id** ——
|
|
// `ID` 留 0 即可:由 `buildPlan` 按 `base+i` 分配。**case 里不许写死 id** ——
|
|
@@ -128,6 +135,17 @@ type UsedLogSeed struct {
|
|
|
Memo string
|
|
Memo string
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+// DiscountSeed 是一条要种的赠送额度行。
|
|
|
|
|
+//
|
|
|
|
|
+// 只种 `discount_amount` / `discount_amount_used` / `income` 三个金额,其余留库默认:
|
|
|
|
|
+// - `balance_requestid` 留 NULL(3a 不做 varchar→bigint 的 id 重映射,且 Q3 断言两侧都是 NULL)
|
|
|
|
|
+type DiscountSeed struct {
|
|
|
|
|
+ ActivityIndex int
|
|
|
|
|
+ AmountCents int64 // discount_amount(2 位口径列)
|
|
|
|
|
+ UsedCents int64 // discount_amount_used(**3 位口径列**,与上一行不共用 readRound)
|
|
|
|
|
+ IncomeCents int64
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// buildPlan 按 case 的声明构造实际 plan(id 由 base 决定)。
|
|
// buildPlan 按 case 的声明构造实际 plan(id 由 base 决定)。
|
|
|
//
|
|
//
|
|
|
// 两条路径:
|
|
// 两条路径:
|
|
@@ -306,6 +324,18 @@ VALUES (?, ?, ?, ?, ?, ?, NOW())`,
|
|
|
return fmt.Errorf("种子 legacy 报名 %d 失败:%w", it.ID, err)
|
|
return fmt.Errorf("种子 legacy 报名 %d 失败:%w", it.ID, err)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ // 赠送额度行(`user_discount_*` 的游标依据;不种就进不去循环)。
|
|
|
|
|
+ for _, d := range c.Activity.Discounts {
|
|
|
|
|
+ aid := p.Items[d.ActivityIndex].ID
|
|
|
|
|
+ if err := tx.Exec(`
|
|
|
|
|
+INSERT INTO t_courses_activity_user_discount
|
|
|
|
|
+ (activityid, schoolid, campusid, userid, income, discount_amount, discount_amount_used, create_time)
|
|
|
|
|
+VALUES (?, ?, ?, ?, ?, ?, ?, NOW())`,
|
|
|
|
|
+ aid, c.InstitutionID, c.CampusID, uid,
|
|
|
|
|
+ yuan(d.IncomeCents), yuan(d.AmountCents), yuan(d.UsedCents)).Error; err != nil {
|
|
|
|
|
+ return fmt.Errorf("种子 legacy 赠送额度失败:%w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
// 用量流水(W2 冲回路径的定位依据)。两侧 `orderid` / `order_no` 写同一个字符串。
|
|
// 用量流水(W2 冲回路径的定位依据)。两侧 `orderid` / `order_no` 写同一个字符串。
|
|
|
for _, ul := range c.Activity.UsedLogs {
|
|
for _, ul := range c.Activity.UsedLogs {
|
|
|
aid := p.Items[ul.ActivityIndex].ID
|
|
aid := p.Items[ul.ActivityIndex].ID
|
|
@@ -363,6 +393,18 @@ VALUES (?, ?, ?, ?, ?, ?, ?, ?, NOW(3))`,
|
|
|
return fmt.Errorf("种子 target 报名 %d 失败:%w", it.ID, err)
|
|
return fmt.Errorf("种子 target 报名 %d 失败:%w", it.ID, err)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+ // 赠送额度行(同 legacy)。`balance_request_id` 留 NULL —— 3a 不做 id 重映射。
|
|
|
|
|
+ for _, d := range c.Activity.Discounts {
|
|
|
|
|
+ aid := p.Items[d.ActivityIndex].ID
|
|
|
|
|
+ if err := tx.Exec(`
|
|
|
|
|
+INSERT INTO t_courses_activity_user_discount
|
|
|
|
|
+ (activity_id, institution_id, campus_id, user_id, income, discount_amount, discount_amount_used, create_time)
|
|
|
|
|
+VALUES (?, ?, ?, ?, ?, ?, ?, NOW(3))`,
|
|
|
|
|
+ aid, c.InstitutionID, c.CampusID, uid,
|
|
|
|
|
+ yuan(d.IncomeCents), yuan(d.AmountCents), yuan(d.UsedCents)).Error; err != nil {
|
|
|
|
|
+ return fmt.Errorf("种子 target 赠送额度失败:%w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
// 用量流水:`order_no` 与 legacy 的 `orderid` 同一个字符串(两侧游标靠它定位)。
|
|
// 用量流水:`order_no` 与 legacy 的 `orderid` 同一个字符串(两侧游标靠它定位)。
|
|
|
for _, ul := range c.Activity.UsedLogs {
|
|
for _, ul := range c.Activity.UsedLogs {
|
|
|
aid := p.Items[ul.ActivityIndex].ID
|
|
aid := p.Items[ul.ActivityIndex].ID
|