소스 검색

fix(migrate): t_legacy_mapping 补 legacy_teaching_user_id(P1-05 §2 三源语义拍定)

种子 16077 用户的阅卷/标记系统 id(t_user_account_association.marking_system_userid)
落 legacy_teaching_user_id;legacy_i_user_id=t_user.id 不变;legacy_academic_user_id 本地恒 NULL。
对齐 P1-05 字段覆盖矩阵 v2 §2 拍定的三源归属(收口 P0-07' I 侧' vs P0-13'marking_v2_db' 命名差异)。
门禁:go build/vet 0 错误,单测全绿。
Q 2 일 전
부모
커밋
e579b3e4b2
1개의 변경된 파일과 32개의 추가작업 그리고 13개의 파일을 삭제
  1. 32 13
      internal/migrate/runner.go

+ 32 - 13
internal/migrate/runner.go

@@ -162,6 +162,16 @@ func (r *Runner) Run(ctx context.Context) (*MigrateReport, error) {
 		}
 	}
 
+	// 种子映射(userid → 阅卷/标记系统 id),供 t_legacy_mapping.legacy_teaching_user_id(P1-05 §2 拍定)。
+	teachingByUserID := make(map[int32]int32, len(assoc))
+	for i := range assoc {
+		if assoc[i].UserID > 0 && assoc[i].MarkingSystemUserID != nil && *assoc[i].MarkingSystemUserID > 0 {
+			if _, exists := teachingByUserID[assoc[i].UserID]; !exists {
+				teachingByUserID[assoc[i].UserID] = *assoc[i].MarkingSystemUserID
+			}
+		}
+	}
+
 	planner := NewPlanner(users, assoc, wx)
 	// ULID 发放:已映射复用,新 id 发放(时间有序:以 regTime 为锚)
 	canonByID := make(map[int32]string, len(users))
@@ -248,7 +258,7 @@ func (r *Runner) Run(ctx context.Context) (*MigrateReport, error) {
 			}
 			r.writeIdentities(ctx, tx, u, canon, d, rep, usedPhone, existPhone)
 			r.writeWechatUnion(ctx, tx, u.ID, canon, planner, rep)
-			if err := r.writeLegacyMapping(ctx, tx, u, canon, d, rep); err != nil {
+			if err := r.writeLegacyMapping(ctx, tx, u, canon, d, teachingByUserID, rep); err != nil {
 				rep.Warnings = append(rep.Warnings, fmt.Sprintf("写 t_legacy_mapping legacy_id=%d 失败: %v", u.ID, err))
 			}
 		}
@@ -555,8 +565,13 @@ func (r *Runner) writeWechatUnion(ctx context.Context, tx *gorm.DB, userID int32
 }
 
 // writeLegacyMapping 写 t_legacy_mapping(canonical_user_id UNIQUE 幂等;重跑复用 ULID 时天然存在则跳过)。
+//
+// 三源 user_id(P1-05 §2 拍定):
+//   - LegacyIUserID        = 旧A yuansiwei_i.t_user.id(本地主源,恒有)
+//   - LegacyTeachingUserID = 阅卷/标记系统 id(t_user_account_association.marking_system_userid,仅种子用户有)
+//   - LegacyAcademicUserID = 教务 user id(本地恒 NULL,finance_bk 无 user 主表)
 func (r *Runner) writeLegacyMapping(ctx context.Context, tx *gorm.DB, u *LegacyUser, canon string,
-	d MatchDecision, rep *MigrateReport) error {
+	d MatchDecision, teachingByUserID map[int32]int32, rep *MigrateReport) error {
 	var n int64
 	tx.WithContext(ctx).Model(&identitymodel.LegacyMapping{}).Where("canonical_user_id = ?", canon).Count(&n)
 	if n > 0 {
@@ -565,17 +580,21 @@ func (r *Runner) writeLegacyMapping(ctx context.Context, tx *gorm.DB, u *LegacyU
 	legacyID := u.ID
 	role := mapRoleCode(u.Role)
 	lm := &identitymodel.LegacyMapping{
-		CanonicalUserID:      canon,
-		LegacyIUserID:        &legacyID, // I 库=教学侧,legacy_i_user_id
-		InstitutionID:        0,         // 平台级/待 P1-05 细化(canonical 用户跨机构)
-		CampusID:             0,
-		Role:                 &role,
-		MatchSource:          strPtr(d.MatchSource),
-		MatchConfidence:      d.Confidence,
-		AuditRef:             strPtr(fmt.Sprintf("migrate/v1.2/%d", u.ID)),
-		MergedAt:             &r.opts.Now,
-		CreatedAt:            r.opts.Now,
-		UpdatedAt:            r.opts.Now,
+		CanonicalUserID: canon,
+		LegacyIUserID:   &legacyID, // 旧A yuansiwei_i.t_user.id
+		InstitutionID:   0,         // 平台级(canonical 跨机构;代表机构非身份属性,P1-05 §6 拍定)
+		CampusID:        0,
+		Role:            &role,
+		MatchSource:     strPtr(d.MatchSource),
+		MatchConfidence: d.Confidence,
+		AuditRef:        strPtr(fmt.Sprintf("migrate/v1.2/%d", u.ID)),
+		MergedAt:        &r.opts.Now,
+		CreatedAt:       r.opts.Now,
+		UpdatedAt:       r.opts.Now,
+	}
+	// 阅卷/标记系统 id(种子用户才有;P1-05 §2:marking_system_userid → legacy_teaching_user_id)
+	if markingID, ok := teachingByUserID[u.ID]; ok {
+		lm.LegacyTeachingUserID = &markingID
 	}
 	if err := tx.WithContext(ctx).Create(lm).Error; err != nil {
 		return err