فهرست منبع

chore(attribution): 问卷模板种子启用(enabled=1) + 迁移编号对齐(并入425组)

- 迁移425-种子: 幂等启用(已存在则 UPDATE enabled=1,不覆盖 questions_json)
- 去掉独立迁移426,A2 问卷种子并入 425 组(对齐任务书 A1/A3=424/425)
- 单测同步:已存在时断言幂等启用
Sisyphus 2 هفته پیش
والد
کامیت
34f1091c41

+ 14 - 9
cfc-backend/src/main/java/com/etotem/cfc/config/DatabaseInitializer.java

@@ -3350,7 +3350,7 @@ insertSysConfigSeed("gift_membership_pay_price", "198000", "送会员商品达
         createAttributionNormValuesTable();
         // 迁移425-导入: 菌群常模可配置 JSON 导入(空壳文件导入 0 行,不报错)
         importAttributionNormGutFlora();
-        // 迁移426: 家庭归因确认问卷模板种子(第八章 16 条,幂等)
+        // 迁移425-种子: 家庭归因确认问卷模板种子(第八章 16 条,幂等)
         seedFamilyAttributionSurveyTemplate();
     }
 
@@ -14399,21 +14399,26 @@ log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记
     }
 
     /**
-     * 迁移426: 家庭归因确认问卷模板种子(A2:第八章 16 条 / 39 采集项)。
-     * 幂等:按 title 判重,已存在则跳过;questionsJson 存 §3.2 扩展结构(schemaVersion/target/questions)。
+     * 迁移425-种子: 家庭归因确认问卷模板种子(A2:第八章 16 条 / 45 采集项)。
+     * 幂等:按 title 判重;已存在则只确保 enabled=1(不覆盖管理员改过的 questions_json);
+     * questionsJson 存 §3.2 扩展结构(schemaVersion/target/questions)。
      */
     void seedFamilyAttributionSurveyTemplate() {
         try {
             ClassPathResource resource = new ClassPathResource(SURVEY_FAMILY_ATTRIBUTION_CLASSPATH);
             if (!resource.exists()) {
-                log.warn("迁移426: 未找到问卷模板种子 {},跳过", SURVEY_FAMILY_ATTRIBUTION_CLASSPATH);
+                log.warn("迁移425-种子: 未找到问卷模板种子 {},跳过", SURVEY_FAMILY_ATTRIBUTION_CLASSPATH);
                 return;
             }
             Integer cnt = jdbcTemplate.queryForObject(
                     "SELECT COUNT(*) FROM survey_templates WHERE title = ?",
                     Integer.class, SURVEY_FAMILY_ATTRIBUTION_TITLE);
             if (cnt != null && cnt > 0) {
-                log.info("迁移426: 家庭归因问卷模板已存在(title={}),跳过种子", SURVEY_FAMILY_ATTRIBUTION_TITLE);
+                // 已存在:幂等启用(不覆盖管理员可能改过的 questions_json)
+                jdbcTemplate.update(
+                        "UPDATE survey_templates SET enabled = 1, updated_at = NOW() WHERE title = ?",
+                        SURVEY_FAMILY_ATTRIBUTION_TITLE);
+                log.info("迁移425-种子: 家庭归因问卷模板已存在(title={}),幂等启用(enabled=1)", SURVEY_FAMILY_ATTRIBUTION_TITLE);
                 return;
             }
             String content = StreamUtils.copyToString(resource.getInputStream(), StandardCharsets.UTF_8);
@@ -14421,20 +14426,20 @@ log.info("迁移298: 已为无 openid 的 child 账号补齐 family_members 记
             ObjectMapper mapper = new ObjectMapper();
             JsonNode root = mapper.readTree(content);
             if (root == null || !root.isObject() || root.get("questions") == null) {
-                log.warn("迁移426: 问卷模板种子格式非法,跳过");
+                log.warn("迁移425-种子: 问卷模板种子格式非法,跳过");
                 return;
             }
             jdbcTemplate.update(
                     "INSERT INTO survey_templates (title, dimension, questions_json, cycle_type, ai_generated, enabled, created_at, updated_at) "
-                            + "VALUES (?, ?, ?, ?, 0, 0, NOW(), NOW())",
+                            + "VALUES (?, ?, ?, ?, 0, 1, NOW(), NOW())",
                     SURVEY_FAMILY_ATTRIBUTION_TITLE,
                     "family_attribution",
                     content,
                     "once");
-            log.info("迁移426: 已写入家庭归因问卷模板种子 title={} questions={}(enabled=0,阶段二启用)",
+            log.info("迁移425-种子: 已写入家庭归因问卷模板种子 title={} questions={}(enabled=1,已启用)",
                     SURVEY_FAMILY_ATTRIBUTION_TITLE, root.get("questions").size());
         } catch (Exception e) {
-            log.warn("迁移426: 家庭归因问卷模板种子失败(忽略): {}", e.getMessage());
+            log.warn("迁移425-种子: 家庭归因问卷模板种子失败(忽略): {}", e.getMessage());
         }
     }
 

+ 7 - 2
cfc-backend/src/test/java/com/etotem/cfc/config/AttributionStage1FoundationTest.java

@@ -59,12 +59,15 @@ class AttributionStage1FoundationTest {
     // ---------------- A2:问卷模板种子 ----------------
 
     @Test
-    void A2_模板已存在时跳过种子() {
+    void A2_模板已存在时幂等启用() {
         when(jdbcTemplate.queryForObject(anyString(), eq(Integer.class), any())).thenReturn(1);
 
         initializer.seedFamilyAttributionSurveyTemplate();
 
-        assertNoUpdateCalled();
+        ArgumentCaptor<String> sql = ArgumentCaptor.forClass(String.class);
+        verify(jdbcTemplate).update(sql.capture(), any(Object.class));
+        assertTrue(sql.getValue().contains("UPDATE survey_templates SET enabled = 1"),
+                "已存在时只幂等启用,不覆盖 questions_json:" + sql.getValue());
     }
 
     @Test
@@ -78,6 +81,8 @@ class AttributionStage1FoundationTest {
         verify(jdbcTemplate).update(sql.capture(), arg.capture(), arg.capture(), arg.capture(), arg.capture());
 
         assertTrue(sql.getValue().contains("INSERT INTO survey_templates"), "应写入 survey_templates");
+        assertTrue(sql.getValue().contains("VALUES (?, ?, ?, ?, 0, 1, NOW(), NOW())"),
+                "模板种子应默认启用(enabled=1):" + sql.getValue());
         List<Object> args = arg.getAllValues();
         assertEquals(DatabaseInitializer.SURVEY_FAMILY_ATTRIBUTION_TITLE, args.get(0), "按 title 判重");
         String questionsJson = (String) args.get(2);