-- 评估端发票申请:基本信息行级开票金额(手工在目标库执行,仓库无迁移框架) -- 目标库:xg_saas -- -- 【部署顺序 —— 必须严格遵守】 -- 1) 先执行本脚本的 ALTER TABLE -- 2) 再执行回填 UPDATE -- 3) 然后才部署后端(jeeplus-assess) -- 4) 最后部署前端 -- -- 原因:FinanceInvoiceBase 实体新增 account 字段后,MyBatis-Plus 的 selectList/selectById -- 会按实体字段拼 SELECT 列清单。若先上代码后加列,以下 7 处查询会全部报 -- Unknown column 'account' in 'field list': -- FinanceInvoiceService.java:233 / 257 findList——发票列表按项目名、报告号筛选 -- FinanceInvoiceService.java:1313 / 1337 findRedList——红冲发票列表 -- FinanceInvoiceService.java:1963 updateProjectArchiveByInvoiceId——开票后回写归档 -- is_invoice / invoice_date(外层 try/catch 吞异常,会静默失效) -- FinanceInvoiceService.java:2238 batchMatchInvoices——台账导入导出的发票匹配 -- ProjectListService.java:2513 importProvincialFiling——项目备案导入 -- 反之,先加列不上代码则完全无影响(列可空,旧代码不读它)。 -- ---------------------------- -- 1. 新增列 -- ---------------------------- -- 类型对齐会计端 cw_finance_invoice_base.account(varchar(64)), -- 实体与 DTO 均为 String,MapStruct 同名自动映射。 ALTER TABLE `finance_invoice_base` ADD COLUMN `account` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '发票金额(元)——该条项目/报告行的开票金额,各行合计应等于 finance_invoice.account' AFTER `report_no`; -- ---------------------------- -- 2. 历史数据回填 -- ---------------------------- -- 只回填「仅有一条基本信息行」的历史单据:这类单据不存在金额分配歧义, -- 行金额必然等于主表全额,回填后完全对齐新模型。 -- -- 一票挂多个项目/报告的历史单据(base 行数 > 1)保持 NULL: -- 没有任何数据能推断各项目分别开了多少,只能由业务人工补录。 -- 后端校验与前端汇总对这类单据均放行(全 NULL 视为历史未拆分单据, -- 保留主表 account 原值,不覆盖为 0)。 -- -- 用派生表而非同表子查询:MySQL 不允许在 UPDATE 的子查询里引用被更新的同一张表。 -- WHERE b.account IS NULL 保证脚本可重复执行。 UPDATE `finance_invoice_base` b JOIN ( SELECT `invoice_id` FROM `finance_invoice_base` WHERE `del_flag` = 0 GROUP BY `invoice_id` HAVING COUNT(*) = 1 ) single ON single.`invoice_id` = b.`invoice_id` JOIN `finance_invoice` f ON f.`id` = b.`invoice_id` AND f.`del_flag` = 0 SET b.`account` = f.`account` WHERE b.`del_flag` = 0 AND b.`account` IS NULL AND f.`account` IS NOT NULL AND TRIM(f.`account`) <> ''; -- ---------------------------- -- 3. 执行后核对(只读,不改数据) -- ---------------------------- -- 3.1 回填覆盖情况:按 base 行数分组统计 -- SELECT -- CASE WHEN cnt = 1 THEN '单行单据' ELSE '多行单据(需人工补录)' END AS 类型, -- COUNT(*) AS 发票数, -- SUM(filled) AS 已填行金额的发票数 -- FROM ( -- SELECT b.invoice_id, -- COUNT(*) AS cnt, -- MAX(CASE WHEN b.account IS NOT NULL AND TRIM(b.account) <> '' THEN 1 ELSE 0 END) AS filled -- FROM finance_invoice_base b -- WHERE b.del_flag = 0 -- GROUP BY b.invoice_id -- ) t -- GROUP BY CASE WHEN cnt = 1 THEN '单行单据' ELSE '多行单据(需人工补录)' END; -- 3.2 一致性校验:已填行金额的单据,各行合计是否等于主表金额 -- 正常应返回 0 行。若有返回,说明历史数据本身主表与明细就不一致,需人工核对。 -- SELECT b.invoice_id, -- f.account AS 主表金额, -- SUM(CAST(NULLIF(TRIM(b.account), '') AS DECIMAL(18,2))) AS 行金额合计 -- FROM finance_invoice_base b -- JOIN finance_invoice f ON f.id = b.invoice_id AND f.del_flag = 0 -- WHERE b.del_flag = 0 -- AND b.account IS NOT NULL AND TRIM(b.account) <> '' -- GROUP BY b.invoice_id, f.account -- HAVING ABS(IFNULL(SUM(CAST(NULLIF(TRIM(b.account), '') AS DECIMAL(18,2))), 0) -- - CAST(NULLIF(TRIM(f.account), '') AS DECIMAL(18,2))) > 0.005; -- 3.3 列出需要人工补录的多行历史单据(供业务排期) -- SELECT f.no AS 发票申请编号, f.account AS 发票总金额, COUNT(*) AS 项目行数, -- GROUP_CONCAT(b.program_name SEPARATOR ' / ') AS 关联项目 -- FROM finance_invoice_base b -- JOIN finance_invoice f ON f.id = b.invoice_id AND f.del_flag = 0 -- WHERE b.del_flag = 0 -- GROUP BY f.no, f.account, b.invoice_id -- HAVING COUNT(*) > 1 -- AND MAX(CASE WHEN b.account IS NOT NULL AND TRIM(b.account) <> '' THEN 1 ELSE 0 END) = 0; -- ---------------------------- -- 4. 回滚(仅在部署失败需要退回旧代码时执行) -- ---------------------------- -- 旧代码不读该列,正常情况下无需回滚;加列本身对旧版本无害。 -- 若确实要移除: -- ALTER TABLE `finance_invoice_base` DROP COLUMN `account`;