package com.ruoyi.system.service.impl; import java.math.BigDecimal; import java.util.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.SysTask; import com.ruoyi.system.domain.SysTaskEmergency; import com.ruoyi.system.domain.SysTaskAdditionalFee; import com.ruoyi.system.domain.SysTaskPayment; import com.ruoyi.system.domain.vo.TaskPaymentInfoVO; import com.ruoyi.system.domain.vo.TaskPaymentCreateVO; import com.ruoyi.system.domain.vo.TaskPaymentResultVO; import com.ruoyi.system.mapper.SysTaskMapper; import com.ruoyi.system.mapper.SysTaskEmergencyMapper; import com.ruoyi.system.mapper.SysTaskAdditionalFeeMapper; import com.ruoyi.system.mapper.SysTaskPaymentMapper; import com.ruoyi.system.service.ISysTaskPaymentService; import com.ruoyi.system.service.IPaymentModuleService; import com.ruoyi.system.service.IPaymentSyncService; import com.ruoyi.system.service.IAdditionalFeeSyncService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 任务支付Service实现 * * @author ruoyi * @date 2025-01-15 */ @Service public class SysTaskPaymentServiceImpl implements ISysTaskPaymentService { private static final Logger log = LoggerFactory.getLogger(SysTaskPaymentServiceImpl.class); @Autowired private SysTaskMapper sysTaskMapper; @Autowired private SysTaskEmergencyMapper sysTaskEmergencyMapper; @Autowired private SysTaskAdditionalFeeMapper additionalFeeMapper; @Autowired private SysTaskPaymentMapper paymentMapper; @Autowired private IPaymentModuleService paymentModuleService; @Autowired private IPaymentSyncService paymentSyncService; @Autowired private IAdditionalFeeSyncService additionalFeeSyncService; /** * 供外部应用回调的接口 */ @Value("${payment.callback.base-url:http://localhost:8080}") private String callbackBaseUrl; @Override public TaskPaymentInfoVO getPaymentInfo(Long taskId) { // 查询任务 SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); if (task == null) { throw new ServiceException("任务不存在"); } // 只有转运任务才支持支付 if (!"EMERGENCY_TRANSFER".equals(task.getTaskType())) { throw new ServiceException("只有转运任务支持支付功能"); } // 查询转运任务扩展信息获取成交价 SysTaskEmergency emergencyInfo = sysTaskEmergencyMapper.selectSysTaskEmergencyByTaskId(taskId); BigDecimal transferPrice = emergencyInfo != null && emergencyInfo.getTransferPrice() != null ? emergencyInfo.getTransferPrice() : BigDecimal.ZERO; // 获取任务基本信息 String taskCode = task.getTaskCode(); String taskType = task.getTaskType(); // 获取车辆信息 String vehicleInfo = ""; if (task.getAssignedVehicles() != null && !task.getAssignedVehicles().isEmpty()) { vehicleInfo = task.getAssignedVehicles().get(0).getVehicleNo(); if (task.getAssignedVehicles().size() > 1) { vehicleInfo += " 等" + task.getAssignedVehicles().size() + "辆"; } } // 获取出发地和目的地(从转运任务扩展信息) String departureAddress = ""; String destinationAddress = ""; if (emergencyInfo != null) { departureAddress = emergencyInfo.getHospitalOutAddress() != null ? emergencyInfo.getHospitalOutAddress() : ""; destinationAddress = emergencyInfo.getHospitalInAddress() != null ? emergencyInfo.getHospitalInAddress() : ""; } // 查询附加费用 List additionalFees = additionalFeeMapper.selectByTaskId(taskId); // 计算附加费用汇总 BigDecimal additionalAmount = additionalFees.stream() .map(SysTaskAdditionalFee::getTotalAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); // 计算总金额 BigDecimal totalAmount = transferPrice.add(additionalAmount); // 查询所有已支付记录,计算已支付总额 List paidPayments = paymentMapper.selectAllPaidByTaskId(taskId); BigDecimal paidAmount = paidPayments.stream() .map(SysTaskPayment::getSettlementAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); // 查询最近一次支付记录 SysTaskPayment latestPayment = paymentMapper.selectLatestPaidByTaskId(taskId); // 构造返回数据 TaskPaymentInfoVO vo = new TaskPaymentInfoVO(); vo.setTaskCode(taskCode); vo.setTaskType(taskType); vo.setVehicleInfo(vehicleInfo); vo.setDepartureAddress(departureAddress); vo.setDestinationAddress(destinationAddress); vo.setTransferPrice(transferPrice); vo.setAdditionalFees(additionalFees); vo.setAdditionalAmount(additionalAmount); vo.setTotalAmount(totalAmount); vo.setPaidAmount(paidAmount); vo.setPaidPayments(paidPayments); // 设置已支付记录列表 vo.setLatestPayment(latestPayment); vo.setPaymentMethods(Arrays.asList("CASH", "ON_ACCOUNT", "WECHAT", "ALIPAY")); return vo; } @Override @Transactional public BigDecimal addAdditionalFee(Long taskId, String feeType, String feeName, BigDecimal unitAmount, Integer quantity, String remark) { // 验证参数 if (unitAmount == null || unitAmount.compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("单价必须大于0"); } if (quantity == null || quantity <= 0) { throw new ServiceException("数量必须大于0"); } // 计算总金额 BigDecimal totalAmount = unitAmount.multiply(new BigDecimal(quantity)); // 创建附加费用记录 SysTaskAdditionalFee fee = new SysTaskAdditionalFee(); fee.setTaskId(taskId); fee.setFeeType(feeType); fee.setFeeName(feeName); fee.setUnitAmount(unitAmount); fee.setQuantity(quantity); fee.setTotalAmount(totalAmount); fee.setRemark(remark); fee.setCreatedBy(SecurityUtils.getUsername()); additionalFeeMapper.insert(fee); // 异步同步到旧系统 try { additionalFeeSyncService.syncAdditionalFeeToLegacy(fee.getId()); } catch (Exception e) { log.error("同步附加费用到旧系统失败", e); } // 返回当前附加费用汇总 return calculateAdditionalAmount(taskId); } @Override @Transactional public BigDecimal removeAdditionalFee(Long taskId, Long feeId) { additionalFeeMapper.deleteById(feeId); return calculateAdditionalAmount(taskId); } @Override @Transactional public TaskPaymentResultVO createPayment(TaskPaymentCreateVO createVO) { Long taskId = createVO.getTaskId(); String paymentMethod = createVO.getPaymentMethod(); BigDecimal settlementAmount = createVO.getSettlementAmount(); // 获取支付信息并校验 TaskPaymentInfoVO paymentInfo = getPaymentInfo(taskId); BigDecimal paidAmount = paymentInfo.getPaidAmount(); BigDecimal remainingAmount = paymentInfo.getTotalAmount().subtract(paidAmount); // 校验结算金额必须大于0且不超过剩余金额 if (settlementAmount.compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("结算金额必须大于0"); } if (settlementAmount.compareTo(remainingAmount) > 0) { throw new ServiceException("结算金额不能超过剩余未支付金额:" + remainingAmount); } // 查询任务编号 SysTask task = sysTaskMapper.selectSysTaskByTaskId(taskId); String taskCode = task.getTaskCode(); // 生成商户订单号: {taskCode}-{timestampMillis} String outTradeNo = taskCode + "-" + System.currentTimeMillis(); // 创建支付记录 SysTaskPayment payment = new SysTaskPayment(); payment.setTaskId(taskId); payment.setTotalAmount(paymentInfo.getTotalAmount()); payment.setSettlementAmount(settlementAmount); payment.setPaymentMethod(paymentMethod); payment.setOutTradeNo(outTradeNo); payment.setRemark(createVO.getRemark()); payment.setCreatedBy(SecurityUtils.getUsername()); payment.setCreatedTime(new Date()); TaskPaymentResultVO result = new TaskPaymentResultVO(); // 支付方式字典值:1-现金, 2-银行转账, 3-微信支付, 4-支付宝, 5-POS收款, 6-挂账, 7-易医通挂账 // 1-现金, 2-银行转账, 5-POS收款, 6-挂账, 7-易医通挂账 直接标记为已支付 if ("1".equals(paymentMethod) || "2".equals(paymentMethod) || "5".equals(paymentMethod) || "6".equals(paymentMethod) || "7".equals(paymentMethod)) { payment.setPayStatus("PAID"); payment.setPayTime(new Date()); payment.setSyncStatus(0); // 未同步 paymentMapper.insert(payment); result.setPaymentId(payment.getId()); result.setPayStatus("PAID"); result.setPayTime(payment.getPayTime()); log.info("任务{}创建支付方式{}支付成功,订单号:{}", taskId, paymentMethod, outTradeNo); // 异步同步到旧系统 try { paymentSyncService.syncPaymentToLegacy(payment); } catch (Exception e) { log.error("同步支付记录到旧系统失败", e); } } // 3-微信支付, 4-支付宝 需要生成二维码 else if ("3".equals(paymentMethod) || "4".equals(paymentMethod)) { payment.setPayStatus("PENDING"); // 设置支付提供商:3-WECHAT, 4-ALIPAY String provider = "3".equals(paymentMethod) ? "WECHAT" : "ALIPAY"; payment.setProvider(provider); // 生成回调地址 String callbackUrl = callbackBaseUrl + "/payment/callback/" + provider.toLowerCase(); payment.setCallbackUrl(callbackUrl); try { // 调用支付模块创建二维码 String subject = "医疗转运支付(" + taskCode + ")"; String attach = "taskId:" + taskId; Map qrResult = paymentModuleService.createQrCode( outTradeNo, settlementAmount, provider, subject, attach, callbackUrl ); // 保存支付模块返回的信息 payment.setPaymentRefId((String) qrResult.get("paymentRefId")); payment.setCodeUrl((String) qrResult.get("codeUrl")); payment.setQrExpireTime((Date) qrResult.get("expireTime")); paymentMapper.insert(payment); result.setPaymentId(payment.getId()); result.setPayStatus("PENDING"); result.setCodeUrl(payment.getCodeUrl()); result.setQrExpireTime(payment.getQrExpireTime()); log.info("任务{}创建支付方式{}支付二维码成功,订单号:{},二维码:{}", taskId, paymentMethod, outTradeNo, payment.getCodeUrl()); } catch (Exception e) { log.error("调用支付模块失败", e); throw new ServiceException("创建支付二维码失败:" + e.getMessage()); } } else { throw new ServiceException("不支持的支付方式:" + paymentMethod); } return result; } @Override public TaskPaymentResultVO getPaymentStatus(Long taskId, Long paymentId) { SysTaskPayment payment; if (paymentId != null) { payment = paymentMapper.selectById(paymentId); } else { // 查询最近一次支付记录 List payments = paymentMapper.selectByTaskId(taskId); if (payments.isEmpty()) { throw new ServiceException("未找到支付记录"); } payment = payments.get(0); } if (payment == null) { throw new ServiceException("支付记录不存在"); } // 如果是待支付状态,查询支付模块获取最新状态 if ("PENDING".equals(payment.getPayStatus())) { try { Map statusResult = paymentModuleService.queryPaymentStatus( payment.getPaymentRefId(), payment.getOutTradeNo() ); String status = (String) statusResult.get("status"); // 如果支付成功,更新本地记录 if ("PAID".equals(status)) { String tradeNo = (String) statusResult.get("tradeNo"); paymentMapper.updatePayStatus(payment.getId(), "PAID", tradeNo); payment.setPayStatus("PAID"); payment.setTradeNo(tradeNo); payment.setPayTime(new Date()); log.info("支付记录{}状态更新为已支付,交易号:{}", payment.getId(), tradeNo); // 异步同步到旧系统 try { paymentSyncService.syncPaymentToLegacy(payment); } catch (Exception ex) { log.error("同步支付记录到旧系统失败", ex); } } } catch (Exception e) { log.error("查询支付状态失败", e); } } // 构造返回结果 TaskPaymentResultVO result = new TaskPaymentResultVO(); result.setPaymentId(payment.getId()); result.setPayStatus(payment.getPayStatus()); result.setCodeUrl(payment.getCodeUrl()); result.setQrExpireTime(payment.getQrExpireTime()); result.setTradeNo(payment.getTradeNo()); result.setPayTime(payment.getPayTime()); return result; } @Override @Transactional public boolean handlePaymentCallback(String outTradeNo, String tradeNo, String provider) { log.info("收到支付回调:outTradeNo={}, tradeNo={}, provider={}", outTradeNo, tradeNo, provider); // 查询支付记录 SysTaskPayment payment = paymentMapper.selectByOutTradeNo(outTradeNo); if (payment == null) { log.error("支付回调失败:未找到订单,outTradeNo={}", outTradeNo); return false; } // 如果已经是已支付状态,直接返回成功 if ("PAID".equals(payment.getPayStatus())) { log.info("订单{}已支付,忽略重复回调", outTradeNo); return true; } // 更新支付状态 paymentMapper.updatePayStatus(payment.getId(), "PAID", tradeNo); log.info("支付回调处理成功:订单{}已更新为已支付状态", outTradeNo); // 异步同步到旧系统 try { paymentSyncService.syncPaymentToLegacy(payment); } catch (Exception e) { log.error("同步支付记录到旧系统失败", e); } return true; } @Override public List getAdditionalFees(Long taskId) { return additionalFeeMapper.selectByTaskId(taskId); } @Override public SysTaskPayment getLatestPayment(Long taskId) { return paymentMapper.selectLatestPaidByTaskId(taskId); } /** * 计算附加费用汇总 */ private BigDecimal calculateAdditionalAmount(Long taskId) { List fees = additionalFeeMapper.selectByTaskId(taskId); return fees.stream() .map(SysTaskAdditionalFee::getTotalAmount) .reduce(BigDecimal.ZERO, BigDecimal::add); } }