# 附加费用双向同步功能说明 ## 功能概述 实现新系统 `sys_task_additional_fee` 表与旧系统 `PaidMoney_Add` 表之间的附加费用双向同步,确保两个系统的附加费用数据保持一致。 ## 技术架构 ### 核心实体 #### 1. SysTaskAdditionalFee(新系统附加费用记录) - **表名**: `sys_task_additional_fee` - **新增字段**: - `pid`: 旧系统附加费用记录ID(PaidMoney_Add.id) - `sync_status`: 同步状态(0未同步,1同步中,2同步成功,3同步失败) - `sync_time`: 同步时间 #### 2. PaidMoneyAdd(旧系统附加费用记录) - **表名**: `PaidMoney_Add` - **关键字段**: - `id`: 主键 - `ToServiceOrdID`: 服务单ID - `ToDispatchOrdID`: 调度单ID - `AddMoneyType`: 附加费用类型 - `AddMoney`: 附加费用金额 - `AddMoneyExplain`: 附加费用说明 - `AddMoneyTime`: 附加费用时间 - `AddMoneyOAID`: 添加用户的OAID ### 关键关联 通过 `SysTaskEmergency` 表获取任务与旧系统订单的映射关系: - `legacy_service_ord_id` → `ToServiceOrdID` - `legacy_dispatch_ord_id` → `ToDispatchOrdID` ## 同步逻辑 ### 1. 新系统 → 旧系统同步 #### 触发时机 - 新系统添加附加费用后自动触发 #### 同步流程 1. 添加附加费用后,调用 `AdditionalFeeSyncService.syncAdditionalFeeToLegacy(feeId)` 2. 查询新系统附加费用记录和任务信息 3. 获取 `ToServiceOrdID` 和 `ToDispatchOrdID` 4. 转换费用类型(新系统 → 旧系统) 5. 构建 `PaidMoneyAdd` 对象并插入旧系统 6. 更新新系统附加费用记录的 `pid`、`sync_status`、`sync_time` #### 费用类型映射(新 → 旧) | 新系统字典值 | 旧系统AddMoneyType | 说明 | |------------|------------------|------| | 1 | 1 | 等待费 | | 2 | 2 | 担架 | | 3 | 3 | 居家ICU | | 4 | 4 | 医疗设备 | #### 数据映射 ```java PaidMoneyAdd.ToServiceOrdID = emergency.legacyServiceOrdId PaidMoneyAdd.ToDispatchOrdID = emergency.legacyDispatchOrdId PaidMoneyAdd.AddMoneyType = Integer.parseInt(fee.feeType) PaidMoneyAdd.AddMoney = fee.totalAmount PaidMoneyAdd.AddMoneyExplain = fee.feeName + (备注) PaidMoneyAdd.AddMoneyTime = fee.createdTime PaidMoneyAdd.AddMoneyOAID = user.oaUserId ``` ### 2. 旧系统 → 新系统同步 #### 触发时机 - 定时任务(每15分钟执行一次) - 手动调用 `AdditionalFeeSyncService.syncAdditionalFeeFromLegacy(paidMoneyAddId)` #### 同步流程 1. 查询旧系统 `PaidMoney_Add` 记录 2. 检查是否已同步(通过 `pid` 字段) 3. 根据 `ToServiceOrdID` 查询新系统任务 4. 验证 `ToDispatchOrdID` 是否匹配 5. 转换费用类型(旧系统 → 新系统) 6. 构建 `SysTaskAdditionalFee` 对象并插入新系统 7. 设置 `pid`、`sync_status=2`、`sync_time` #### 费用类型映射(旧 → 新) | 旧系统AddMoneyType | 新系统字典值 | 说明 | |------------------|-----------|------| | 1 | 1 | 等待费 | | 2 | 2 | 担架 | | 3 | 3 | 居家ICU | | 4 | 4 | 医疗设备 | #### 数据映射 ```java SysTaskAdditionalFee.taskId = emergency.taskId SysTaskAdditionalFee.feeType = String.valueOf(paidMoneyAdd.addMoneyType) SysTaskAdditionalFee.feeName = getFeeTypeName(feeType) SysTaskAdditionalFee.unitAmount = paidMoneyAdd.addMoney SysTaskAdditionalFee.quantity = 1 SysTaskAdditionalFee.totalAmount = paidMoneyAdd.addMoney SysTaskAdditionalFee.remark = paidMoneyAdd.addMoneyExplain SysTaskAdditionalFee.pid = paidMoneyAddId SysTaskAdditionalFee.syncStatus = 2 SysTaskAdditionalFee.syncTime = now() ``` ## 核心代码实现 ### 文件清单 #### 新增文件 1. **实体类** - `PaidMoneyAdd.java` - 旧系统附加费用记录实体 2. **Mapper接口** - `PaidMoneyAddMapper.java` - 旧系统附加费用记录Mapper接口 3. **Mapper XML** - `PaidMoneyAddMapper.xml` - 旧系统附加费用记录SQL映射 4. **Service接口** - `IAdditionalFeeSyncService.java` - 附加费用同步服务接口 5. **Service实现** - `AdditionalFeeSyncServiceImpl.java` - 附加费用同步服务实现 6. **数据库脚本** - `additional_fee_sync_update.sql` - 数据表更新脚本 #### 修改文件 1. **实体类** - `SysTaskAdditionalFee.java` - 新增 pid、syncStatus、syncTime 字段 2. **Mapper接口** - `SysTaskAdditionalFeeMapper.java` - 新增 selectByPid、updateSyncInfo、selectUnsyncedFees 方法 3. **Mapper XML** - `SysTaskAdditionalFeeMapper.xml` - 更新映射和新增查询方法 4. **Service实现** - `SysTaskPaymentServiceImpl.java` - 添加附加费用后触发同步 5. **定时任务** - `LegacySystemSyncTask.java` - 新增附加费用同步定时任务方法 ## 数据源配置 使用 `@DataSource` 注解切换数据源: ```java // 访问新系统数据库(默认) public void processNewSystem() { // 默认使用主数据源 } // 访问旧系统数据库 @DataSource(DataSourceType.SQLSERVER) public void processLegacySystem() { // 使用SQL Server数据源 } ``` ## 同步状态管理 ### sync_status 状态值 - **0 - 未同步**: 新创建的附加费用记录,尚未同步到旧系统 - **1 - 同步中**: 正在执行同步操作 - **2 - 同步成功**: 已成功同步到旧系统 - **3 - 同步失败**: 同步过程中发生错误 ### 状态流转 ``` 新附加费用记录 → 0(未同步) → 1(同步中) → 2(同步成功) 或 3(同步失败) ↓ 可重试 ``` ## 异常处理 ### 同步失败场景 1. 任务未同步到旧系统(缺少 ToServiceOrdID/ToDispatchOrdID) 2. 旧系统数据库连接失败 3. 数据插入冲突或约束违反 4. 网络异常 ### 处理策略 1. 同步失败时标记 `sync_status=3` 2. 记录详细错误日志 3. 不影响主业务流程(异步同步) 4. 可通过定时任务或手动触发重试 ## 使用示例 ### 手动触发同步 ```java @Autowired private IAdditionalFeeSyncService additionalFeeSyncService; // 同步单条附加费用到旧系统 boolean success = additionalFeeSyncService.syncAdditionalFeeToLegacy(feeId); // 从旧系统同步附加费用 boolean success = additionalFeeSyncService.syncAdditionalFeeFromLegacy(paidMoneyAddId); // 批量同步 int count = additionalFeeSyncService.batchSyncAdditionalFeeToLegacy(); int count = additionalFeeSyncService.batchSyncAdditionalFeeFromLegacy(24); // 同步24小时内的记录 ``` ### 配置定时任务 #### 新系统 → 旧系统同步 ``` 任务名称: 附加费用同步 任务组名: DEFAULT 调用目标: legacySystemSyncTask.syncAdditionalFeeToLegacy() cron表达式: 0 0/10 * * * ? (每10分钟执行一次) ``` #### 旧系统 → 新系统同步 ``` 任务名称: 附加费用反向同步 任务组名: DEFAULT 调用目标: legacySystemSyncTask.syncAdditionalFeeFromLegacy() cron表达式: 0 0/15 * * * ? (每15分钟执行一次) ``` ## 数据库更新 执行 SQL 脚本: ```sql source sql/additional_fee_sync_update.sql ``` ## 注意事项 1. **前置条件**: 任务必须已经同步到旧系统(有 ServiceOrdID 和 DispatchOrdID) 2. **费用类型**: 使用统一的字典值(1-等待费, 2-担架, 3-居家ICU, 4-医疗设备) 3. **同步间隔**: 新系统→旧系统立即同步,旧系统→新系统定时同步 4. **错误处理**: 同步失败不影响主业务,可以重试 5. **性能优化**: 批量同步限制每次100条记录,每条记录间隔1秒 ## 验证测试 ### 测试步骤 1. **新增附加费用(新系统 → 旧系统)** - 在APP中为转运任务添加附加费用 - 检查新系统 `sys_task_additional_fee` 表的 `sync_status` 字段 - 检查旧系统 `PaidMoney_Add` 表是否有对应记录 2. **旧系统新增附加费用(旧系统 → 新系统)** - 在旧系统中添加附加费用记录 - 运行定时任务或手动调用同步方法 - 检查新系统 `sys_task_additional_fee` 表是否有对应记录 ### 查询验证SQL ```sql -- 查看新系统附加费用及同步状态 SELECT id, task_id, fee_type, fee_name, total_amount, sync_status, pid FROM sys_task_additional_fee WHERE task_id = ?; -- 查看旧系统附加费用(在SQL Server中执行) SELECT id, ToServiceOrdID, ToDispatchOrdID, AddMoneyType, AddMoney, AddMoneyExplain FROM PaidMoney_Add WHERE ToServiceOrdID = ? AND ToDispatchOrdID = ?; -- 查看未同步的附加费用 SELECT * FROM sys_task_additional_fee WHERE (sync_status = 0 OR sync_status = 3 OR sync_status IS NULL); ``` ## 技术要点 1. **双向同步**: 支持新旧系统之间的双向数据同步 2. **幂等性**: 通过 pid 字段避免重复同步 3. **事务性**: 使用 @Transactional 确保数据一致性 4. **异步处理**: 同步不阻塞主业务流程 5. **错误重试**: 支持失败记录的重新同步