You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

41 lines
2.0 KiB

fix(botp): 打通「转换 → 手动保存 → 反写」链路并修复反写失效 - 移除转换时的反写触发:删除 ConvertOrchestrator#triggerSaveWriteBack 及其 WriteBackOrchestrator 依赖。转换只负责「源单 → 目标单」的数据复制,原实现在 autoSave 落库后补触发反写,等于把刚复制过去的值按规则再写回来,累加类公式让源单数量指数增长 (1→2→4→8→24),覆盖类公式把源单字段改成复制值。反写改由目标单被真正操作时触发, 入口已存在:SaveOperationServicePlugIn(保存)、AuditOperationServicePlugIn(审核), 时机由 reverse_writing_rules.trigger_timing 决定('1' 保存 / '2' 审核) - 转换关系改用落库后的真实主键:BotpService#addNew 落库前收集分录「预发主键 → 对象实例」, 落库后读真实主键建立映射,saveRelation 用它覆盖 targe_entry_id。根因是 initDestBillData 建骨架时预发主键,而 ormGenDataSourceUtil.addNew 插入分录时会重新发号, 关系表存的是库里不存在的 id,反写按 targe_entry_id 查目标分录必然为空而静默跳过。 新增 BtpTransformResult#entryIdMap 承载映射,校正时打 INFO 记录「计划id / 实际id」 - 批量保存回写真实主键:新增 syncSavedIds,exePlugin 落库后把 ORM 回写的真实主键同步回 入参 JSON(表头直接覆盖,分录按 key 顺序 + 行下标对齐,与 getObjectValue 的入栈顺序一致)。 不回写的话 executeBatchSaveInTransaction 补写 convert_relation 时用预发 id, 关系指向不存在的记录,用户改单保存触发反写就会「找不到关联关系」。 实测:payload 里 header id=...101824 / entry id=...101825, 库里实际 ...04651520 / ...34011648 - 新增转换关系补写门面:BotpConvertRelationFacade(common-core 接口)+ ConvertRelationFacade(common-botp 实现),按 BillRelation JSON 补写 convert_relation / convert_relation_entry,target_id 以落库后真实主键覆盖,按主键幂等。 为什么需要:convert_relation 只在 BotpService#transform 的 autoSave 分支写入, formStatus=2(未落库、前端手动保存)时转换阶段不写关系,保存后反写找不到来源单。 ConvertedBill 新增 billRelation,buildBatchSavePayload 内嵌到 masterData[i].billRelation, 父子关系由结构而非下标保证;executeBatchSave 摘出该键(不能当表头字段交给 ORM)。 executeBatchSaveInTransaction 增加 relationList 参数,落库后调 saveRelationQuietly 补写, 与保存在同一事务内。BotpReverseWriteSupport 泛化 getFacadeQuietly 支持按类型取门面, 未挂载 botp 的应用静默跳过 - 修正反写公式读写方向:formula(formulaEnglish) 指回写位置(源单), sourceSingleField 指取值位置(目标单),原实现写反了,表现为「反写执行了但源单没变」。 变量统一改为 read(目标单,取值)/ write(源单,回写),避免后续再被读反 - 新增 isHeadTable:公式引用表头字段时用单据 id 查,引用分录字段时用分录行 id 查。 原先一律用分录 id,配成 请购单.请购单.供应商 这类表头字段时永远查不到行 - 新增 syncNonNumericValue:供应商、名称等文本字段无法做 BigDecimal 运算 (toBigDecimal 返回 null,nullToZero 后变成 0),改为正向直接把目标单值写到源单, 回滚按 before_value 恢复;目标单字段为空时跳过并告警,不把源单写空 - recordBeforeValue 改用 LambdaUpdateWrapper 显式 set:beforeValue 为 null 时 MyBatis-Plus 会跳过 null 字段,生成 UPDATE ... WHERE id=? 这种无 SET 的非法 SQL - 新增 resolveEntryTableQuietly(key 兼容 tableId 与表名,解析不到返回 null 不抛) 与 toJsonRowList(分录值兼容数组与单行对象),用于主键回写 - 反写跳过日志补上表名与行 id,原先只打 id,无法判断查的是表头还是分录 - 新增 zz-resource/db-scripts/2026-10-27-convert-relation-entry-writeback-script.sql: 补 convert_relation_entry 的 before_value(decimal(24,8))与 writeback_rule_version(int)。 实体早已声明这两个字段(注释也写明「需要新增列」)但 DDL 未跟上,MyBatis-Plus 按实体 拼 SELECT,任何查询该表的 SQL 都会报 Unknown column 'before_value' in 'field list', 反写与转换落库都会直接失败。脚本用 information_schema 判断列是否存在,可重复执行
2 days ago
-- ----------------------------
-- convert_relation_entry 补反写回滚所需的两个字段。
--
-- 背景:ConvertRelationEntry 实体上声明了 beforeValue / writebackRuleVersion,
-- 但 DDL 没跟上,MyBatis-Plus 查询会带上这两列,导致
-- Unknown column 'before_value' in 'field list'
-- 反写(WriteBackOrchestrator#loadRelationEntries)与转换落库都会直接报错。
--
-- 请在 tenant-admin 服务指向的默认数据库执行该脚本;脚本可重复执行。
-- ----------------------------
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- 1. before_value:反写前的源单字段原值。
-- 只有「覆盖」方式需要——累加/扣减天然可逆,覆盖把原值冲掉了,不记下来撤销时就回不去。
-- ----------------------------
SET @ddl = (SELECT IF(COUNT(*) = 0,
'ALTER TABLE `convert_relation_entry` ADD COLUMN `before_value` decimal(24,8) DEFAULT NULL COMMENT ''反写前的源单字段原值,仅覆盖方式使用,供撤销回滚恢复''',
'DO 0')
FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'convert_relation_entry' AND column_name = 'before_value');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
-- ----------------------------
-- 2. writeback_rule_version:本次反写实际使用的反写规则版本。
-- 撤销/弃审时按该版本取快照执行,保证「怎么加的就怎么退」。
-- ----------------------------
SET @ddl = (SELECT IF(COUNT(*) = 0,
'ALTER TABLE `convert_relation_entry` ADD COLUMN `writeback_rule_version` int DEFAULT NULL COMMENT ''本次反写使用的反写规则版本,供撤销回滚按同一版本执行''',
'DO 0')
FROM information_schema.columns
WHERE table_schema = DATABASE() AND table_name = 'convert_relation_entry' AND column_name = 'writeback_rule_version');
PREPARE stmt FROM @ddl;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET FOREIGN_KEY_CHECKS = 1;