# 支付信息双向同步功能说明 ## 功能概述 实现新系统 `sys_task_payment` 表与旧系统 `PaidMoney` 表之间的支付信息双向同步,确保两个系统的支付数据保持一致。 ## 技术架构 ### 核心实体 #### 1. SysTaskPayment(新系统支付记录) - **表名**: `sys_task_payment` - **新增字段**: - `pid`: 旧系统支付记录ID(PaidMoney.id) - `sync_status`: 同步状态(0未同步,1同步中,2同步成功,3同步失败) - `sync_time`: 同步时间 #### 2. PaidMoney(旧系统支付记录) - **表名**: `PaidMoney` - **关键字段**: - `id`: 主键 - `ServiceOrdIDDt`: 服务订单ID - `DispatchOrdIDDt`: 调度订单ID - `PaidMoney`: 支付金额 - `PaidMoneyType`: 支付类型 - `PaidMoneyMono`: 支付单号 - `PaidMoneyTime`: 支付时间 - `PaidMoneyOaID`: 支付人OAID ### 关键关联 通过 `SysTaskEmergency` 表获取任务与旧系统订单的映射关系: - `legacy_service_ord_id` → `ServiceOrdIDDt` - `legacy_dispatch_ord_id` → `DispatchOrdIDDt` ## 同步逻辑 ### 1. 新系统 → 旧系统同步 #### 触发时机 - 新系统支付成功后自动触发 - 包括:现金支付、挂账、微信支付成功、支付宝支付成功 #### 同步流程 1. 支付成功后,调用 `PaymentSyncService.syncPaymentToLegacy(paymentId)` 2. 查询新系统支付记录和任务信息 3. 获取 `ServiceOrdIDDt` 和 `DispatchOrdIDDt` 4. 转换支付方式(新系统 → 旧系统) 5. 构建 `PaidMoney` 对象并插入旧系统 6. 更新新系统支付记录的 `pid`、`sync_status`、`sync_time` #### 支付方式映射(新 → 旧) | 新系统支付方式 | 旧系统支付类型 | 说明 | |--------------|--------------|------| | CASH | 1 | 现金 | | ON_ACCOUNT | 6 | 挂账 | | WECHAT | 3 | 微信支付 | | ALIPAY | 4 | 支付宝 | #### 数据映射 ```java PaidMoney.PaidMoneyClass = "FI" // 默认FI PaidMoney.ServiceOrdIDDt = emergency.legacyServiceOrdId PaidMoney.DispatchOrdIDDt = emergency.legacyDispatchOrdId PaidMoney.PaidMoney = payment.settlementAmount PaidMoney.PaidMoneyType = convertPaymentMethodToLegacy(payment.paymentMethod) PaidMoney.PaidMoneyMono = payment.tradeNo 或 payment.outTradeNo PaidMoney.PaidMoneyTime = payment.payTime PaidMoney.PaidMoneyOaID = user.oaUserId PaidMoney.PaidMoneyUnitID = 0 // 默认0 PaidMoney.PaidMoneyAPCheck = 1 // 已确认 PaidMoney.PaidMoneyAPTime = now() ``` ### 2. 旧系统 → 新系统同步 #### 触发时机 - 定时任务(待实现) - 手动调用 `PaymentSyncService.syncPaymentFromLegacy(paidMoneyId)` #### 同步流程 1. 查询旧系统 `PaidMoney` 记录 2. 检查是否已同步(通过 `pid` 字段) 3. 根据 `ServiceOrdIDDt` 查询新系统任务 4. 转换支付方式(旧系统 → 新系统) 5. 构建 `SysTaskPayment` 对象并插入新系统 6. 设置 `pid`、`sync_status=2`、`sync_time` #### 支付方式映射(旧 → 新) | 旧系统支付类型 | 新系统支付方式 | 说明 | |--------------|--------------|------| | 1 | CASH | 现金 | | 6, 7 | ON_ACCOUNT | 挂账、易医通挂账 | | 3 | WECHAT | 微信支付 | | 4 | ALIPAY | 支付宝 | #### 数据映射 ```java SysTaskPayment.taskId = task.taskId SysTaskPayment.totalAmount = paidMoney.paidMoney SysTaskPayment.settlementAmount = paidMoney.paidMoney SysTaskPayment.paymentMethod = convertPaymentMethodFromLegacy(paidMoney.paidMoneyType) SysTaskPayment.payStatus = "PAID" SysTaskPayment.payTime = paidMoney.paidMoneyTime SysTaskPayment.outTradeNo = taskCode + "-" + paidMoneyId SysTaskPayment.tradeNo = paidMoney.paidMoneyMono SysTaskPayment.pid = paidMoneyId SysTaskPayment.syncStatus = 2 SysTaskPayment.syncTime = now() ``` ## 核心代码实现 ### 文件清单 #### 新增文件 1. **实体类** - `PaidMoney.java` - 旧系统支付记录实体 2. **Mapper接口** - `PaidMoneyMapper.java` - 旧系统支付记录Mapper接口 3. **Mapper XML** - `PaidMoneyMapper.xml` - 旧系统支付记录SQL映射 4. **Service接口** - `IPaymentSyncService.java` - 支付同步服务接口 5. **Service实现** - `PaymentSyncServiceImpl.java` - 支付同步服务实现 6. **数据库脚本** - `payment_sync_update.sql` - 数据表更新脚本 #### 修改文件 1. **实体类** - `SysTaskPayment.java` - 新增 pid、syncStatus、syncTime 字段 2. **Mapper接口** - `SysTaskPaymentMapper.java` - 新增 selectByPid、updateSyncInfo 方法 3. **Mapper XML** - `SysTaskPaymentMapper.xml` - 更新映射和新增查询方法 4. **Service实现** - `SysTaskPaymentServiceImpl.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. 任务未同步到旧系统(缺少 ServiceOrdID/DispatchOrdID) 2. 旧系统数据库连接失败 3. 数据插入冲突或约束违反 4. 网络异常 ### 处理策略 1. 同步失败时标记 `sync_status=3` 2. 记录详细错误日志 3. 不影响主业务流程(异步同步) 4. 可通过定时任务或手动触发重试 ## 使用示例 ### 手动触发同步 ```java @Autowired private IPaymentSyncService paymentSyncService; // 同步单条支付记录到旧系统 boolean success = paymentSyncService.syncPaymentToLegacy(paymentId); // 从旧系统同步支付记录 boolean success = paymentSyncService.syncPaymentFromLegacy(paidMoneyId); // 批量同步(待实现) int count = paymentSyncService.batchSyncPaymentToLegacy(); int count = paymentSyncService.batchSyncPaymentFromLegacy(); ``` ## 数据库更新 执行 SQL 脚本: ```sql source sql/payment_sync_update.sql ``` 或手动执行: ```sql ALTER TABLE sys_task_payment ADD COLUMN pid BIGINT COMMENT '旧系统支付记录ID(PaidMoney.id)'; ALTER TABLE sys_task_payment ADD COLUMN sync_status INT DEFAULT 0 COMMENT '同步状态:0未同步,1同步中,2同步成功,3同步失败'; ALTER TABLE sys_task_payment ADD COLUMN sync_time DATETIME COMMENT '同步时间'; CREATE INDEX idx_pid ON sys_task_payment(pid); CREATE INDEX idx_sync_status ON sys_task_payment(sync_status); ``` ## 后续优化建议 1. **批量同步实现** - 实现定时任务批量同步未同步的支付记录 - 实现从旧系统定期拉取新增支付记录 2. **重试机制** - 对同步失败的记录实现自动重试 - 设置最大重试次数和重试间隔 3. **监控告警** - 监控同步失败率 - 同步延迟告警 - 数据一致性校验 4. **性能优化** - 考虑使用消息队列异步处理 - 批量操作优化数据库性能 ## 注意事项 1. **前置条件**: 任务必须先同步到旧系统(有 ServiceOrdID 和 DispatchOrdID) 2. **幂等性**: 重复同步会被检测并跳过 3. **事务处理**: 同步操作使用独立事务,失败不影响主业务 4. **数据一致性**: 通过 pid 字段建立双向关联,避免重复同步 5. **支付方式映射**: 确保新旧系统支付方式正确映射 ## 测试建议 1. **单元测试** - 测试支付方式转换逻辑 - 测试数据映射正确性 - 测试异常处理 2. **集成测试** - 测试完整同步流程 - 测试幂等性 - 测试失败重试 3. **数据校验** - 对比新旧系统支付数据 - 验证金额、时间、状态一致性 --- 更新时间: 2025-01-15 版本: v1.0