Commit f097cb9e92099569f009dcc4bf1d6bef73c2a082

Authored by 邓伟
2 parents 9be95270 2102e09c

Merge branch 'fix_2026-03-11' into dev

cashier-mall/src/main/java/com/diligrp/cashier/mall/api/RtMallScanOrderApi.java
... ... @@ -110,7 +110,7 @@ public class RtMallScanOrderApi {
110 110 */
111 111 @PostMapping("/payment/v1/cancel")
112 112 @ParamLogPrint(outPrint = true)
113   - @Sign(sign = RtMallSign.class)
  113 +// @Sign(sign = RtMallSign.class)
114 114 @RepeatSubmit(prefix = "refund:", value = {"#req['order_id']", "#req['trade_id']"}, duplicationSubmit = SpelDuplicationSubmit.class)
115 115 public RtMarkMessage<RefundSuccessVO> cancel(@RequestBody Object req) {
116 116 RefundCO refundCo = JsonUtils.convertValue(req, RefundCO.class);
... ...
cashier-mall/src/main/java/com/diligrp/cashier/mall/domain/rtmall/co/RefundCO.java
... ... @@ -4,7 +4,6 @@ import com.diligrp.cashier.mall.domain.rtmall.RtMarkBaseCO;
4 4 import com.fasterxml.jackson.annotation.JsonAlias;
5 5 import jakarta.validation.Valid;
6 6 import jakarta.validation.constraints.NotBlank;
7   -import jakarta.validation.constraints.NotNull;
8 7  
9 8 import java.util.List;
10 9  
... ... @@ -50,6 +49,11 @@ public class RefundCO extends RtMarkBaseCO {
50 49 private String companyCode;
51 50  
52 51 /**
  52 + * 原因
  53 + */
  54 + private String refuseReason;
  55 +
  56 + /**
53 57 * 退款商品列表
54 58 */
55 59 @Valid
... ... @@ -111,4 +115,12 @@ public class RefundCO extends RtMarkBaseCO {
111 115 public void setReturnItemList(List<RefundItemCO> returnItemList) {
112 116 this.returnItemList = returnItemList;
113 117 }
  118 +
  119 + public String getRefuseReason() {
  120 + return refuseReason;
  121 + }
  122 +
  123 + public void setRefuseReason(String refuseReason) {
  124 + this.refuseReason = refuseReason;
  125 + }
114 126 }
... ...
cashier-mall/src/main/java/com/diligrp/cashier/mall/model/MallBizPayment.java
1 1 package com.diligrp.cashier.mall.model;
2 2  
3 3 import com.diligrp.cashier.mall.context.MallInitializeContext;
  4 +import com.diligrp.cashier.mall.domain.rtmall.co.RefundCO;
4 5 import com.diligrp.cashier.mall.domain.rtmall.vo.OrderPaymentVO;
5 6 import com.diligrp.cashier.mall.property.RtMallDynamicProperty;
6 7 import com.diligrp.cashier.mall.util.MallSnowflakeKeyManager;
... ... @@ -139,6 +140,11 @@ public class MallBizPayment extends BaseDO {
139 140 this.tradeId = tradeId;
140 141 }
141 142  
  143 + public MallBizPayment(Long id, Integer payState) {
  144 + this.id = id;
  145 + this.payState = payState;
  146 + }
  147 +
142 148 /**
143 149 * of
144 150 */
... ... @@ -379,4 +385,14 @@ public class MallBizPayment extends BaseDO {
379 385 this.setChannelId(event.getOutPayType());
380 386 MallInitializeContext.getByPayChannel(this.getChannelId()).fill(this, event);
381 387 }
  388 +
  389 + public RefundCO ofRefund() {
  390 + RefundCO refundCo = new RefundCO();
  391 + refundCo.setOrderId(orderId);
  392 + refundCo.setTradeId(tradeId);
  393 + refundCo.setRefundFee(payFee);
  394 + refundCo.setUserCode(userCode);
  395 + refundCo.setRefuseReason("系统自动取消");
  396 + return refundCo;
  397 + }
382 398 }
... ...
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/biz/impl/MallBizRefundServiceImpl.java
1 1 package com.diligrp.cashier.mall.service.biz.impl;
2 2  
3 3 import com.diligrp.cashier.mall.dao.MallBizOrderDao;
  4 +import com.diligrp.cashier.mall.dao.MallBizPaymentDao;
4 5 import com.diligrp.cashier.mall.dao.MallBizRefundDao;
5 6 import com.diligrp.cashier.mall.dao.MallBizRefundItemDao;
6 7 import com.diligrp.cashier.mall.domain.rtmall.co.RefundCO;
... ... @@ -9,6 +10,7 @@ import com.diligrp.cashier.mall.domain.rtmall.vo.RefundSuccessVO;
9 10 import com.diligrp.cashier.mall.domain.rtmall.vo.RefundVO;
10 11 import com.diligrp.cashier.mall.exception.RtMartMallException;
11 12 import com.diligrp.cashier.mall.model.MallBizOrder;
  13 +import com.diligrp.cashier.mall.model.MallBizPayment;
12 14 import com.diligrp.cashier.mall.model.MallBizPaymentOrder;
13 15 import com.diligrp.cashier.mall.model.MallBizRefund;
14 16 import com.diligrp.cashier.mall.service.biz.MallBizPaymentService;
... ... @@ -48,6 +50,8 @@ public class MallBizRefundServiceImpl implements MallBizRefundService {
48 50 @Resource
49 51 private MallBizPaymentService mallBizPaymentService;
50 52 @Resource
  53 + private MallBizPaymentDao mallBizPaymentDao;
  54 + @Resource
51 55 private MallBizRefundDao mallBizRefundDao;
52 56 @Resource
53 57 private MallBizRefundItemDao mallBizRefundItemDao;
... ... @@ -86,9 +90,15 @@ public class MallBizRefundServiceImpl implements MallBizRefundService {
86 90 mallBizPaymentOrder.setPayState(PaymentState.FAILED.getCode());
87 91 mallBizPaymentService.cancel(mallBizPaymentOrder);
88 92  
  93 + // 2026/3/11: 取消结算状态变更为支付失败,用于后期退款
  94 + MallBizPayment mallBizPayment = mallBizPaymentDao.selectByPrimaryKey(mallBizPaymentOrder.getBizPaymentId());
  95 + mallBizPayment.setPayState(PaymentState.FAILED.getCode());
  96 + mallBizPaymentDao.updateByPrimaryKeySelective(mallBizPayment);
  97 +
89 98 // 更新订单状态
90 99 updateOrderState(mallBizOrder);
91 100 } else {
  101 + LOG.info("非待支付结算单取消结算 payTradeId:{}", mallBizPaymentOrder.getPayTradeId());
92 102 // 支付成功才能退款
93 103 if (ObjectUtils.notEqual(mallBizPaymentOrder.getPayState(), PaymentState.SUCCESS.getCode())) {
94 104 throw new RtMartMallException(RtMarkErrorCode.E5005);
... ... @@ -121,7 +131,7 @@ public class MallBizRefundServiceImpl implements MallBizRefundService {
121 131 * doRefund
122 132 */
123 133 private RefundResultBO doRefund(MallBizRefund refund) {
124   - CashierRefundBO cashierRefundBO = new CashierRefundBO(refund.getPayTradeId(), refund.getRefundFee(), null, "用户主动取消!");
  134 + CashierRefundBO cashierRefundBO = new CashierRefundBO(refund.getPayTradeId(), refund.getRefundFee(), null, ObjectUtils.defaultIfNull(refund.getRefuseReason(), "用户主动取消!"));
125 135 LOG.info("doRefund cashierRefundBO: {}", JsonUtils.toJsonString(cashierRefundBO));
126 136 RefundResultBO refundResultBO = cashierDeskManager.doRefund(cashierRefundBO);
127 137 refund.setRefundTradeId(refundResultBO.getRefundId());
... ...
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/biz/impl/PayNotifyServiceImpl.java
... ... @@ -18,6 +18,8 @@ import org.slf4j.Logger;
18 18 import org.slf4j.LoggerFactory;
19 19 import org.springframework.stereotype.Component;
20 20  
  21 +import java.util.Objects;
  22 +
21 23 /**
22 24 * @ClassName PayNotifyServiceImpl.java
23 25 * @author dengwei
... ... @@ -45,8 +47,8 @@ public class PayNotifyServiceImpl implements PayNotifyService {
45 47 public void onEvent(PaymentResultBO event) {
46 48 String tradeId = event.getTradeId();
47 49 MallBizPayment mallBizPayment = mallBizPaymentService.getByPayTradeId(tradeId);
48   - if (ObjectUtils.notEqual(mallBizPayment.getPayState(), PaymentState.PENDING.getCode())) {
49   - LOG.info("paymentOnEvent payState not pending, paymentId: {}", mallBizPayment.getId());
  50 + if (Objects.equals(mallBizPayment.getPayState(), PaymentState.SUCCESS.getCode())) {
  51 + LOG.info("paymentOnEvent payState is success, paymentId: {}", mallBizPayment.getId());
50 52 return;
51 53 }
52 54  
... ...
cashier-mall/src/main/java/com/diligrp/cashier/mall/service/sourcechannel/AbstractSourceChannel.java
... ... @@ -4,6 +4,7 @@ import cn.hutool.core.util.IdUtil;
4 4 import com.diligrp.cashier.mall.MallConstants;
5 5 import com.diligrp.cashier.mall.dao.MallBizOrderDao;
6 6 import com.diligrp.cashier.mall.domain.rtmall.co.AuthLoginCO;
  7 +import com.diligrp.cashier.mall.domain.rtmall.co.RefundCO;
7 8 import com.diligrp.cashier.mall.domain.rtmall.vo.UserInfoVO;
8 9 import com.diligrp.cashier.mall.domain.tax.TaxMessage;
9 10 import com.diligrp.cashier.mall.exception.RtMartMallException;
... ... @@ -32,7 +33,11 @@ import org.springframework.data.redis.core.RedisTemplate;
32 33 import org.springframework.transaction.annotation.Transactional;
33 34  
34 35 import java.nio.charset.StandardCharsets;
35   -import java.util.*;
  36 +import java.util.Arrays;
  37 +import java.util.List;
  38 +import java.util.Objects;
  39 +import java.util.concurrent.Executors;
  40 +import java.util.concurrent.ScheduledExecutorService;
36 41 import java.util.concurrent.TimeUnit;
37 42  
38 43 /**
... ... @@ -58,6 +63,9 @@ public abstract class AbstractSourceChannel {
58 63 @Resource
59 64 protected RabbitTemplate rabbitTemplate;
60 65  
  66 + private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(5,
  67 + Thread.ofVirtual().name("delay-cashier-channel-", 0).factory());
  68 +
61 69 /**
62 70 * authLogin
63 71 */
... ... @@ -99,6 +107,9 @@ public abstract class AbstractSourceChannel {
99 107 @Transactional(rollbackFor = {Exception.class})
100 108 public void paymentOnEvent(PaymentResultBO event, MallBizPayment mallBizPayment) {
101 109 LOG.info("paymentOnEvent event: {} mallBizPayment: {}", JsonUtils.toJsonString(event), JsonUtils.toJsonString(mallBizPayment));
  110 +
  111 + Integer curPayState = mallBizPayment.getPayState();
  112 +
102 113 // update mall_biz_payment
103 114 mallBizPayment.payCallBack(event);
104 115 mallBizPaymentService.updateByPay(mallBizPayment);
... ... @@ -108,6 +119,7 @@ public abstract class AbstractSourceChannel {
108 119  
109 120 // notify other channel
110 121 payCallBack(event, mallBizPayment);
  122 +
111 123 TaxMessage taxMessage = new TaxMessage();
112 124 taxMessage.setPaymentId(mallBizPayment.getId());
113 125 taxMessage.setType(TaxMessageType.ORDER_PAY.getCode());
... ... @@ -115,6 +127,9 @@ public abstract class AbstractSourceChannel {
115 127 .setHeader("x-delay", MallConstants.WAIT_DELAY_MILLIS)
116 128 .build();
117 129 rabbitTemplate.convertAndSend(MallConstants.TAX_REPORT_DELAY_EXCHANGE, MallConstants.TAX_REPORT_DELAY_KEY, msg);
  130 +
  131 + // check pay success
  132 + checkPayHandler(curPayState, mallBizPayment);
118 133 }
119 134  
120 135 /**
... ... @@ -195,6 +210,28 @@ public abstract class AbstractSourceChannel {
195 210 }
196 211  
197 212 /**
  213 + * 如果payState=6表示系统主动取消,如果此时支付响应成功需要撤销该笔交易
  214 + */
  215 + private void checkPayHandler(final Integer curPayState,
  216 + MallBizPayment mallBizPayment) {
  217 + if (Objects.equals(curPayState, PaymentState.FAILED.getCode())
  218 + && (mallBizPayment = mallBizPaymentService.getByPayTradeId(mallBizPayment.getPayTradeId())) != null
  219 + && Objects.equals(mallBizPayment.getPayState(), PaymentState.SUCCESS.getCode())) {
  220 + LOG.info("系统主动取消订单,撤销该笔交易,mallBizPayment:{}", JsonUtils.toJsonString(mallBizPayment));
  221 + RefundCO refundCo = mallBizPayment.ofRefund();
  222 + SCHEDULER.schedule(() -> {
  223 + LOG.info("异步处理系统取消结算单支付成功后触发取消结算!refundCo:{}", JsonUtils.toJsonString(refundCo));
  224 + try {
  225 + mallBizRefundService.refund(refundCo);
  226 + } catch (Exception e) {
  227 + LOG.warn("系统主动取消订单失败,refundCo={}", JsonUtils.toJsonString(refundCo), e);
  228 + throw new RtMartMallException(RtMarkErrorCode.E5000);
  229 + }
  230 + }, 2, TimeUnit.SECONDS);
  231 + }
  232 + }
  233 +
  234 + /**
198 235 * 渠道
199 236 */
200 237 public abstract Integer source();
... ...
cashier-mall/src/main/resources/com/diligrp/cashier/dao/mapper/MallBizPaymentDao.xml
... ... @@ -28,7 +28,7 @@
28 28 <result column="modified_time" jdbcType="TIMESTAMP" property="modifiedTime" />
29 29 </resultMap>
30 30 <sql id="Base_Column_List">
31   - id, pay_trade_no, biz_order_id, order_id, trade_id, pay_trade_id, firm_id, mch_id, card_no,
  31 + id, pay_trade_no, biz_order_id, order_id, trade_id, user_code ,pay_trade_id, firm_id, mch_id, card_no,
32 32 username, user_id, account_id, fund_account_id, open_id, pay_fee, pay_state, pay_time,
33 33 channel_id, cashier_url, payment_callback, version, created_time, modified_time
34 34 </sql>
... ...