Commit 3ab3cdfd821d673c5f6f43bbe315459d7ee5ba6d

Authored by huanggang
1 parent ea665fba

upgrade after testing

cashier-boss/src/main/java/com/diligrp/cashier/boss/Constants.java
... ... @@ -6,7 +6,7 @@ public final class Constants {
6 6 // 商户信息过期时长-单位秒 - 1个小时
7 7 public static final int MERCHANT_TIMEOUT_SECONDS = 60 * 60;
8 8 // TOKEN信息缓存Key
9   - public static final String TOKEN_REDIS_KEY = "cashier:token:%s";
  9 + public static final String TRADE_REDIS_KEY = "cashier:trade:%s";
10 10 // TOKEN参数名称
11 11 public static final String TOKEN_PARAM_NAME = "token";
12 12 // TOKEN签名算法
... ...
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/impl/CashierDeskServiceImpl.java
... ... @@ -56,7 +56,7 @@ public class CashierDeskServiceImpl implements ICashierDeskService {
56 56 CashierOrderToken orderToken = new CashierOrderToken(merchant.getMchId(), tradeId, order.getType().getCode(),
57 57 order.getUserId(), order.getRedirectUrl());
58 58  
59   - String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token);
  59 + String tokenKey = String.format(Constants.TRADE_REDIS_KEY, tradeId);
60 60 stringRedisTemplate.opsForValue().set(tokenKey, orderToken.toString(), Constants.TOKEN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
61 61 MerchantParams params = merchant.getParams();
62 62 String paymentUrl = switch (order.getType()) {
... ... @@ -70,8 +70,8 @@ public class CashierDeskServiceImpl implements ICashierDeskService {
70 70  
71 71 @Override
72 72 public CashierOrderVO getCashierOrderByToken(String token) {
73   - CashierOrderToken.decode(token, cashierDeskProperties.getSecretKey());
74   - String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token);
  73 + long tradeId = CashierOrderToken.decode(token, cashierDeskProperties.getSecretKey());
  74 + String tokenKey = String.format(Constants.TRADE_REDIS_KEY, tradeId);
75 75 String payload = stringRedisTemplate.opsForValue().get(tokenKey);
76 76 if (ObjectUtils.isEmpty(payload)) {
77 77 throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "TOKEN超时过期,不能完成支付");
... ... @@ -83,9 +83,6 @@ public class CashierDeskServiceImpl implements ICashierDeskService {
83 83 throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "收银台订单已完成,不能进行支付");
84 84 }
85 85 List<PaymentPipeline> pipelines = paymentPipelineManager.listPipelines(orderToken.getMchId(), PaymentPipeline.class);
86   - if (pipelines.isEmpty()) {
87   - throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "商户无可用的支付通道");
88   - }
89 86 List<CashierOrderVO.PaymentPipeline> pipelineList = pipelines.stream().map(pipeline ->
90 87 new CashierOrderVO.PaymentPipeline(pipeline.pipelineId(), pipeline.supportedChannel())).toList();
91 88 return new CashierOrderVO(orderToken.getUserId(), orderToken.getRedirectUrl(), pipelineList);
... ... @@ -102,7 +99,7 @@ public class CashierDeskServiceImpl implements ICashierDeskService {
102 99 OnlinePaymentStatus paymentStatus = cashierPaymentService.doPayment(payment);
103 100 // 只要提交了收银台支付,无论是否支付成功,都使token失效,收银台页面将无法重新打开
104 101 String token = CashierOrderToken.encode(Long.valueOf(payment.getTradeId()), cashierDeskProperties.getSecretKey());
105   - String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token);
  102 + String tokenKey = String.format(Constants.TRADE_REDIS_KEY, token);
106 103 stringRedisTemplate.delete(tokenKey);
107 104 return paymentStatus;
108 105 }
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/Constants.java
... ... @@ -18,4 +18,7 @@ public final class Constants {
18 18 public static final long TEN_MINUTES = 10 * ONE_MINUTE;
19 19  
20 20 public static final long ONE_SECOND = 1000;
  21 +
  22 + // 支付通道最小超时时间(单位秒), 一分钟
  23 + public static final long MIN_PIPELINE_TIMEOUT = 60;
21 24 }
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/WechatDirectHttpClient.java
... ... @@ -240,7 +240,7 @@ public class WechatDirectHttpClient extends WechatHttpClient {
240 240 params.put("mchid", wechatConfig.getMchId());
241 241 params.put("description", request.getGoods());
242 242 params.put("out_trade_no", request.getPaymentId());
243   - params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusMinutes(WechatConstants.PAY_DURATION_MINS),
  243 + params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusSeconds(request.getTimeout()),
244 244 WechatConstants.RFC3339_FORMAT));
245 245 params.put("notify_url", notifyUri);
246 246 Map<String, Object> amount = new LinkedHashMap<>();
... ... @@ -258,7 +258,7 @@ public class WechatDirectHttpClient extends WechatHttpClient {
258 258 params.put("mchid", wechatConfig.getMchId());
259 259 params.put("description", request.getGoods());
260 260 params.put("out_trade_no", request.getPaymentId());
261   - params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusMinutes(WechatConstants.PAY_DURATION_MINS),
  261 + params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusSeconds(request.getTimeout()),
262 262 WechatConstants.RFC3339_FORMAT));
263 263 params.put("notify_url", notifyUri);
264 264 Map<String, Object> amount = new LinkedHashMap<>();
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/WechatPartnerHttpClient.java
... ... @@ -256,7 +256,7 @@ public class WechatPartnerHttpClient extends WechatHttpClient {
256 256 params.put("sub_mchid", subMchId);
257 257 params.put("description", request.getGoods());
258 258 params.put("out_trade_no", request.getPaymentId());
259   - params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusMinutes(WechatConstants.PAY_DURATION_MINS),
  259 + params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusSeconds(request.getTimeout()),
260 260 WechatConstants.RFC3339_FORMAT));
261 261 params.put("notify_url", notifyUri);
262 262 Map<String, Object> amount = new LinkedHashMap<>();
... ... @@ -278,7 +278,7 @@ public class WechatPartnerHttpClient extends WechatHttpClient {
278 278 params.put("sub_mchid", subMchId);
279 279 params.put("description", request.getGoods());
280 280 params.put("out_trade_no", request.getPaymentId());
281   - params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusMinutes(WechatConstants.PAY_DURATION_MINS),
  281 + params.put("time_expire", DateUtils.formatDateTime(request.getWhen().plusSeconds(request.getTimeout()),
282 282 WechatConstants.RFC3339_FORMAT));
283 283 params.put("notify_url", notifyUri);
284 284 Map<String, Object> amount = new LinkedHashMap<>();
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/MiniProPrepayRequest.java
... ... @@ -5,13 +5,21 @@ import java.time.LocalDateTime;
5 5 public class MiniProPrepayRequest extends OnlinePaymentRequest {
6 6 // 小程序openId
7 7 private final String openId;
  8 + // 超时时间-秒
  9 + private final Long timeout;
8 10  
9   - public MiniProPrepayRequest(String paymentId, long amount, String goods, String description, LocalDateTime when, String openId) {
  11 + public MiniProPrepayRequest(String paymentId, long amount, String goods, String description, LocalDateTime when,
  12 + String openId, Long timeout) {
10 13 super(paymentId, amount, goods, description, when);
11 14 this.openId = openId;
  15 + this.timeout = timeout;
12 16 }
13 17  
14 18 public String getOpenId() {
15 19 return openId;
16 20 }
  21 +
  22 + public Long getTimeout() {
  23 + return timeout;
  24 + }
17 25 }
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/NativePrepayRequest.java
... ... @@ -3,7 +3,16 @@ package com.diligrp.cashier.pipeline.domain;
3 3 import java.time.LocalDateTime;
4 4  
5 5 public class NativePrepayRequest extends OnlinePaymentRequest {
6   - public NativePrepayRequest(String paymentId, long amount, String goods, String description, LocalDateTime when) {
  6 + // 超时时间-秒
  7 + private final Long timeout;
  8 +
  9 + public NativePrepayRequest(String paymentId, long amount, String goods, String description, LocalDateTime when,
  10 + Long timeout) {
7 11 super(paymentId, amount, goods, description, when);
  12 + this.timeout = timeout;
  13 + }
  14 +
  15 + public Long getTimeout() {
  16 + return timeout;
8 17 }
9 18 }
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/OutPaymentType.java
... ... @@ -13,6 +13,8 @@ import java.util.stream.Stream;
13 13 */
14 14 public enum OutPaymentType implements IEnumType {
15 15  
  16 + NOP("未知方式", 0),
  17 +
16 18 WXPAY("微信支付", 10),
17 19  
18 20 ALIPAY("支付宝支付", 11),
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/util/WechatConstants.java
... ... @@ -52,6 +52,4 @@ public class WechatConstants {
52 52 public static final String REFUND_PROCESSING = "PROCESSING"; // 退款处理中
53 53 public static final String REFUND_ABNORMAL = "ABNORMAL"; // 退款异常
54 54  
55   - // 预支付订单有效期持续时间,超过这个时间将不能支付
56   - public static final int PAY_DURATION_MINS = 8;
57 55 }
... ...
cashier-shared/src/main/java/com/diligrp/cashier/shared/util/DateUtils.java
... ... @@ -8,6 +8,7 @@ import java.time.LocalDate;
8 8 import java.time.LocalDateTime;
9 9 import java.time.ZoneOffset;
10 10 import java.time.format.DateTimeFormatter;
  11 +import java.time.temporal.ChronoUnit;
11 12 import java.util.Date;
12 13  
13 14 /**
... ... @@ -55,8 +56,7 @@ public class DateUtils {
55 56  
56 57 public static LocalDateTime addDays(long amount) {
57 58 LocalDateTime localDateTime = LocalDateTime.now();
58   - localDateTime.plusDays(amount);
59   - return localDateTime;
  59 + return localDateTime.plusDays(amount);
60 60 }
61 61  
62 62 public static String format(Date date, String format) {
... ... @@ -134,4 +134,14 @@ public class DateUtils {
134 134 public static long timestampInSeconds() {
135 135 return Instant.now().getEpochSecond();
136 136 }
  137 +
  138 + /**
  139 + * 两个时间点间隔的秒数
  140 + *
  141 + * 2026-01-07 10:00:00 - 2026-01-07 10:00:30, 返回 30
  142 + * 2026-01-07 10:00:30 - 2026-01-07 10:00:00, 返回 -30
  143 + */
  144 + public static long secondsDiff(LocalDateTime startTime, LocalDateTime endTime) {
  145 + return ChronoUnit.SECONDS.between(startTime, endTime);
  146 + }
137 147 }
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierPaymentServiceImpl.java
... ... @@ -145,7 +145,8 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
145 145 .type(TradeType.TRADE).paymentId(paymentId).channelId(onlinePipeline.supportedChannel())
146 146 .payType(PaymentType.MINI_PRO).pipelineId(onlinePipeline.pipelineId()).goods(trade.getGoods())
147 147 .amount(trade.getAmount()).payerId(request.getOpenId()).outTradeNo(response.getOutTradeNo())
148   - .state(response.getState()).version(0).createdTime(now).modifiedTime(now).build();
  148 + .outPayType(OutPaymentType.NOP).finishTime(null).state(response.getState())
  149 + .notifyUrl(trade.getNotifyUrl()).description(null).version(0).createdTime(now).modifiedTime(now).build();
149 150 onlinePaymentDao.insertOnlinePayment(payment);
150 151 return response;
151 152 } else if (pipeline instanceof DiliCardPipeline cardPipeline) { // 园区卡支付通道
... ... @@ -160,10 +161,10 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
160 161 OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId())
161 162 .type(TradeType.TRADE).paymentId(paymentId).channelId(cardPipeline.supportedChannel())
162 163 .payType(PaymentType.DIRECT).pipelineId(cardPipeline.pipelineId()).goods(trade.getGoods())
163   - .amount(trade.getAmount()).payerId(response.getPayerId())
164   - .finishTime(response.getWhen()).outTradeNo(response.getOutTradeNo())
165   - .outPayType(response.getOutPayType()).state(response.getState()).notifyUrl(trade.getNotifyUrl())
166   - .description(response.getMessage()).version(0).createdTime(now).modifiedTime(now).build();
  164 + .amount(trade.getAmount()).payerId(response.getPayerId()).outTradeNo(response.getOutTradeNo())
  165 + .outPayType(response.getOutPayType()).finishTime(response.getWhen()).state(response.getState())
  166 + .notifyUrl(trade.getNotifyUrl()).description(response.getMessage()).version(0)
  167 + .createdTime(now).modifiedTime(now).build();
167 168 onlinePaymentDao.insertOnlinePayment(payment);
168 169  
169 170 TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS,
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/util/MiniProPaymentConverter.java
... ... @@ -3,6 +3,7 @@ package com.diligrp.cashier.trade.util;
3 3 import com.diligrp.cashier.pipeline.Constants;
4 4 import com.diligrp.cashier.pipeline.domain.MiniProPrepayRequest;
5 5 import com.diligrp.cashier.shared.codec.IConverter;
  6 +import com.diligrp.cashier.shared.util.DateUtils;
6 7 import com.diligrp.cashier.trade.domain.CashierPayment;
7 8 import com.diligrp.cashier.trade.model.TradeOrder;
8 9 import org.springframework.util.Assert;
... ... @@ -31,8 +32,11 @@ public class MiniProPaymentConverter implements IConverter&lt;CashierPayment, MiniP
31 32 String openId = (String) params.get(Constants.PARAM_OPEN_ID);
32 33 Assert.notNull(openId, "params.openId missed");
33 34  
  35 + // 根据Trade超时时间,计算得出第三方支付通道的超时时间
  36 + long seconds = DateUtils.secondsDiff(tradeOrder.getCreatedTime(), when);
  37 + long timeout = Math.max(tradeOrder.getTimeout() - seconds, Constants.MIN_PIPELINE_TIMEOUT);
34 38 MiniProPrepayRequest prepayRequest = new MiniProPrepayRequest(paymentId, tradeOrder.getMaxAmount(),
35   - tradeOrder.getGoods(), tradeOrder.getDescription(), when, openId);
  39 + tradeOrder.getGoods(), tradeOrder.getDescription(), when, openId, timeout);
36 40 prepayRequest.putParams(params);
37 41 return prepayRequest;
38 42 }
... ...