|
@@ -944,48 +944,80 @@ SELECT t1.biz_no, t1.id,
|
|
|
return out, rows.Err()
|
|
return out, rows.Err()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-// readRecommenderAccount 读"推荐人"的资金账户(全局 + 本校区)。
|
|
|
|
|
|
|
+// recAccountCols 是推荐人账户六列的统一读法(2 位口径,与全仓一致)。
|
|
|
|
|
+//
|
|
|
|
|
+// 抽成常量而不是复制六遍:这六行里任何一处括号写错,`Row().Scan` 会报 column 数不匹配,
|
|
|
|
|
+// 那种错误看起来像"读不到账户",实际是 SQL 语法写坏了(本轮真踩了一次)。
|
|
|
|
|
+const recAccountCols = `CAST(ROUND(CAST(balance AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
+ CAST(ROUND(CAST(spend AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
+ CAST(ROUND(CAST(total_income AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
+ CAST(ROUND(CAST(total_expenditure AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
+ CAST(ROUND(CAST(special_expenses AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
+ CAST(ROUND(CAST(total_recommended_amount AS DECIMAL(20,3)),2) AS DECIMAL(12,2))`
|
|
|
|
|
+
|
|
|
|
|
+// readRecommenderAccounts 读"推荐人"的两个资金账户:全局(`t_user_expense`)+ 本校区(`t_user_expense_school`)。
|
|
|
//
|
|
//
|
|
|
// 只在 `c.RecommendUserID > 0` 时读 —— 其余 case 不付额外查询代价(报告尾部的"代价"行会体现)。
|
|
// 只在 `c.RecommendUserID > 0` 时读 —— 其余 case 不付额外查询代价(报告尾部的"代价"行会体现)。
|
|
|
-func readRecommenderAccount(ctx context.Context, tx *gorm.DB, c Case, target bool) (Account, bool, error) {
|
|
|
|
|
|
|
+//
|
|
|
|
|
+// ⚠ **只读全局是不够的**(3d 的 W4-B 逼出来的):
|
|
|
|
|
+// - `t_user_expense.balance` 有 `DEFAULT 0.000` ⇒ 建行后**有值** ⇒ `+m` 到账;
|
|
|
|
|
+// - `t_user_expense_school.balance` **无 DEFAULT** ⇒ 建行后 **NULL** ⇒ `+m` 仍是 NULL ⇒ 没到账。
|
|
|
|
|
+//
|
|
|
|
|
+// 只比全局的话,两侧在全局那一半**恰好相等** ⇒ W4-B 红不出来,得到一条
|
|
|
|
|
+// "只验了正确部分"的绿。那比"少验"更坏,因为它看起来通过了。
|
|
|
|
|
+//
|
|
|
|
|
+// 两个 bool 各自独立:**行不存在**(会走建行分支)与**行在但列 NULL** 是两条不同路径。
|
|
|
|
|
+func readRecommenderAccounts(ctx context.Context, tx *gorm.DB, c Case, target bool) (
|
|
|
|
|
+ global Account, hasGlobal bool, campus Account, hasCampus bool, err error) {
|
|
|
if c.RecommendUserID <= 0 {
|
|
if c.RecommendUserID <= 0 {
|
|
|
- return Account{}, false, nil
|
|
|
|
|
|
|
+ return Account{}, false, Account{}, false, nil
|
|
|
}
|
|
}
|
|
|
|
|
+ var g, s accountNS
|
|
|
if target {
|
|
if target {
|
|
|
uid := CanonicalUIDFor(c.RecommendUserID)
|
|
uid := CanonicalUIDFor(c.RecommendUserID)
|
|
|
- var g accountNS
|
|
|
|
|
- if err := tx.Raw(`
|
|
|
|
|
-SELECT CAST(ROUND(CAST(balance AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(spend AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(total_income AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(total_expenditure AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(special_expenses AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(total_recommended_amount AS DECIMAL(20,3)),2) AS DECIMAL(12,2))
|
|
|
|
|
- FROM t_user_expense WHERE user_id = ?`, uid).
|
|
|
|
|
- Row().Scan(&g.Balance, &g.Spend, &g.Income, &g.Expenditure, &g.Special, &g.Recommended); err != nil {
|
|
|
|
|
- if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
|
- return Account{}, false, nil
|
|
|
|
|
- }
|
|
|
|
|
- return Account{}, false, fmt.Errorf("读 target 推荐人全局账户失败:%w", err)
|
|
|
|
|
- }
|
|
|
|
|
- return g.account(), true, nil
|
|
|
|
|
- }
|
|
|
|
|
- var g accountNS
|
|
|
|
|
- if err := tx.Raw(`
|
|
|
|
|
-SELECT CAST(ROUND(CAST(balance AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(spend AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(total_income AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(total_expenditure AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(special_expenses AS DECIMAL(20,3)),2) AS DECIMAL(12,2)),
|
|
|
|
|
- CAST(ROUND(CAST(total_recommended_amount AS DECIMAL(20,3)),2) AS DECIMAL(12,2))
|
|
|
|
|
- FROM t_user_expense WHERE userid = ?`, c.RecommendUserID).
|
|
|
|
|
- Row().Scan(&g.Balance, &g.Spend, &g.Income, &g.Expenditure, &g.Special, &g.Recommended); err != nil {
|
|
|
|
|
- if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
|
- return Account{}, false, nil
|
|
|
|
|
- }
|
|
|
|
|
- return Account{}, false, fmt.Errorf("读 legacy 推荐人全局账户失败:%w", err)
|
|
|
|
|
- }
|
|
|
|
|
- return g.account(), true, nil
|
|
|
|
|
|
|
+ err = tx.Raw(`SELECT `+recAccountCols+` FROM t_user_expense WHERE user_id = ?`, uid).
|
|
|
|
|
+ Row().Scan(&g.Balance, &g.Spend, &g.Income, &g.Expenditure, &g.Special, &g.Recommended)
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ hasGlobal = true
|
|
|
|
|
+ } else if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
|
+ err = nil
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return Account{}, false, Account{}, false, fmt.Errorf("读 target 推荐人全局账户失败:%w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ err = tx.Raw(`SELECT `+recAccountCols+`
|
|
|
|
|
+ FROM t_user_expense_school WHERE user_id = ? AND institution_id = ? AND campus_id = ?`,
|
|
|
|
|
+ uid, c.InstitutionID, c.CampusID).
|
|
|
|
|
+ Row().Scan(&s.Balance, &s.Spend, &s.Income, &s.Expenditure, &s.Special, &s.Recommended)
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ hasCampus = true
|
|
|
|
|
+ } else if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
|
+ err = nil
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return Account{}, false, Account{}, false, fmt.Errorf("读 target 推荐人校区账户失败:%w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return g.account(), hasGlobal, s.account(), hasCampus, nil
|
|
|
|
|
+ }
|
|
|
|
|
+ err = tx.Raw(`SELECT `+recAccountCols+` FROM t_user_expense WHERE userid = ?`, c.RecommendUserID).
|
|
|
|
|
+ Row().Scan(&g.Balance, &g.Spend, &g.Income, &g.Expenditure, &g.Special, &g.Recommended)
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ hasGlobal = true
|
|
|
|
|
+ } else if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
|
+ err = nil
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return Account{}, false, Account{}, false, fmt.Errorf("读 legacy 推荐人全局账户失败:%w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ err = tx.Raw(`SELECT `+recAccountCols+`
|
|
|
|
|
+ FROM t_user_expense_school WHERE userid = ? AND schoolid = ? AND campusid = ?`,
|
|
|
|
|
+ c.RecommendUserID, c.InstitutionID, c.CampusID).
|
|
|
|
|
+ Row().Scan(&s.Balance, &s.Spend, &s.Income, &s.Expenditure, &s.Special, &s.Recommended)
|
|
|
|
|
+ if err == nil {
|
|
|
|
|
+ hasCampus = true
|
|
|
|
|
+ } else if errors.Is(err, sql.ErrNoRows) {
|
|
|
|
|
+ err = nil
|
|
|
|
|
+ } else {
|
|
|
|
|
+ return Account{}, false, Account{}, false, fmt.Errorf("读 legacy 推荐人校区账户失败:%w", err)
|
|
|
|
|
+ }
|
|
|
|
|
+ return g.account(), hasGlobal, s.account(), hasCampus, nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// studentBizNos 安全地取 case 声明的报课单号(两侧都为空时返回 nil)。
|
|
// studentBizNos 安全地取 case 声明的报课单号(两侧都为空时返回 nil)。
|