fix: 协议子资源单事务保存,并补齐样本编码/OA/质检等近期能力

锁定缴费校验失败时整单回滚,避免样本半成功落库;前端禁止删除锁定缴费样本,改码走更正编码。同步落地样本更正、采集微信通知、OA提及未读、细胞产品套餐与相关迁移文档。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zlwuandCursor committed 2026-10-26 11:02:25 +08:00
1 parent 19bc66ba45
commit 5dad1bb0e3
142 files changed
+95584 -65717

No files matched your search

@@ -0,0 +1,31 @@
-- 微信服务号通知发送日志(幂等)
-- 对齐 docs/superpowers/specs/2026-10-22-basic-experiment-delivery-remind-design.md
CREATE TABLE IF NOT EXISTS biz_wx_notify_log (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
biz_type VARCHAR(64) NOT NULL COMMENT '业务类型,如 basic_experiment_delivery_remind',
biz_id VARCHAR(64) NOT NULL COMMENT '业务主键(如交付计划ID)',
notify_date VARCHAR(10) NOT NULL COMMENT '提醒日 YYYY-MM-DD',
user_id VARCHAR(64) DEFAULT NULL COMMENT '接收用户ID',
status VARCHAR(16) NOT NULL DEFAULT 'success' COMMENT 'success/fail',
errcode VARCHAR(64) DEFAULT NULL COMMENT '微信/内部错误码',
errmsg VARCHAR(512) DEFAULT NULL COMMENT '错误信息',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT DEFAULT NULL COMMENT '排序号',
remark VARCHAR(512) DEFAULT NULL COMMENT '备注',
create_by VARCHAR(64) DEFAULT NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
UNIQUE KEY uk_wx_notify_tenant_biz (
tenant_no,
biz_type,
biz_id,
notify_date
),
KEY idx_wx_notify_tenant_time (tenant_no, create_time),
KEY idx_wx_notify_lookup (tenant_no, biz_type, biz_id, notify_date, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='微信服务号通知发送日志';
@@ -0,0 +1,93 @@
-- 细胞产品包装主数据
-- 执行前请确认目标库;可重复执行:表 IF NOT EXISTS,种子数据按编码去重
CREATE TABLE IF NOT EXISTS `biz_cell_product_package` (
`id` VARCHAR(64) NOT NULL COMMENT '主键ID',
`package_code` VARCHAR(64) NOT NULL COMMENT '包装编码',
`package_name` VARCHAR(200) NOT NULL COMMENT '包装名称',
`tenant_no` VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
`order_num` INT NULL COMMENT '排序号',
`remark` VARCHAR(512) NULL COMMENT '备注',
`create_by` VARCHAR(64) NULL COMMENT '创建人id',
`create_dept_id` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`update_by` VARCHAR(64) NULL COMMENT '更新人id',
`update_time` DATETIME NOT NULL COMMENT '更新时间',
`del_flag` SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (`id`),
KEY `idx_cell_product_package_tenant` (`tenant_no`, `del_flag`),
KEY `idx_cell_product_package_code` (`tenant_no`, `package_code`, `del_flag`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='细胞产品包装';
-- 初始包装类型(租户 zkxw;编码已存在则跳过)
INSERT INTO `biz_cell_product_package` (
`id`, `package_code`, `package_name`, `tenant_no`, `order_num`, `remark`,
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
)
SELECT * FROM (
SELECT
'PKG000000000000000000000000000001' AS `id`,
'BZ01' AS `package_code`,
'冻存管' AS `package_name`,
'zkxw' AS `tenant_no`,
1 AS `order_num`,
'' AS `remark`,
NULL AS `create_by`,
'' AS `create_dept_id`,
NOW() AS `create_time`,
NULL AS `update_by`,
NOW() AS `update_time`,
0 AS `del_flag`
) AS t
WHERE NOT EXISTS (
SELECT 1 FROM `biz_cell_product_package` p
WHERE p.`tenant_no` = 'zkxw' AND p.`package_code` = 'BZ01' AND p.`del_flag` = 0
);
INSERT INTO `biz_cell_product_package` (
`id`, `package_code`, `package_name`, `tenant_no`, `order_num`, `remark`,
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
)
SELECT * FROM (
SELECT
'PKG000000000000000000000000000002' AS `id`,
'BZ02' AS `package_code`,
'离心管' AS `package_name`,
'zkxw' AS `tenant_no`,
2 AS `order_num`,
'' AS `remark`,
NULL AS `create_by`,
'' AS `create_dept_id`,
NOW() AS `create_time`,
NULL AS `update_by`,
NOW() AS `update_time`,
0 AS `del_flag`
) AS t
WHERE NOT EXISTS (
SELECT 1 FROM `biz_cell_product_package` p
WHERE p.`tenant_no` = 'zkxw' AND p.`package_code` = 'BZ02' AND p.`del_flag` = 0
);
INSERT INTO `biz_cell_product_package` (
`id`, `package_code`, `package_name`, `tenant_no`, `order_num`, `remark`,
`create_by`, `create_dept_id`, `create_time`, `update_by`, `update_time`, `del_flag`
)
SELECT * FROM (
SELECT
'PKG000000000000000000000000000003' AS `id`,
'BZ03' AS `package_code`,
'一次性塑料血袋' AS `package_name`,
'zkxw' AS `tenant_no`,
3 AS `order_num`,
'' AS `remark`,
NULL AS `create_by`,
'' AS `create_dept_id`,
NOW() AS `create_time`,
NULL AS `update_by`,
NOW() AS `update_time`,
0 AS `del_flag`
) AS t
WHERE NOT EXISTS (
SELECT 1 FROM `biz_cell_product_package` p
WHERE p.`tenant_no` = 'zkxw' AND p.`package_code` = 'BZ03' AND p.`del_flag` = 0
);
@@ -0,0 +1,234 @@
-- 修复内置工艺路线缺步骤(2026-10-22)
-- 对齐 docs/superpowers/specs/2026-10-22-cc-builtin-route-steps-fix-design.md
--
-- 现象:CC样本处理-BUILTIN 等内置路线仅有路线头、无 biz_process_route_step,
-- 导致 B* 入库编码自动派发后任务显示「样本处理 0/0」。
-- 策略:对「内置 + 无有效步骤 + 源路线有步骤」的 *-BUILTIN 路线,
-- 从源路线(route_code 去掉 -BUILTIN)深拷贝步骤及产出/数据采集等子表。
-- 幂等:仅当目标内置路线当前 0 条有效步骤时执行;已有步骤则跳过。
-- MySQL 5.7
-- 1) 需要修复的内置路线 ↔ 源路线
DROP TEMPORARY TABLE IF EXISTS tmp_builtin_route_fix;
CREATE TEMPORARY TABLE tmp_builtin_route_fix (
dst_route_id VARCHAR(64) NOT NULL,
src_route_id VARCHAR(64) NOT NULL,
tenant_no VARCHAR(64) NOT NULL,
PRIMARY KEY (dst_route_id)
) ENGINE=MEMORY;
INSERT INTO tmp_builtin_route_fix (dst_route_id, src_route_id, tenant_no)
SELECT
b.id,
(
SELECT s.id
FROM biz_process_route s
WHERE s.tenant_no = b.tenant_no
AND s.route_code = REPLACE(b.route_code, '-BUILTIN', '')
AND s.del_flag = 0
AND IFNULL(s.is_builtin, '0') = '0'
ORDER BY
CASE WHEN IFNULL(s.is_current, '0') = '1' THEN 0 ELSE 1 END,
s.update_time DESC,
s.create_time DESC
LIMIT 1
) AS src_route_id,
b.tenant_no
FROM biz_process_route b
WHERE IFNULL(b.is_builtin, '0') = '1'
AND b.del_flag = 0
AND b.route_code LIKE '%-BUILTIN'
AND NOT EXISTS (
SELECT 1
FROM biz_process_route_step st
WHERE st.route_id = b.id
AND st.del_flag = 0
);
-- 去掉找不到源、或源也无步骤的行
DELETE FROM tmp_builtin_route_fix
WHERE src_route_id IS NULL
OR NOT EXISTS (
SELECT 1
FROM biz_process_route_step st
WHERE st.route_id = tmp_builtin_route_fix.src_route_id
AND st.del_flag = 0
);
-- 2) 源步骤 → 新步骤 ID 映射
DROP TEMPORARY TABLE IF EXISTS tmp_step_id_map;
CREATE TEMPORARY TABLE tmp_step_id_map (
src_step_id VARCHAR(64) NOT NULL,
dst_step_id VARCHAR(64) NOT NULL,
dst_route_id VARCHAR(64) NOT NULL,
tenant_no VARCHAR(64) NOT NULL,
PRIMARY KEY (src_step_id)
) ENGINE=MEMORY;
INSERT INTO tmp_step_id_map (src_step_id, dst_step_id, dst_route_id, tenant_no)
SELECT
ss.id,
-- MD5+源步骤保证同语句多行不撞主键;前缀避免与历史 UUID 冲突
CONCAT('BF', UPPER(MD5(CONCAT('fix-builtin-step:', f.dst_route_id, ':', ss.id)))),
f.dst_route_id,
f.tenant_no
FROM tmp_builtin_route_fix f
INNER JOIN biz_process_route_step ss
ON ss.route_id = f.src_route_id
AND ss.del_flag = 0;
-- 3) 拷贝步骤
INSERT INTO biz_process_route_step (
id, route_id, process_id, step_order, process_code, category_id,
process_name, description, equipment_ids, equipment_name, estimated_duration,
sop_ids, sop_content, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
m.dst_step_id,
m.dst_route_id,
ss.process_id,
ss.step_order,
ss.process_code,
ss.category_id,
ss.process_name,
ss.description,
ss.equipment_ids,
ss.equipment_name,
ss.estimated_duration,
ss.sop_ids,
ss.sop_content,
ss.tenant_no,
ss.order_num,
ss.remark,
ss.create_by,
ss.create_dept_id,
NOW(),
ss.update_by,
NOW(),
0
FROM tmp_step_id_map m
INNER JOIN biz_process_route_step ss ON ss.id = m.src_step_id;
-- 4) 试剂
INSERT INTO biz_process_route_step_reagent (
id, step_id, reagent_code, reagent_name, spec, standard_usage, unit,
is_key_material, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
CONCAT('BF', UPPER(MD5(CONCAT('fix-builtin-reag:', m.dst_step_id, ':', r.id)))),
m.dst_step_id,
r.reagent_code,
r.reagent_name,
r.spec,
r.standard_usage,
r.unit,
r.is_key_material,
r.tenant_no,
r.order_num,
r.remark,
r.create_by,
r.create_dept_id,
NOW(),
r.update_by,
NOW(),
0
FROM tmp_step_id_map m
INNER JOIN biz_process_route_step_reagent r
ON r.step_id = m.src_step_id
AND r.del_flag = 0;
-- 5) 耗材
INSERT INTO biz_process_route_step_consumable (
id, step_id, consumable_code, consumable_name, spec_model, standard_usage,
unit, is_required, remark, tenant_no, order_num,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
CONCAT('BF', UPPER(MD5(CONCAT('fix-builtin-cons:', m.dst_step_id, ':', c.id)))),
m.dst_step_id,
c.consumable_code,
c.consumable_name,
c.spec_model,
c.standard_usage,
c.unit,
c.is_required,
c.remark,
c.tenant_no,
c.order_num,
c.create_by,
c.create_dept_id,
NOW(),
c.update_by,
NOW(),
0
FROM tmp_step_id_map m
INNER JOIN biz_process_route_step_consumable c
ON c.step_id = m.src_step_id
AND c.del_flag = 0;
-- 6) 产出
INSERT INTO biz_process_route_step_output (
id, step_id, output_type_id, output_name, output_barcode, tenant_no,
order_num, remark, create_by, create_dept_id, create_time, update_by,
update_time, del_flag
)
SELECT
CONCAT('BF', UPPER(MD5(CONCAT('fix-builtin-out:', m.dst_step_id, ':', o.id)))),
m.dst_step_id,
o.output_type_id,
o.output_name,
o.output_barcode,
o.tenant_no,
o.order_num,
o.remark,
o.create_by,
o.create_dept_id,
NOW(),
o.update_by,
NOW(),
0
FROM tmp_step_id_map m
INNER JOIN biz_process_route_step_output o
ON o.step_id = m.src_step_id
AND o.del_flag = 0;
-- 7) 数据采集
INSERT INTO biz_process_route_step_data_collection (
id, step_id, collection_name, unit, tenant_no, order_num, remark,
create_by, create_dept_id, create_time, update_by, update_time, del_flag
)
SELECT
CONCAT('BF', UPPER(MD5(CONCAT('fix-builtin-dc:', m.dst_step_id, ':', d.id)))),
m.dst_step_id,
d.collection_name,
d.unit,
d.tenant_no,
d.order_num,
d.remark,
d.create_by,
d.create_dept_id,
NOW(),
d.update_by,
NOW(),
0
FROM tmp_step_id_map m
INNER JOIN biz_process_route_step_data_collection d
ON d.step_id = m.src_step_id
AND d.del_flag = 0;
-- 8) 校验(人工看结果)
SELECT
b.route_code,
b.route_name,
(SELECT COUNT(*) FROM biz_process_route_step st
WHERE st.route_id = b.id AND st.del_flag = 0) AS step_count
FROM biz_process_route b
WHERE IFNULL(b.is_builtin, '0') = '1'
AND b.del_flag = 0
AND b.route_code LIKE '%-BUILTIN'
ORDER BY b.route_code;
DROP TEMPORARY TABLE IF EXISTS tmp_step_id_map;
DROP TEMPORARY TABLE IF EXISTS tmp_builtin_route_fix;
@@ -0,0 +1,44 @@
-- 交付/输注计划及产品明细增加产品包装字段(透传至生产/质检出库工单展示)
-- 可重复执行:已存在列则跳过
SET @db := DATABASE();
-- biz_pilot_infusion_schedule.package_id
SET @exists := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'biz_pilot_infusion_schedule' AND COLUMN_NAME = 'package_id'
);
SET @sql := IF(@exists = 0,
'ALTER TABLE `biz_pilot_infusion_schedule` ADD COLUMN `package_id` VARCHAR(64) NULL COMMENT ''产品包装ID'' AFTER `spec_text`',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- biz_pilot_infusion_schedule.package_text
SET @exists := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'biz_pilot_infusion_schedule' AND COLUMN_NAME = 'package_text'
);
SET @sql := IF(@exists = 0,
'ALTER TABLE `biz_pilot_infusion_schedule` ADD COLUMN `package_text` VARCHAR(200) NULL COMMENT ''产品包装名称(冗余展示)'' AFTER `package_id`',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- biz_pilot_infusion_schedule_product.package_id
SET @exists := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'biz_pilot_infusion_schedule_product' AND COLUMN_NAME = 'package_id'
);
SET @sql := IF(@exists = 0,
'ALTER TABLE `biz_pilot_infusion_schedule_product` ADD COLUMN `package_id` VARCHAR(64) NULL COMMENT ''产品包装ID'' AFTER `spec_text`',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- biz_pilot_infusion_schedule_product.package_text
SET @exists := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 'biz_pilot_infusion_schedule_product' AND COLUMN_NAME = 'package_text'
);
SET @sql := IF(@exists = 0,
'ALTER TABLE `biz_pilot_infusion_schedule_product` ADD COLUMN `package_text` VARCHAR(200) NULL COMMENT ''产品包装名称(冗余展示)'' AFTER `package_id`',
'SELECT 1');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
@@ -0,0 +1,24 @@
-- 样本编码全链路纠错审计日志(2026-10-22)
-- 对齐 docs/superpowers/specs/2026-10-22-sample-code-correction-design.md
CREATE TABLE IF NOT EXISTS biz_sample_code_correction_log (
id VARCHAR(64) NOT NULL COMMENT '主键ID',
reception_source VARCHAR(32) NOT NULL COMMENT '来源 cell_storage/research_donation',
old_sample_code VARCHAR(32) NOT NULL COMMENT '旧样本编码',
new_sample_code VARCHAR(32) NOT NULL COMMENT '新样本编码',
impact_json TEXT COMMENT '各表影响行数 JSON',
reason VARCHAR(512) DEFAULT NULL COMMENT '更正原因',
tenant_no VARCHAR(64) NOT NULL DEFAULT 'zkxw' COMMENT '租户编号',
order_num INT DEFAULT NULL COMMENT '排序号',
remark VARCHAR(512) DEFAULT NULL COMMENT '备注',
create_by VARCHAR(64) DEFAULT NULL COMMENT '创建人id',
create_dept_id VARCHAR(64) NOT NULL DEFAULT '' COMMENT '创建人部门ID',
create_time DATETIME NOT NULL COMMENT '创建时间',
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人id',
update_time DATETIME NOT NULL COMMENT '更新时间',
del_flag SMALLINT NOT NULL DEFAULT 0 COMMENT '删除标记',
PRIMARY KEY (id),
KEY idx_scc_tenant_time (tenant_no, create_time),
KEY idx_scc_tenant_old (tenant_no, old_sample_code, del_flag),
KEY idx_scc_tenant_new (tenant_no, new_sample_code, del_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='样本编码纠错审计日志';
@@ -0,0 +1,7 @@
-- OA「提到我的」未读:oa_instance_view_grant.is_read
-- 存量行置已读,避免上线后角标暴涨
ALTER TABLE `oa_instance_view_grant`
ADD COLUMN `is_read` SMALLINT NOT NULL DEFAULT 0 COMMENT '是否已读 0未读 1已读' AFTER `granted_by`;
UPDATE `oa_instance_view_grant` SET `is_read` = 1 WHERE `del_flag` = 0;
@@ -0,0 +1,41 @@
-- 样本采集通知人员角色(幂等)
-- 仅插入角色,不挂菜单、不自动绑用户;由运营在「角色管理」中挂人。
-- 对齐 docs/superpowers/specs/2026-10-23-sample-collect-wx-notify-design.md
INSERT INTO sys_role (
id,
role_name,
data_scope,
status,
tenant_no,
order_num,
remark,
create_by,
create_dept_id,
create_time,
update_by,
update_time,
del_flag
)
SELECT
REPLACE(UUID(), '-', ''),
'样本采集通知人员',
'1',
'1',
'zkxw',
0,
'协议新增样本时接收服务号模板消息',
'system',
'',
NOW(),
'system',
NOW(),
0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1
FROM sys_role r
WHERE r.tenant_no = 'zkxw'
AND r.role_name = '样本采集通知人员'
AND r.del_flag = 0
);
@@ -0,0 +1,469 @@
-- =============================================================================
-- 数据修复:马丽娜 / 邓诗婷 样本编码错乱回正
-- 基准备份:zkxw_2026-10-26_092540.sql.gz(执行前请再备份当前库)
--
-- 目标终态:
-- 马丽娜 协议 XBCC20261008000001 → 样本码 ZKZX34000964
-- + 原质检/生产/接收/入库审核/缴费(曾被误改到 1007)一并回到 964
-- 邓诗婷 协议 XBCC20261026000001 → 样本码 ZKZX34000842
-- (不含马丽娜的质检生产)
--
-- 不改:lab_storage_code、biz_cell_product.product_code、短信正文、软删历史行
--
-- 执行方式(MySQL 5.7):
-- 1) 先跑「一、执行前校验」全部 SELECT,确认与预期一致
-- 2) 再跑「二、事务修复」;任一步报错会 ROLLBACK
-- 3) 跑「三、执行后校验」
-- =============================================================================
-- ---------------------------------------------------------------------------
-- 常量(与 09:25 备份一致;若线上 ID 已变,以校验 SELECT 为准再改)
-- ---------------------------------------------------------------------------
-- 租户
-- SET @tenant = 'zkxw';
-- 马丽娜协议 / 活跃样本 / 编码池
-- 6A7CBB85EA024AF08061FD9AFB8DF6EC
-- EC3B60D2880544D9909980D36FF9704E (当前活跃,码=842)
-- BBC01CCFDCA14E7BBE3ED34CE1B1DE47 (池 964)
-- 7C4C8FEDE210453F9D2F357D4F5A46A4 (池 842)
-- 邓诗婷协议 / 活跃样本 / 编码池
-- AAF11BCC7A584B09AFCE17AA8F7B7CD4
-- 21D2D4A063064E0B850F5C807F964079 (当前活跃,码=1007)
-- 817D230359EE4DCEA0F0CB532F099F12 (池 1007)
-- 下游(属马丽娜,当前 sample_code=1007)
-- reception 0E69E16E7E9C4B3AA9D894622BBE237B
-- qc_wo 019FC51312BB4225901014BE90A3AB2E
-- prod_wo 92F20C8B731E474985BB2C6D74A2BA3A
/* =============================================================================
一、执行前校验(只读)—— 全部应对上,再执行第二节
============================================================================= */
SELECT '【预检1】活跃协议样本(期望:马丽娜=842 一条;邓诗婷=1007 一条;964 无活跃)' AS step;
SELECT ps.id,
ps.sample_code,
ps.sample_code_id,
ps.collection_protocol_id,
cp.protocol_no,
ppc.mother_name,
ps.del_flag,
ps.update_time
FROM biz_protocol_sample ps
JOIN biz_collection_protocol cp ON cp.id = ps.collection_protocol_id AND cp.del_flag = 0
LEFT JOIN biz_protocol_party_customer ppc
ON ppc.collection_protocol_id = ps.collection_protocol_id AND ppc.del_flag = 0
WHERE ps.tenant_no = 'zkxw'
AND ps.del_flag = 0
AND ps.sample_code IN ('ZKZX34000842', 'ZKZX34000964', 'ZKZX34001007')
ORDER BY ps.sample_code, ps.create_time;
SELECT '【预检2】马丽娜下游当前码(期望均为 1007,协议仍为马丽娜)' AS step;
SELECT 'reception' AS tbl, id, sample_code, protocol_sample_id, collection_protocol_id, lab_storage_code
FROM biz_sample_reception
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND collection_protocol_id = '6A7CBB85EA024AF08061FD9AFB8DF6EC'
UNION ALL
SELECT 'qc_wo', id, sample_code, protocol_sample_id, collection_protocol_id, work_order_no
FROM biz_qc_work_order
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND collection_protocol_id = '6A7CBB85EA024AF08061FD9AFB8DF6EC'
UNION ALL
SELECT 'prod_wo', id, sample_code, protocol_sample_id, collection_protocol_id, work_order_no
FROM biz_production_work_order
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND collection_protocol_id = '6A7CBB85EA024AF08061FD9AFB8DF6EC'
UNION ALL
SELECT 'storage_rev', id, sample_code, NULL, protocol_id, protocol_no
FROM biz_storage_release_review
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND protocol_id = '6A7CBB85EA024AF08061FD9AFB8DF6EC';
SELECT '【预检3】码分布计数(活跃)' AS step;
SELECT sample_code, COUNT(*) AS cnt
FROM biz_protocol_sample
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND sample_code IN ('ZKZX34000842', 'ZKZX34000964', 'ZKZX34001007')
GROUP BY sample_code;
SELECT sample_code, COUNT(*) AS qc_task_cnt
FROM biz_qc_task
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND sample_code IN ('ZKZX34000842', 'ZKZX34000964', 'ZKZX34001007')
GROUP BY sample_code;
SELECT sample_code, collection_protocol_id, COUNT(*) AS pay_cnt
FROM biz_protocol_sample_payment
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND sample_code IN ('ZKZX34000842', 'ZKZX34000964', 'ZKZX34001007')
GROUP BY sample_code, collection_protocol_id;
/* =============================================================================
二、事务修复
A 马丽娜 842 → 964(仅协议侧;下游此时在 1007,不会被带走)
B 马丽娜协议下 1007 → 964(质检/生产/缴费等,按协议 ID 定向)
C 邓诗婷 1007 → 842
============================================================================= */
START TRANSACTION;
-- 说明:库内同时存在 utf8mb4_unicode_ci / utf8mb4_general_ci 列。
-- 字符串比较一律用 BINARY,避免会话变量 collation 混用报错。
SET NAMES utf8mb4;
SET @now := NOW();
SET @operator := 'data_fix_20261026';
SET @marina_sample_id := NULL;
SET @deng_sample_id := NULL;
SELECT id INTO @marina_sample_id
FROM biz_protocol_sample
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34000842'
LIMIT 1;
SELECT id INTO @deng_sample_id
FROM biz_protocol_sample
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY 'AAF11BCC7A584B09AFCE17AA8F7B7CD4'
AND BINARY sample_code = BINARY 'ZKZX34001007'
LIMIT 1;
SET @gate := 0;
SELECT IF(@marina_sample_id IS NULL OR @marina_sample_id = '', 1, 0)
+ IF(@deng_sample_id IS NULL OR @deng_sample_id = '', 1, 0)
+ (SELECT COUNT(*) FROM biz_protocol_sample
WHERE del_flag = 0 AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY sample_code = BINARY 'ZKZX34000964')
+ (SELECT COUNT(*) FROM biz_protocol_sample
WHERE del_flag = 0 AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY sample_code = BINARY 'ZKZX34000842'
AND id <> @marina_sample_id)
INTO @gate;
SELECT @marina_sample_id AS marina_sample_id,
@deng_sample_id AS deng_sample_id,
@gate AS gate_should_be_0;
SET @__abort := (0 + 1) / IF(@gate = 0, 1, 0);
/* ---------- A. 马丽娜活跃样本 842 → 964 + 编码池切换 ---------- */
UPDATE biz_protocol_sample
SET sample_code = 'ZKZX34000964',
sample_code_id = 'BBC01CCFDCA14E7BBE3ED34CE1B1DE47',
update_by = @operator,
update_time = @now
WHERE id = @marina_sample_id
AND del_flag = 0
AND BINARY sample_code = BINARY 'ZKZX34000842';
UPDATE biz_sample_code
SET issued = 1, update_by = @operator, update_time = @now
WHERE BINARY id = BINARY 'BBC01CCFDCA14E7BBE3ED34CE1B1DE47'
AND BINARY tenant_no = BINARY 'zkxw' AND del_flag = 0;
UPDATE biz_sample_code
SET issued = 0, update_by = @operator, update_time = @now
WHERE BINARY id = BINARY '7C4C8FEDE210453F9D2F357D4F5A46A4'
AND BINARY tenant_no = BINARY 'zkxw' AND del_flag = 0
AND NOT EXISTS (
SELECT 1 FROM biz_protocol_sample
WHERE del_flag = 0 AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY sample_code_id = BINARY '7C4C8FEDE210453F9D2F357D4F5A46A4'
AND id <> @marina_sample_id
);
UPDATE biz_protocol_sample_transport
SET sample_code = 'ZKZX34000964',
sample_id = @marina_sample_id,
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34000842';
INSERT INTO biz_sample_code_correction_log (
id, reception_source, old_sample_code, new_sample_code, impact_json, reason,
tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag
) VALUES (
REPLACE(UUID(), '-', ''),
'cell_storage', 'ZKZX34000842', 'ZKZX34000964',
JSON_OBJECT(
'biz_protocol_sample', 1,
'biz_sample_code', 1,
'biz_protocol_sample_transport', 1,
'note', 'stepA_marina_protocol_only'
),
'数据修复:马丽娜协议样本 842→964(下游另按协议定向迁移)',
'zkxw', 0, 'fix_marina_deng_20261026_stepA',
@operator, '', @now, @operator, @now, 0
);
/* ---------- B. 马丽娜协议下 1007 → 964(质检/生产/缴费) ---------- */
UPDATE biz_sample_reception
SET sample_code = 'ZKZX34000964',
protocol_sample_id = @marina_sample_id,
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_qc_work_order
SET sample_code = 'ZKZX34000964',
protocol_sample_id = @marina_sample_id,
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_qc_task t
JOIN biz_qc_work_order w
ON w.id = t.work_order_id
AND w.del_flag = 0
AND BINARY w.tenant_no = BINARY 'zkxw'
AND BINARY w.collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
SET t.sample_code = 'ZKZX34000964',
t.update_by = @operator,
t.update_time = @now
WHERE t.del_flag = 0
AND BINARY t.tenant_no = BINARY 'zkxw'
AND BINARY t.sample_code = BINARY 'ZKZX34001007';
UPDATE biz_production_work_order
SET sample_code = 'ZKZX34000964',
protocol_sample_id = @marina_sample_id,
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_sample_production_reception pr
JOIN biz_sample_reception r
ON r.id = pr.reception_id
AND r.del_flag = 0
AND BINARY r.tenant_no = BINARY 'zkxw'
AND BINARY r.collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
SET pr.sample_code = 'ZKZX34000964',
pr.update_by = @operator,
pr.update_time = @now
WHERE pr.del_flag = 0
AND BINARY pr.tenant_no = BINARY 'zkxw'
AND BINARY pr.sample_code = BINARY 'ZKZX34001007';
UPDATE biz_production_task_input ti
JOIN biz_production_task pt
ON pt.id = ti.task_id AND pt.del_flag = 0 AND BINARY pt.tenant_no = BINARY 'zkxw'
JOIN biz_production_work_order pw
ON pw.id = pt.work_order_id
AND pw.del_flag = 0
AND BINARY pw.tenant_no = BINARY 'zkxw'
AND BINARY pw.collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
SET ti.input_code = 'ZKZX34000964',
ti.update_by = @operator,
ti.update_time = @now
WHERE ti.del_flag = 0
AND BINARY ti.tenant_no = BINARY 'zkxw'
AND BINARY ti.input_type = BINARY 'sample'
AND BINARY ti.input_code = BINARY 'ZKZX34001007';
UPDATE biz_storage_release_review
SET sample_code = 'ZKZX34000964',
sample_name = 'ZKZX34000964',
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_protocol_sample_payment
SET sample_code = 'ZKZX34000964',
protocol_sample_id = @marina_sample_id,
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_protocol_payment_schedule
SET sample_code = 'ZKZX34000964',
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_protocol_payment_transfer
SET sample_code = 'ZKZX34000964',
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY '6A7CBB85EA024AF08061FD9AFB8DF6EC'
AND BINARY sample_code = BINARY 'ZKZX34001007';
INSERT INTO biz_sample_code_correction_log (
id, reception_source, old_sample_code, new_sample_code, impact_json, reason,
tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag
) VALUES (
REPLACE(UUID(), '-', ''),
'cell_storage', 'ZKZX34001007', 'ZKZX34000964',
JSON_OBJECT('note', 'stepB_marina_downstream_by_protocol'),
'数据修复:马丽娜下游质检/生产/缴费 1007→964(按协议定向,不含邓诗婷)',
'zkxw', 0, 'fix_marina_deng_20261026_stepB',
@operator, '', @now, @operator, @now, 0
);
/* ---------- C. 邓诗婷 1007 → 842 ---------- */
SELECT COUNT(*) INTO @deng_1007_left_qc
FROM biz_qc_work_order
WHERE del_flag = 0 AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY sample_code = BINARY 'ZKZX34001007';
SELECT COUNT(*) INTO @deng_1007_left_prod
FROM biz_production_work_order
WHERE del_flag = 0 AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY sample_code = BINARY 'ZKZX34001007';
SET @gate2 := IF(@deng_1007_left_qc + @deng_1007_left_prod = 0, 0, 1)
+ (SELECT COUNT(*) FROM biz_protocol_sample
WHERE del_flag = 0 AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY sample_code = BINARY 'ZKZX34000842');
SELECT @deng_1007_left_qc AS leftover_qc_on_1007,
@deng_1007_left_prod AS leftover_prod_on_1007,
@gate2 AS gate2_should_be_0;
SET @__abort2 := (0 + 1) / IF(@gate2 = 0, 1, 0);
UPDATE biz_protocol_sample
SET sample_code = 'ZKZX34000842',
sample_code_id = '7C4C8FEDE210453F9D2F357D4F5A46A4',
update_by = @operator,
update_time = @now
WHERE id = @deng_sample_id
AND del_flag = 0
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_sample_code
SET issued = 1, update_by = @operator, update_time = @now
WHERE BINARY id = BINARY '7C4C8FEDE210453F9D2F357D4F5A46A4'
AND BINARY tenant_no = BINARY 'zkxw' AND del_flag = 0;
UPDATE biz_sample_code
SET issued = 0, update_by = @operator, update_time = @now
WHERE BINARY id = BINARY '817D230359EE4DCEA0F0CB532F099F12'
AND BINARY tenant_no = BINARY 'zkxw' AND del_flag = 0
AND NOT EXISTS (
SELECT 1 FROM biz_protocol_sample
WHERE del_flag = 0 AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY sample_code_id = BINARY '817D230359EE4DCEA0F0CB532F099F12'
);
UPDATE biz_protocol_sample_payment
SET sample_code = 'ZKZX34000842',
protocol_sample_id = @deng_sample_id,
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY 'AAF11BCC7A584B09AFCE17AA8F7B7CD4'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_protocol_payment_schedule
SET sample_code = 'ZKZX34000842',
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY 'AAF11BCC7A584B09AFCE17AA8F7B7CD4'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_protocol_payment_transfer
SET sample_code = 'ZKZX34000842',
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY 'AAF11BCC7A584B09AFCE17AA8F7B7CD4'
AND BINARY sample_code = BINARY 'ZKZX34001007';
UPDATE biz_protocol_sample_transport
SET sample_code = 'ZKZX34000842',
sample_id = @deng_sample_id,
update_by = @operator,
update_time = @now
WHERE del_flag = 0
AND BINARY tenant_no = BINARY 'zkxw'
AND BINARY collection_protocol_id = BINARY 'AAF11BCC7A584B09AFCE17AA8F7B7CD4'
AND BINARY sample_code = BINARY 'ZKZX34001007';
INSERT INTO biz_sample_code_correction_log (
id, reception_source, old_sample_code, new_sample_code, impact_json, reason,
tenant_no, order_num, remark, create_by, create_dept_id, create_time, update_by, update_time, del_flag
) VALUES (
REPLACE(UUID(), '-', ''),
'cell_storage', 'ZKZX34001007', 'ZKZX34000842',
JSON_OBJECT('note', 'stepC_deng_1007_to_842'),
'数据修复:邓诗婷协议样本 1007→842',
'zkxw', 0, 'fix_marina_deng_20261026_stepC',
@operator, '', @now, @operator, @now, 0
);
COMMIT;
/* =============================================================================
三、执行后校验(期望)
- 马丽娜活跃样本 = 964;质检/生产 sample_code = 964;protocol_sample_id = 马丽娜活跃样本
- 邓诗婷活跃样本 = 842;无 ZJ202610090001 / SC202610090001
- 1007 无活跃协议样本
============================================================================= */
SELECT '【验1】活跃样本归属' AS step;
SELECT ps.sample_code, cp.protocol_no, ppc.mother_name, ps.id AS protocol_sample_id
FROM biz_protocol_sample ps
JOIN biz_collection_protocol cp ON cp.id = ps.collection_protocol_id
LEFT JOIN biz_protocol_party_customer ppc
ON ppc.collection_protocol_id = ps.collection_protocol_id AND ppc.del_flag = 0
WHERE ps.tenant_no = 'zkxw' AND ps.del_flag = 0
AND ps.sample_code IN ('ZKZX34000842', 'ZKZX34000964', 'ZKZX34001007')
ORDER BY ps.sample_code;
SELECT '【验2】马丽娜下游' AS step;
SELECT 'qc_wo' AS tbl, work_order_no, sample_code, protocol_sample_id, collection_protocol_id, conclusion
FROM biz_qc_work_order
WHERE id = '019FC51312BB4225901014BE90A3AB2E'
UNION ALL
SELECT 'prod_wo', work_order_no, sample_code, protocol_sample_id, collection_protocol_id, work_order_status
FROM biz_production_work_order
WHERE id = '92F20C8B731E474985BB2C6D74A2BA3A'
UNION ALL
SELECT 'reception', id, sample_code, protocol_sample_id, collection_protocol_id, lab_storage_code
FROM biz_sample_reception
WHERE id = '0E69E16E7E9C4B3AA9D894622BBE237B';
SELECT '【验3】三码活跃样本数(期望 842=1, 964=1, 1007=0)' AS step;
SELECT sample_code, COUNT(*) AS cnt
FROM biz_protocol_sample
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND sample_code IN ('ZKZX34000842', 'ZKZX34000964', 'ZKZX34001007')
GROUP BY sample_code;
SELECT '【验4】邓诗婷协议下不应有该质检/生产工单' AS step;
SELECT COUNT(*) AS deng_should_be_0
FROM biz_qc_work_order
WHERE tenant_no = 'zkxw' AND del_flag = 0
AND collection_protocol_id = 'AAF11BCC7A584B09AFCE17AA8F7B7CD4';
SELECT COUNT(*) AS leftover_1007_qc_should_be_0
FROM biz_qc_task
WHERE tenant_no = 'zkxw' AND del_flag = 0 AND sample_code = 'ZKZX34001007';