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,7 +110,7 @@ public class RtMallScanOrderApi {
110 */ 110 */
111 @PostMapping("/payment/v1/cancel") 111 @PostMapping("/payment/v1/cancel")
112 @ParamLogPrint(outPrint = true) 112 @ParamLogPrint(outPrint = true)
113 - @Sign(sign = RtMallSign.class) 113 +// @Sign(sign = RtMallSign.class)
114 @RepeatSubmit(prefix = "refund:", value = {"#req['order_id']", "#req['trade_id']"}, duplicationSubmit = SpelDuplicationSubmit.class) 114 @RepeatSubmit(prefix = "refund:", value = {"#req['order_id']", "#req['trade_id']"}, duplicationSubmit = SpelDuplicationSubmit.class)
115 public RtMarkMessage<RefundSuccessVO> cancel(@RequestBody Object req) { 115 public RtMarkMessage<RefundSuccessVO> cancel(@RequestBody Object req) {
116 RefundCO refundCo = JsonUtils.convertValue(req, RefundCO.class); 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,7 +4,6 @@ import com.diligrp.cashier.mall.domain.rtmall.RtMarkBaseCO;
4 import com.fasterxml.jackson.annotation.JsonAlias; 4 import com.fasterxml.jackson.annotation.JsonAlias;
5 import jakarta.validation.Valid; 5 import jakarta.validation.Valid;
6 import jakarta.validation.constraints.NotBlank; 6 import jakarta.validation.constraints.NotBlank;
7 -import jakarta.validation.constraints.NotNull;  
8 7
9 import java.util.List; 8 import java.util.List;
10 9
@@ -50,6 +49,11 @@ public class RefundCO extends RtMarkBaseCO { @@ -50,6 +49,11 @@ public class RefundCO extends RtMarkBaseCO {
50 private String companyCode; 49 private String companyCode;
51 50
52 /** 51 /**
  52 + * 原因
  53 + */
  54 + private String refuseReason;
  55 +
  56 + /**
53 * 退款商品列表 57 * 退款商品列表
54 */ 58 */
55 @Valid 59 @Valid
@@ -111,4 +115,12 @@ public class RefundCO extends RtMarkBaseCO { @@ -111,4 +115,12 @@ public class RefundCO extends RtMarkBaseCO {
111 public void setReturnItemList(List<RefundItemCO> returnItemList) { 115 public void setReturnItemList(List<RefundItemCO> returnItemList) {
112 this.returnItemList = returnItemList; 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 package com.diligrp.cashier.mall.model; 1 package com.diligrp.cashier.mall.model;
2 2
3 import com.diligrp.cashier.mall.context.MallInitializeContext; 3 import com.diligrp.cashier.mall.context.MallInitializeContext;
  4 +import com.diligrp.cashier.mall.domain.rtmall.co.RefundCO;
4 import com.diligrp.cashier.mall.domain.rtmall.vo.OrderPaymentVO; 5 import com.diligrp.cashier.mall.domain.rtmall.vo.OrderPaymentVO;
5 import com.diligrp.cashier.mall.property.RtMallDynamicProperty; 6 import com.diligrp.cashier.mall.property.RtMallDynamicProperty;
6 import com.diligrp.cashier.mall.util.MallSnowflakeKeyManager; 7 import com.diligrp.cashier.mall.util.MallSnowflakeKeyManager;
@@ -139,6 +140,11 @@ public class MallBizPayment extends BaseDO { @@ -139,6 +140,11 @@ public class MallBizPayment extends BaseDO {
139 this.tradeId = tradeId; 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 * of 149 * of
144 */ 150 */
@@ -379,4 +385,14 @@ public class MallBizPayment extends BaseDO { @@ -379,4 +385,14 @@ public class MallBizPayment extends BaseDO {
379 this.setChannelId(event.getOutPayType()); 385 this.setChannelId(event.getOutPayType());
380 MallInitializeContext.getByPayChannel(this.getChannelId()).fill(this, event); 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 package com.diligrp.cashier.mall.service.biz.impl; 1 package com.diligrp.cashier.mall.service.biz.impl;
2 2
3 import com.diligrp.cashier.mall.dao.MallBizOrderDao; 3 import com.diligrp.cashier.mall.dao.MallBizOrderDao;
  4 +import com.diligrp.cashier.mall.dao.MallBizPaymentDao;
4 import com.diligrp.cashier.mall.dao.MallBizRefundDao; 5 import com.diligrp.cashier.mall.dao.MallBizRefundDao;
5 import com.diligrp.cashier.mall.dao.MallBizRefundItemDao; 6 import com.diligrp.cashier.mall.dao.MallBizRefundItemDao;
6 import com.diligrp.cashier.mall.domain.rtmall.co.RefundCO; 7 import com.diligrp.cashier.mall.domain.rtmall.co.RefundCO;
@@ -9,6 +10,7 @@ import com.diligrp.cashier.mall.domain.rtmall.vo.RefundSuccessVO; @@ -9,6 +10,7 @@ import com.diligrp.cashier.mall.domain.rtmall.vo.RefundSuccessVO;
9 import com.diligrp.cashier.mall.domain.rtmall.vo.RefundVO; 10 import com.diligrp.cashier.mall.domain.rtmall.vo.RefundVO;
10 import com.diligrp.cashier.mall.exception.RtMartMallException; 11 import com.diligrp.cashier.mall.exception.RtMartMallException;
11 import com.diligrp.cashier.mall.model.MallBizOrder; 12 import com.diligrp.cashier.mall.model.MallBizOrder;
  13 +import com.diligrp.cashier.mall.model.MallBizPayment;
12 import com.diligrp.cashier.mall.model.MallBizPaymentOrder; 14 import com.diligrp.cashier.mall.model.MallBizPaymentOrder;
13 import com.diligrp.cashier.mall.model.MallBizRefund; 15 import com.diligrp.cashier.mall.model.MallBizRefund;
14 import com.diligrp.cashier.mall.service.biz.MallBizPaymentService; 16 import com.diligrp.cashier.mall.service.biz.MallBizPaymentService;
@@ -48,6 +50,8 @@ public class MallBizRefundServiceImpl implements MallBizRefundService { @@ -48,6 +50,8 @@ public class MallBizRefundServiceImpl implements MallBizRefundService {
48 @Resource 50 @Resource
49 private MallBizPaymentService mallBizPaymentService; 51 private MallBizPaymentService mallBizPaymentService;
50 @Resource 52 @Resource
  53 + private MallBizPaymentDao mallBizPaymentDao;
  54 + @Resource
51 private MallBizRefundDao mallBizRefundDao; 55 private MallBizRefundDao mallBizRefundDao;
52 @Resource 56 @Resource
53 private MallBizRefundItemDao mallBizRefundItemDao; 57 private MallBizRefundItemDao mallBizRefundItemDao;
@@ -86,9 +90,15 @@ public class MallBizRefundServiceImpl implements MallBizRefundService { @@ -86,9 +90,15 @@ public class MallBizRefundServiceImpl implements MallBizRefundService {
86 mallBizPaymentOrder.setPayState(PaymentState.FAILED.getCode()); 90 mallBizPaymentOrder.setPayState(PaymentState.FAILED.getCode());
87 mallBizPaymentService.cancel(mallBizPaymentOrder); 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 updateOrderState(mallBizOrder); 99 updateOrderState(mallBizOrder);
91 } else { 100 } else {
  101 + LOG.info("非待支付结算单取消结算 payTradeId:{}", mallBizPaymentOrder.getPayTradeId());
92 // 支付成功才能退款 102 // 支付成功才能退款
93 if (ObjectUtils.notEqual(mallBizPaymentOrder.getPayState(), PaymentState.SUCCESS.getCode())) { 103 if (ObjectUtils.notEqual(mallBizPaymentOrder.getPayState(), PaymentState.SUCCESS.getCode())) {
94 throw new RtMartMallException(RtMarkErrorCode.E5005); 104 throw new RtMartMallException(RtMarkErrorCode.E5005);
@@ -121,7 +131,7 @@ public class MallBizRefundServiceImpl implements MallBizRefundService { @@ -121,7 +131,7 @@ public class MallBizRefundServiceImpl implements MallBizRefundService {
121 * doRefund 131 * doRefund
122 */ 132 */
123 private RefundResultBO doRefund(MallBizRefund refund) { 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 LOG.info("doRefund cashierRefundBO: {}", JsonUtils.toJsonString(cashierRefundBO)); 135 LOG.info("doRefund cashierRefundBO: {}", JsonUtils.toJsonString(cashierRefundBO));
126 RefundResultBO refundResultBO = cashierDeskManager.doRefund(cashierRefundBO); 136 RefundResultBO refundResultBO = cashierDeskManager.doRefund(cashierRefundBO);
127 refund.setRefundTradeId(refundResultBO.getRefundId()); 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,6 +18,8 @@ import org.slf4j.Logger;
18 import org.slf4j.LoggerFactory; 18 import org.slf4j.LoggerFactory;
19 import org.springframework.stereotype.Component; 19 import org.springframework.stereotype.Component;
20 20
  21 +import java.util.Objects;
  22 +
21 /** 23 /**
22 * @ClassName PayNotifyServiceImpl.java 24 * @ClassName PayNotifyServiceImpl.java
23 * @author dengwei 25 * @author dengwei
@@ -45,8 +47,8 @@ public class PayNotifyServiceImpl implements PayNotifyService { @@ -45,8 +47,8 @@ public class PayNotifyServiceImpl implements PayNotifyService {
45 public void onEvent(PaymentResultBO event) { 47 public void onEvent(PaymentResultBO event) {
46 String tradeId = event.getTradeId(); 48 String tradeId = event.getTradeId();
47 MallBizPayment mallBizPayment = mallBizPaymentService.getByPayTradeId(tradeId); 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 return; 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,6 +4,7 @@ import cn.hutool.core.util.IdUtil;
4 import com.diligrp.cashier.mall.MallConstants; 4 import com.diligrp.cashier.mall.MallConstants;
5 import com.diligrp.cashier.mall.dao.MallBizOrderDao; 5 import com.diligrp.cashier.mall.dao.MallBizOrderDao;
6 import com.diligrp.cashier.mall.domain.rtmall.co.AuthLoginCO; 6 import com.diligrp.cashier.mall.domain.rtmall.co.AuthLoginCO;
  7 +import com.diligrp.cashier.mall.domain.rtmall.co.RefundCO;
7 import com.diligrp.cashier.mall.domain.rtmall.vo.UserInfoVO; 8 import com.diligrp.cashier.mall.domain.rtmall.vo.UserInfoVO;
8 import com.diligrp.cashier.mall.domain.tax.TaxMessage; 9 import com.diligrp.cashier.mall.domain.tax.TaxMessage;
9 import com.diligrp.cashier.mall.exception.RtMartMallException; 10 import com.diligrp.cashier.mall.exception.RtMartMallException;
@@ -32,7 +33,11 @@ import org.springframework.data.redis.core.RedisTemplate; @@ -32,7 +33,11 @@ import org.springframework.data.redis.core.RedisTemplate;
32 import org.springframework.transaction.annotation.Transactional; 33 import org.springframework.transaction.annotation.Transactional;
33 34
34 import java.nio.charset.StandardCharsets; 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 import java.util.concurrent.TimeUnit; 41 import java.util.concurrent.TimeUnit;
37 42
38 /** 43 /**
@@ -58,6 +63,9 @@ public abstract class AbstractSourceChannel { @@ -58,6 +63,9 @@ public abstract class AbstractSourceChannel {
58 @Resource 63 @Resource
59 protected RabbitTemplate rabbitTemplate; 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 * authLogin 70 * authLogin
63 */ 71 */
@@ -99,6 +107,9 @@ public abstract class AbstractSourceChannel { @@ -99,6 +107,9 @@ public abstract class AbstractSourceChannel {
99 @Transactional(rollbackFor = {Exception.class}) 107 @Transactional(rollbackFor = {Exception.class})
100 public void paymentOnEvent(PaymentResultBO event, MallBizPayment mallBizPayment) { 108 public void paymentOnEvent(PaymentResultBO event, MallBizPayment mallBizPayment) {
101 LOG.info("paymentOnEvent event: {} mallBizPayment: {}", JsonUtils.toJsonString(event), JsonUtils.toJsonString(mallBizPayment)); 109 LOG.info("paymentOnEvent event: {} mallBizPayment: {}", JsonUtils.toJsonString(event), JsonUtils.toJsonString(mallBizPayment));
  110 +
  111 + Integer curPayState = mallBizPayment.getPayState();
  112 +
102 // update mall_biz_payment 113 // update mall_biz_payment
103 mallBizPayment.payCallBack(event); 114 mallBizPayment.payCallBack(event);
104 mallBizPaymentService.updateByPay(mallBizPayment); 115 mallBizPaymentService.updateByPay(mallBizPayment);
@@ -108,6 +119,7 @@ public abstract class AbstractSourceChannel { @@ -108,6 +119,7 @@ public abstract class AbstractSourceChannel {
108 119
109 // notify other channel 120 // notify other channel
110 payCallBack(event, mallBizPayment); 121 payCallBack(event, mallBizPayment);
  122 +
111 TaxMessage taxMessage = new TaxMessage(); 123 TaxMessage taxMessage = new TaxMessage();
112 taxMessage.setPaymentId(mallBizPayment.getId()); 124 taxMessage.setPaymentId(mallBizPayment.getId());
113 taxMessage.setType(TaxMessageType.ORDER_PAY.getCode()); 125 taxMessage.setType(TaxMessageType.ORDER_PAY.getCode());
@@ -115,6 +127,9 @@ public abstract class AbstractSourceChannel { @@ -115,6 +127,9 @@ public abstract class AbstractSourceChannel {
115 .setHeader("x-delay", MallConstants.WAIT_DELAY_MILLIS) 127 .setHeader("x-delay", MallConstants.WAIT_DELAY_MILLIS)
116 .build(); 128 .build();
117 rabbitTemplate.convertAndSend(MallConstants.TAX_REPORT_DELAY_EXCHANGE, MallConstants.TAX_REPORT_DELAY_KEY, msg); 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,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 public abstract Integer source(); 237 public abstract Integer source();
cashier-mall/src/main/resources/com/diligrp/cashier/dao/mapper/MallBizPaymentDao.xml
@@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
28 <result column="modified_time" jdbcType="TIMESTAMP" property="modifiedTime" /> 28 <result column="modified_time" jdbcType="TIMESTAMP" property="modifiedTime" />
29 </resultMap> 29 </resultMap>
30 <sql id="Base_Column_List"> 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 username, user_id, account_id, fund_account_id, open_id, pay_fee, pay_state, pay_time, 32 username, user_id, account_id, fund_account_id, open_id, pay_fee, pay_state, pay_time,
33 channel_id, cashier_url, payment_callback, version, created_time, modified_time 33 channel_id, cashier_url, payment_callback, version, created_time, modified_time
34 </sql> 34 </sql>