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<SysTaskAdditionalFee> additionalFees = additionalFeeMapper.selectByTaskId(taskId);
|
|
// 计算附加费用汇总
|
BigDecimal additionalAmount = additionalFees.stream()
|
.map(SysTaskAdditionalFee::getTotalAmount)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
|
// 计算总金额
|
BigDecimal totalAmount = transferPrice.add(additionalAmount);
|
|
// 查询所有已支付记录,计算已支付总额
|
List<SysTaskPayment> 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);
|
} 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<String, Object> 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<SysTaskPayment> 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<String, Object> 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<SysTaskAdditionalFee> getAdditionalFees(Long taskId) {
|
return additionalFeeMapper.selectByTaskId(taskId);
|
}
|
|
@Override
|
public SysTaskPayment getLatestPayment(Long taskId) {
|
return paymentMapper.selectLatestPaidByTaskId(taskId);
|
}
|
|
/**
|
* 计算附加费用汇总
|
*/
|
private BigDecimal calculateAdditionalAmount(Long taskId) {
|
List<SysTaskAdditionalFee> fees = additionalFeeMapper.selectByTaskId(taskId);
|
return fees.stream()
|
.map(SysTaskAdditionalFee::getTotalAmount)
|
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
}
|
}
|