8.10 小商场退单区分拼团订单与普通订单,拼团订单要等拼团系统回调/普通订单直接改订单状态为Close+退款

This commit is contained in:
zhangsan 2025-08-10 10:45:52 +08:00
parent b36f572239
commit 7fc2af3327
4 changed files with 84 additions and 32 deletions

View File

@ -11,7 +11,7 @@ app:
api-url: http://group-buying-sys:8091
# 回调给自己,通常要是公网可访问的域名或网关地址
# 如果 pay-mall 服务外部也同 host:8092可以写
notify-url: http://group-buying-sys/api/v1/alipay/group_buy_notify
notify-url: http://pay-mall/api/v1/alipay/group_buy_notify
notify-type: MQ
source: s01
channel: c01

View File

@ -28,7 +28,7 @@ public interface IOrderService {
/**
* 营销退单
*/
boolean refundMarketOrder(String userId, String orderId);
boolean preRefundOrder(String userId, String orderId);
/**
* 接收拼团退单消息

View File

@ -146,62 +146,114 @@ public class OrderService extends AbstractOrderService{
repository.changeOrderMarketSettlement(outTradeNoList);
}
/**
* 预备退单
*/
@Override
public boolean refundMarketOrder(String userId, String orderId) {
// 1. 查询订单信息验证订单是否存在且属于该用户
public boolean preRefundOrder(String userId, String orderId) {
// 1.
OrderEntity orderEntity = repository.queryOrderByUserIdAndOrderId(userId, orderId);
if (null == orderEntity) {
if (orderEntity == null) {
log.warn("退单失败,订单不存在或不属于该用户 userId:{} orderId:{}", userId, orderId);
return false;
}
// 2. 检查订单状态只有createpay_waitpay_successdeal_done状态的订单可以退单
String status = orderEntity.getOrderStatusVO().getCode();
// 已关闭直接拒绝
if (OrderStatusVO.CLOSE.getCode().equals(status)) {
log.warn("退单失败,订单已关闭 userId:{} orderId:{} status:{}", userId, orderId, status);
return false;
}
// 3. 对于营销类型的单子调用拼团执行组队退单
port.refundMarketPayOrder(userId, orderId);
// 4. 执行退单操作
if (OrderStatusVO.CREATE.getCode().equals(status) || OrderStatusVO.PAY_WAIT.getCode().equals(status)) {
return repository.refundOrder(userId, orderId);
} else {
// 2. 营销锁单走营销通道 + 统一改库
int marketType = orderEntity.getMarketType(); // 建议后续用枚举替代裸常量
if (marketType == 1) {
try {
port.refundMarketPayOrder(userId, orderId);
} catch (Exception e) {
// 这里按你的容忍度决定是否直接返回 false
log.error("营销退单通道异常 userId:{} orderId:{} err:{}", userId, orderId, e.getMessage(), e);
return false;
}
boolean result = repository.refundMarketOrder(userId, orderId);
if (result) {
log.info("退单成功 userId:{} orderId:{}", userId, orderId);
log.info("营销退单成功(已改库) userId:{} orderId:{}", userId, orderId);
} else {
log.warn("退单失败 userId:{} orderId:{}", userId, orderId);
log.warn("营销退单失败(改库失败) userId:{} orderId:{}", userId, orderId);
}
return result;
}
// 3. 普通订单分未付款 / 已付款
if (OrderStatusVO.CREATE.getCode().equals(status)
|| OrderStatusVO.PAY_WAIT.getCode().equals(status)) {
// 未付款仅改库
boolean result = repository.refundOrder(userId, orderId);
if (result) {
log.info("普通未付款退单成功(仅改库) userId:{} orderId:{}", userId, orderId);
} else {
log.warn("普通未付款退单失败(改库失败) userId:{} orderId:{}", userId, orderId);
}
return result;
} else {
// 已付款三方退款 + 改库用你已有的方法
return refundPayOrder(userId, orderId);
}
}
/**
* 真正的退钱关闭订单逻辑
*/
@Override
public boolean refundPayOrder(String userId, String orderId) throws AlipayApiException {
public boolean refundPayOrder(String userId, String orderId) /* throws AlipayApiException */ {
// 1. 查询订单信息验证订单是否存在且属于该用户
OrderEntity orderEntity = repository.queryOrderByUserIdAndOrderId(userId, orderId);
if (null == orderEntity) {
if (orderEntity == null) {
log.warn("退款失败,订单不存在或不属于该用户 userId:{} orderId:{}", userId, orderId);
return false;
}
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
refundModel.setOutTradeNo(orderEntity.getOrderId());
refundModel.setRefundAmount(orderEntity.getPayAmount().toString());
refundModel.setRefundReason("交易退单");
request.setBizModel(refundModel);
boolean dbOk = false; // 以落库结果为最终返回
// 交易退款
AlipayTradeRefundResponse execute = alipayClient.execute(request);
if (!execute.isSuccess()) return false;
try {
// 2. 调用支付宝退款沙箱里允许失败
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
AlipayTradeRefundModel refundModel = new AlipayTradeRefundModel();
refundModel.setOutTradeNo(orderEntity.getOrderId());
refundModel.setRefundAmount(orderEntity.getPayAmount().toString());
refundModel.setRefundReason("交易退单");
request.setBizModel(refundModel);
// 状态变更
repository.refundOrder(userId, orderId);
AlipayTradeRefundResponse resp = alipayClient.execute(request);
if (resp.isSuccess()) {
log.info("支付宝退款成功 userId:{} orderId:{}", userId, orderId);
} else {
// 不影响后续改库
log.warn("支付宝退款失败(沙箱忽略) code={}, subCode={}, msg={}",
resp.getCode(), resp.getSubCode(), resp.getSubMsg());
}
} catch (Exception e) {
// 捕获所有异常避免抛出导致 MQ 重试
log.error("调用支付宝退款异常(沙箱忽略) userId:{} orderId:{} err:{}",
userId, orderId, e.getMessage(), e);
} finally {
// 3. 必须执行状态变更你要求的必须执行
try {
dbOk = repository.refundOrder(userId, orderId);
if (dbOk) {
log.info("订单状态已更新为已退款 userId:{} orderId:{}", userId, orderId);
} else {
log.warn("订单状态更新失败 userId:{} orderId:{}", userId, orderId);
}
} catch (Exception de) {
// 落库异常要打日志并返回 false交由上层决定是否重试/告警
log.error("订单状态更新异常 userId:{} orderId:{} err:{}",
userId, orderId, de.getMessage(), de);
dbOk = false;
}
}
return true;
// 返回以数据库落库为准支付宝失败在沙箱场景被忽略
return dbOk;
}
}

View File

@ -103,7 +103,7 @@ public class AliPayController implements IPayService {
public String groupBuyNotify(@RequestBody NotifyRequestDTO requestDTO) {
log.info("拼团回调,组队完成,结算开始 {}", JSON.toJSONString(requestDTO));
try {
// 营销结算
// 订单状态更新模拟发货...
orderService.changeOrderMarketSettlement(requestDTO.getOutTradeNoList());
return "success";
} catch (Exception e) {
@ -152,7 +152,7 @@ public class AliPayController implements IPayService {
log.info("支付回调,买家付款金额: {}", params.get("buyer_pay_amount"));
log.info("支付回调,支付回调,更新订单 {}", tradeNo);
// 后续处理更新订单状态...进入下一阶段如发货
// 付款成功更新支付商城系统该笔订单的状态并调用拼团系统中该笔拼团的结算
orderService.changeOrderPaySuccess(tradeNo, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(params.get("gmt_payment")));
return "success";
}
@ -232,7 +232,7 @@ public class AliPayController implements IPayService {
String orderId = requestDTO.getOrderId();
// 执行退单操作
boolean success = orderService.refundMarketOrder(userId, orderId);
boolean success = orderService.preRefundOrder(userId, orderId);
RefundOrderResponseDTO responseDTO = new RefundOrderResponseDTO();
responseDTO.setSuccess(success);