Commit 65220cfeeffdbd45574f880099a0d53a8863acf9

Authored by huanggang
1 parent 07f54ce2

upgrade after testing

Showing 33 changed files with 575 additions and 127 deletions
cashier-boss/src/main/java/com/diligrp/cashier/boss/Constants.java
@@ -3,6 +3,8 @@ package com.diligrp.cashier.boss; @@ -3,6 +3,8 @@ package com.diligrp.cashier.boss;
3 public final class Constants { 3 public final class Constants {
4 // 商户信息缓存Key 4 // 商户信息缓存Key
5 public static final String MERCHANT_REDIS_KEY = "cashier:merchant:%s"; 5 public static final String MERCHANT_REDIS_KEY = "cashier:merchant:%s";
  6 + // 商户信息过期时长-单位秒 - 1个小时
  7 + public static final int MERCHANT_TIMEOUT_SECONDS = 60 * 60;
6 // TOKEN信息缓存Key 8 // TOKEN信息缓存Key
7 public static final String TOKEN_REDIS_KEY = "cashier:token:%s"; 9 public static final String TOKEN_REDIS_KEY = "cashier:token:%s";
8 // TOKEN参数名称 10 // TOKEN参数名称
@@ -11,8 +13,8 @@ public final class Constants { @@ -11,8 +13,8 @@ public final class Constants {
11 public static final String TOKEN_SIGN_ALGORITHM = "HmacSHA256"; 13 public static final String TOKEN_SIGN_ALGORITHM = "HmacSHA256";
12 // TOKEN的签名长度 14 // TOKEN的签名长度
13 public static final int TOKEN_SIGN_LENGTH = 8; 15 public static final int TOKEN_SIGN_LENGTH = 8;
14 - // TOKEN过期时长,单位秒  
15 - public static final long TOKEN_TIMEOUT_SECONDS = 60; 16 + // TOKEN过期时长,单位秒 - 两分钟
  17 + public static final long TOKEN_TIMEOUT_SECONDS = 120;
16 18
17 public final static String CONTENT_TYPE = "application/json;charset=UTF-8"; 19 public final static String CONTENT_TYPE = "application/json;charset=UTF-8";
18 20
cashier-boss/src/main/java/com/diligrp/cashier/boss/controller/CashierDeskController.java
@@ -35,6 +35,7 @@ public class CashierDeskController { @@ -35,6 +35,7 @@ public class CashierDeskController {
35 AssertUtils.notNull(request.getAmount(), "amount missed"); 35 AssertUtils.notNull(request.getAmount(), "amount missed");
36 AssertUtils.isTrue(request.getAmount() > 0, "Invalid amount"); 36 AssertUtils.isTrue(request.getAmount() > 0, "Invalid amount");
37 AssertUtils.notEmpty(request.getOutTradeNo(), "outTradeNo missed"); 37 AssertUtils.notEmpty(request.getOutTradeNo(), "outTradeNo missed");
  38 + AssertUtils.notEmpty(request.getRedirectUrl(), "redirectUrl missed");
38 39
39 CashierOrder cashierOrder = CashierOrderConverter.INSTANCE.convert(request); 40 CashierOrder cashierOrder = CashierOrderConverter.INSTANCE.convert(request);
40 Merchant merchant = merchantService.loadCashierMerchant(request.getMchId()); 41 Merchant merchant = merchantService.loadCashierMerchant(request.getMchId());
cashier-boss/src/main/java/com/diligrp/cashier/boss/domain/CashierOrderDTO.java
@@ -17,6 +17,8 @@ public class CashierOrderDTO { @@ -17,6 +17,8 @@ public class CashierOrderDTO {
17 private String outTradeNo; 17 private String outTradeNo;
18 // 回调地址 18 // 回调地址
19 private String notifyUrl; 19 private String notifyUrl;
  20 + // 页面回调地址
  21 + private String redirectUrl;
20 // 交易描述 22 // 交易描述
21 private String description; 23 private String description;
22 // 附加数据 24 // 附加数据
@@ -86,6 +88,14 @@ public class CashierOrderDTO { @@ -86,6 +88,14 @@ public class CashierOrderDTO {
86 this.notifyUrl = notifyUrl; 88 this.notifyUrl = notifyUrl;
87 } 89 }
88 90
  91 + public String getRedirectUrl() {
  92 + return redirectUrl;
  93 + }
  94 +
  95 + public void setRedirectUrl(String redirectUrl) {
  96 + this.redirectUrl = redirectUrl;
  97 + }
  98 +
89 public String getDescription() { 99 public String getDescription() {
90 return description; 100 return description;
91 } 101 }
cashier-boss/src/main/java/com/diligrp/cashier/boss/domain/CashierOrderToken.java
@@ -21,6 +21,8 @@ public class CashierOrderToken { @@ -21,6 +21,8 @@ public class CashierOrderToken {
21 private Integer cashierType; 21 private Integer cashierType;
22 // 业务系统用户标识 22 // 业务系统用户标识
23 private String userId; 23 private String userId;
  24 + // 页面回调地址
  25 + private String redirectUrl;
24 26
25 public static String encode(Long tokenId, SecretKeySpec secretKey) { 27 public static String encode(Long tokenId, SecretKeySpec secretKey) {
26 try { 28 try {
@@ -70,11 +72,12 @@ public class CashierOrderToken { @@ -70,11 +72,12 @@ public class CashierOrderToken {
70 public CashierOrderToken() { 72 public CashierOrderToken() {
71 } 73 }
72 74
73 - public CashierOrderToken(Long mchId, String tradeId, Integer cashierType, String userId) { 75 + public CashierOrderToken(Long mchId, String tradeId, Integer cashierType, String userId, String redirectUrl) {
74 this.mchId = mchId; 76 this.mchId = mchId;
75 this.tradeId = tradeId; 77 this.tradeId = tradeId;
76 this.cashierType = cashierType; 78 this.cashierType = cashierType;
77 this.userId = userId; 79 this.userId = userId;
  80 + this.redirectUrl = redirectUrl;
78 } 81 }
79 82
80 public Long getMchId() { 83 public Long getMchId() {
@@ -109,6 +112,14 @@ public class CashierOrderToken { @@ -109,6 +112,14 @@ public class CashierOrderToken {
109 this.userId = userId; 112 this.userId = userId;
110 } 113 }
111 114
  115 + public String getRedirectUrl() {
  116 + return redirectUrl;
  117 + }
  118 +
  119 + public void setRedirectUrl(String redirectUrl) {
  120 + this.redirectUrl = redirectUrl;
  121 + }
  122 +
112 @Override 123 @Override
113 public String toString() { 124 public String toString() {
114 return JsonUtils.toJsonString(this); 125 return JsonUtils.toJsonString(this);
cashier-boss/src/main/java/com/diligrp/cashier/boss/domain/CashierOrderInfo.java renamed to cashier-boss/src/main/java/com/diligrp/cashier/boss/domain/CashierOrderVO.java
1 package com.diligrp.cashier.boss.domain; 1 package com.diligrp.cashier.boss.domain;
2 2
  3 +import com.diligrp.cashier.pipeline.type.ChannelType;
  4 +
3 import java.util.List; 5 import java.util.List;
4 6
5 -public class CashierOrderInfo { 7 +public class CashierOrderVO {
6 // 业务系统用户标识 8 // 业务系统用户标识
7 private final String userId; 9 private final String userId;
  10 + // 页面回调地址
  11 + private final String redirectUrl;
8 // 支付通道 12 // 支付通道
9 private final List<PaymentPipeline> pipelines; 13 private final List<PaymentPipeline> pipelines;
10 14
11 - public CashierOrderInfo(String userId, List<PaymentPipeline> pipelines) { 15 + public CashierOrderVO(String userId, String redirectUrl, List<PaymentPipeline> pipelines) {
12 this.userId = userId; 16 this.userId = userId;
  17 + this.redirectUrl = redirectUrl;
13 this.pipelines = pipelines; 18 this.pipelines = pipelines;
14 } 19 }
15 20
@@ -17,6 +22,10 @@ public class CashierOrderInfo { @@ -17,6 +22,10 @@ public class CashierOrderInfo {
17 return userId; 22 return userId;
18 } 23 }
19 24
  25 + public String getRedirectUrl() {
  26 + return redirectUrl;
  27 + }
  28 +
20 public List<PaymentPipeline> getPipelines() { 29 public List<PaymentPipeline> getPipelines() {
21 return pipelines; 30 return pipelines;
22 } 31 }
@@ -27,9 +36,12 @@ public class CashierOrderInfo { @@ -27,9 +36,12 @@ public class CashierOrderInfo {
27 // 支付渠道 36 // 支付渠道
28 private final Integer channelId; 37 private final Integer channelId;
29 38
30 - public PaymentPipeline(Long pipelineId, Integer channelId) { 39 + private final String channelName;
  40 +
  41 + public PaymentPipeline(Long pipelineId, ChannelType channelType) {
31 this.pipelineId = pipelineId; 42 this.pipelineId = pipelineId;
32 - this.channelId = channelId; 43 + this.channelId = channelType.getCode();
  44 + this.channelName = channelType.getName();
33 } 45 }
34 46
35 public Long getPipelineId() { 47 public Long getPipelineId() {
@@ -39,5 +51,9 @@ public class CashierOrderInfo { @@ -39,5 +51,9 @@ public class CashierOrderInfo {
39 public Integer getChannelId() { 51 public Integer getChannelId() {
40 return channelId; 52 return channelId;
41 } 53 }
  54 +
  55 + public String getChannelName() {
  56 + return channelName;
  57 + }
42 } 58 }
43 } 59 }
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/ICashierDeskService.java
1 package com.diligrp.cashier.boss.service; 1 package com.diligrp.cashier.boss.service;
2 2
3 -import com.diligrp.cashier.boss.domain.CashierOrderInfo; 3 +import com.diligrp.cashier.boss.domain.CashierOrderVO;
4 import com.diligrp.cashier.boss.domain.CashierPaymentUrl; 4 import com.diligrp.cashier.boss.domain.CashierPaymentUrl;
5 import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus; 5 import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus;
6 import com.diligrp.cashier.trade.domain.*; 6 import com.diligrp.cashier.trade.domain.*;
@@ -18,7 +18,7 @@ public interface ICashierDeskService { @@ -18,7 +18,7 @@ public interface ICashierDeskService {
18 /** 18 /**
19 * 根据收银台TOKEN信息获取订单信息 19 * 根据收银台TOKEN信息获取订单信息
20 */ 20 */
21 - CashierOrderInfo getCashierOrderByToken(String token); 21 + CashierOrderVO getCashierOrderByToken(String token);
22 22
23 /** 23 /**
24 * 提交收银台支付 24 * 提交收银台支付
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/impl/CashierDeskManager.java 0 → 100644
  1 +package com.diligrp.cashier.boss.service.impl;
  2 +
  3 +import com.diligrp.cashier.boss.domain.CashierPaymentUrl;
  4 +import com.diligrp.cashier.boss.service.ICashierDeskService;
  5 +import com.diligrp.cashier.boss.service.IMerchantService;
  6 +import com.diligrp.cashier.boss.util.CashierOrderConverter2;
  7 +import com.diligrp.cashier.boss.util.OnlineRefundConverter;
  8 +import com.diligrp.cashier.shared.spi.ICashierDeskManager;
  9 +import com.diligrp.cashier.shared.spi.domain.CashierOrderBO;
  10 +import com.diligrp.cashier.shared.spi.domain.CashierRefundBO;
  11 +import com.diligrp.cashier.shared.spi.domain.PaymentUrlBO;
  12 +import com.diligrp.cashier.shared.spi.domain.RefundResultBO;
  13 +import com.diligrp.cashier.shared.util.AssertUtils;
  14 +import com.diligrp.cashier.trade.domain.CashierOrder;
  15 +import com.diligrp.cashier.trade.domain.Merchant;
  16 +import com.diligrp.cashier.trade.domain.OnlineRefundDTO;
  17 +import com.diligrp.cashier.trade.domain.OnlineRefundResult;
  18 +import jakarta.annotation.Resource;
  19 +import org.springframework.stereotype.Service;
  20 +
  21 +@Service("cashierDeskManager")
  22 +public class CashierDeskManager implements ICashierDeskManager {
  23 +
  24 + @Resource
  25 + private ICashierDeskService cashierDeskService;
  26 +
  27 + @Resource
  28 + private IMerchantService merchantService;
  29 +
  30 + @Override
  31 + public PaymentUrlBO submitOrder(CashierOrderBO request) {
  32 + // 基本参数校验
  33 + AssertUtils.notNull(request.getMchId(), "mchId missed");
  34 + AssertUtils.notEmpty(request.getUserId(), "userId missed");
  35 + AssertUtils.notNull(request.getCashierType(), "cashierType missed");
  36 + AssertUtils.notEmpty(request.getGoods(), "goods missed");
  37 + AssertUtils.notNull(request.getAmount(), "amount missed");
  38 + AssertUtils.isTrue(request.getAmount() > 0, "Invalid amount");
  39 + AssertUtils.notEmpty(request.getOutTradeNo(), "outTradeNo missed");
  40 + AssertUtils.notEmpty(request.getRedirectUrl(), "redirectUrl missed");
  41 +
  42 + CashierOrder cashierOrder = CashierOrderConverter2.INSTANCE.convert(request);
  43 + Merchant merchant = merchantService.loadCashierMerchant(request.getMchId());
  44 + CashierPaymentUrl paymentUrl = cashierDeskService.doSubmit(merchant, cashierOrder);
  45 + return new PaymentUrlBO(paymentUrl.tradeId(), paymentUrl.paymentUrl());
  46 + }
  47 +
  48 + @Override
  49 + public RefundResultBO doRefund(CashierRefundBO request) {
  50 + AssertUtils.notEmpty(request.getTradeId(), "tradeId missed");
  51 + AssertUtils.notNull(request.getAmount(), "amount missed");
  52 + AssertUtils.isTrue(request.getAmount() > 0, "Invalid amount");
  53 +
  54 + OnlineRefundDTO onlineRefund = OnlineRefundConverter.INSTANCE.convert(request);
  55 + OnlineRefundResult response = cashierDeskService.sendRefundRequest(onlineRefund);
  56 + return new RefundResultBO(response.getRefundId(), response.getTradeId(), response.getState(),
  57 + response.getWhen(), response.getMessage());
  58 + }
  59 +}
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/impl/CashierDeskServiceImpl.java
@@ -2,7 +2,7 @@ package com.diligrp.cashier.boss.service.impl; @@ -2,7 +2,7 @@ package com.diligrp.cashier.boss.service.impl;
2 2
3 import com.diligrp.cashier.boss.CashierDeskProperties; 3 import com.diligrp.cashier.boss.CashierDeskProperties;
4 import com.diligrp.cashier.boss.Constants; 4 import com.diligrp.cashier.boss.Constants;
5 -import com.diligrp.cashier.boss.domain.CashierOrderInfo; 5 +import com.diligrp.cashier.boss.domain.CashierOrderVO;
6 import com.diligrp.cashier.boss.domain.CashierOrderToken; 6 import com.diligrp.cashier.boss.domain.CashierOrderToken;
7 import com.diligrp.cashier.boss.domain.CashierPaymentUrl; 7 import com.diligrp.cashier.boss.domain.CashierPaymentUrl;
8 import com.diligrp.cashier.boss.exception.BossServiceException; 8 import com.diligrp.cashier.boss.exception.BossServiceException;
@@ -53,7 +53,8 @@ public class CashierDeskServiceImpl implements ICashierDeskService { @@ -53,7 +53,8 @@ public class CashierDeskServiceImpl implements ICashierDeskService {
53 public CashierPaymentUrl doSubmit(Merchant merchant, CashierOrder order) { 53 public CashierPaymentUrl doSubmit(Merchant merchant, CashierOrder order) {
54 String tradeId = cashierPaymentService.doSubmit(merchant, order); 54 String tradeId = cashierPaymentService.doSubmit(merchant, order);
55 String token = CashierOrderToken.encode(Long.valueOf(tradeId), cashierDeskProperties.getSecretKey()); 55 String token = CashierOrderToken.encode(Long.valueOf(tradeId), cashierDeskProperties.getSecretKey());
56 - CashierOrderToken orderToken = new CashierOrderToken(merchant.getMchId(), tradeId, order.getType().getCode(), order.getUserId()); 56 + CashierOrderToken orderToken = new CashierOrderToken(merchant.getMchId(), tradeId, order.getType().getCode(),
  57 + order.getUserId(), order.getRedirectUrl());
57 58
58 String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token); 59 String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token);
59 stringRedisTemplate.opsForValue().set(tokenKey, orderToken.toString(), Constants.TOKEN_TIMEOUT_SECONDS, TimeUnit.SECONDS); 60 stringRedisTemplate.opsForValue().set(tokenKey, orderToken.toString(), Constants.TOKEN_TIMEOUT_SECONDS, TimeUnit.SECONDS);
@@ -68,12 +69,12 @@ public class CashierDeskServiceImpl implements ICashierDeskService { @@ -68,12 +69,12 @@ public class CashierDeskServiceImpl implements ICashierDeskService {
68 } 69 }
69 70
70 @Override 71 @Override
71 - public CashierOrderInfo getCashierOrderByToken(String token) { 72 + public CashierOrderVO getCashierOrderByToken(String token) {
72 CashierOrderToken.decode(token, cashierDeskProperties.getSecretKey()); 73 CashierOrderToken.decode(token, cashierDeskProperties.getSecretKey());
73 String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token); 74 String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token);
74 String payload = stringRedisTemplate.opsForValue().get(tokenKey); 75 String payload = stringRedisTemplate.opsForValue().get(tokenKey);
75 if (ObjectUtils.isEmpty(payload)) { 76 if (ObjectUtils.isEmpty(payload)) {
76 - throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "收银台订单超时过期,不能支付"); 77 + throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "TOKEN超时过期,不能完成支付");
77 } 78 }
78 79
79 CashierOrderToken orderToken = CashierOrderToken.decodeCashierOrder(payload); 80 CashierOrderToken orderToken = CashierOrderToken.decodeCashierOrder(payload);
@@ -85,9 +86,9 @@ public class CashierDeskServiceImpl implements ICashierDeskService { @@ -85,9 +86,9 @@ public class CashierDeskServiceImpl implements ICashierDeskService {
85 if (pipelines.isEmpty()) { 86 if (pipelines.isEmpty()) {
86 throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "商户无可用的支付通道"); 87 throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "商户无可用的支付通道");
87 } 88 }
88 - List<CashierOrderInfo.PaymentPipeline> pipelineList = pipelines.stream().map(pipeline ->  
89 - new CashierOrderInfo.PaymentPipeline(pipeline.pipelineId(), pipeline.supportedChannel().getCode())).toList();  
90 - return new CashierOrderInfo(orderToken.getUserId(), pipelineList); 89 + List<CashierOrderVO.PaymentPipeline> pipelineList = pipelines.stream().map(pipeline ->
  90 + new CashierOrderVO.PaymentPipeline(pipeline.pipelineId(), pipeline.supportedChannel())).toList();
  91 + return new CashierOrderVO(orderToken.getUserId(), orderToken.getRedirectUrl(), pipelineList);
91 } 92 }
92 93
93 /** 94 /**
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/impl/MerchantServiceImpl.java
@@ -13,6 +13,7 @@ import org.springframework.data.redis.core.StringRedisTemplate; @@ -13,6 +13,7 @@ import org.springframework.data.redis.core.StringRedisTemplate;
13 import org.springframework.stereotype.Service; 13 import org.springframework.stereotype.Service;
14 14
15 import java.util.Objects; 15 import java.util.Objects;
  16 +import java.util.concurrent.TimeUnit;
16 17
17 /** 18 /**
18 * 支付平台接入许可服务 19 * 支付平台接入许可服务
@@ -36,8 +37,8 @@ public class MerchantServiceImpl implements IMerchantService { @@ -36,8 +37,8 @@ public class MerchantServiceImpl implements IMerchantService {
36 Merchant merchant = Merchant.decode(payload); 37 Merchant merchant = Merchant.decode(payload);
37 if (Objects.isNull(merchant)) { 38 if (Objects.isNull(merchant)) {
38 merchant = merchantDao.findByMchId(mchId).map(new MerchantConverter(cashierDeskProperties)::convert) 39 merchant = merchantDao.findByMchId(mchId).map(new MerchantConverter(cashierDeskProperties)::convert)
39 - .orElseThrow(() -> new BossServiceException(ErrorCode.OBJECT_NOT_FOUND, "商家信息未注册"));  
40 - stringRedisTemplate.opsForValue().set(cacheKey, merchant.toString()); 40 + .orElseThrow(() -> new BossServiceException(ErrorCode.OBJECT_NOT_FOUND, "商户信息未注册: " + mchId));
  41 + stringRedisTemplate.opsForValue().set(cacheKey, merchant.toString(), Constants.MERCHANT_TIMEOUT_SECONDS, TimeUnit.SECONDS);
41 } 42 }
42 43
43 return merchant; 44 return merchant;
cashier-boss/src/main/java/com/diligrp/cashier/boss/util/CashierOrderConverter.java
@@ -19,6 +19,7 @@ public class CashierOrderConverter implements IConverter&lt;CashierOrderDTO, Cashie @@ -19,6 +19,7 @@ public class CashierOrderConverter implements IConverter&lt;CashierOrderDTO, Cashie
19 cashierOrder.setTimeout(cashierOrderDTO.getTimeout()); 19 cashierOrder.setTimeout(cashierOrderDTO.getTimeout());
20 cashierOrder.setOutTradeNo(cashierOrderDTO.getOutTradeNo()); 20 cashierOrder.setOutTradeNo(cashierOrderDTO.getOutTradeNo());
21 cashierOrder.setNotifyUrl(cashierOrderDTO.getNotifyUrl()); 21 cashierOrder.setNotifyUrl(cashierOrderDTO.getNotifyUrl());
  22 + cashierOrder.setRedirectUrl(cashierOrderDTO.getRedirectUrl());
22 cashierOrder.setDescription(cashierOrderDTO.getDescription()); 23 cashierOrder.setDescription(cashierOrderDTO.getDescription());
23 cashierOrder.setAttach(cashierOrderDTO.getAttach()); 24 cashierOrder.setAttach(cashierOrderDTO.getAttach());
24 return cashierOrder; 25 return cashierOrder;
cashier-boss/src/main/java/com/diligrp/cashier/boss/util/CashierOrderConverter2.java 0 → 100644
  1 +package com.diligrp.cashier.boss.util;
  2 +
  3 +import com.diligrp.cashier.pipeline.type.CashierType;
  4 +import com.diligrp.cashier.shared.codec.IConverter;
  5 +import com.diligrp.cashier.shared.spi.domain.CashierOrderBO;
  6 +import com.diligrp.cashier.trade.domain.CashierOrder;
  7 +
  8 +public class CashierOrderConverter2 implements IConverter<CashierOrderBO, CashierOrder> {
  9 +
  10 + public static IConverter<CashierOrderBO, CashierOrder> INSTANCE = new CashierOrderConverter2();
  11 +
  12 + @Override
  13 + public CashierOrder convert(CashierOrderBO cashierOrderDTO) {
  14 + CashierOrder cashierOrder = new CashierOrder();
  15 + cashierOrder.setUserId(cashierOrderDTO.getUserId());
  16 + cashierOrder.setType(CashierType.getByCode(cashierOrderDTO.getCashierType()));
  17 + cashierOrder.setGoods(cashierOrderDTO.getGoods());
  18 + cashierOrder.setAmount(cashierOrderDTO.getAmount());
  19 + cashierOrder.setTimeout(cashierOrderDTO.getTimeout());
  20 + cashierOrder.setOutTradeNo(cashierOrderDTO.getOutTradeNo());
  21 + cashierOrder.setNotifyUrl(cashierOrderDTO.getNotifyUrl());
  22 + cashierOrder.setRedirectUrl(cashierOrderDTO.getRedirectUrl());
  23 + cashierOrder.setDescription(cashierOrderDTO.getDescription());
  24 + cashierOrder.setAttach(cashierOrderDTO.getAttach());
  25 + return cashierOrder;
  26 + }
  27 +}
cashier-boss/src/main/java/com/diligrp/cashier/boss/util/OnlineRefundConverter.java 0 → 100644
  1 +package com.diligrp.cashier.boss.util;
  2 +
  3 +import com.diligrp.cashier.shared.codec.IConverter;
  4 +import com.diligrp.cashier.shared.spi.domain.CashierRefundBO;
  5 +import com.diligrp.cashier.trade.domain.OnlineRefundDTO;
  6 +
  7 +public class OnlineRefundConverter implements IConverter<CashierRefundBO, OnlineRefundDTO> {
  8 +
  9 + public static IConverter<CashierRefundBO, OnlineRefundDTO> INSTANCE = new OnlineRefundConverter();
  10 +
  11 + @Override
  12 + public OnlineRefundDTO convert(CashierRefundBO cashierRefund) {
  13 + OnlineRefundDTO onlineRefund = new OnlineRefundDTO();
  14 + onlineRefund.setTradeId(cashierRefund.getTradeId());
  15 + onlineRefund.setAmount(cashierRefund.getAmount());
  16 + onlineRefund.setNotifyUrl(cashierRefund.getNotifyUrl());
  17 + onlineRefund.setDescription(cashierRefund.getDescription());
  18 + return onlineRefund;
  19 + }
  20 +}
cashier-boss/src/main/resources/logback-spring.xml
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 </encoder> 26 </encoder>
27 <!-- 过滤器:只输出INFO及以上级别,减少控制台冗余 --> 27 <!-- 过滤器:只输出INFO及以上级别,减少控制台冗余 -->
28 <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> 28 <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
29 - <level>INFO</level> 29 + <level>DEBUG</level>
30 </filter> 30 </filter>
31 </appender> 31 </appender>
32 32
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/ChannelType.java
@@ -15,11 +15,11 @@ import java.util.stream.Stream; @@ -15,11 +15,11 @@ import java.util.stream.Stream;
15 */ 15 */
16 public enum ChannelType implements IEnumType { 16 public enum ChannelType implements IEnumType {
17 17
18 - WXPAY("微信渠道", 10), 18 + WXPAY("微信支付", 10),
19 19
20 - ALIPAY("支付宝渠道", 11), 20 + ALIPAY("支付宝", 11),
21 21
22 - DILIPAY("地利渠道", 19), // 地利园区卡支付 22 + DILIPAY("园区卡支付", 19),
23 23
24 ICBC("工商银行", 20), 24 ICBC("工商银行", 20),
25 25
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/ICashierDeskManager.java 0 → 100644
  1 +package com.diligrp.cashier.shared.spi;
  2 +
  3 +import com.diligrp.cashier.shared.spi.domain.CashierOrderBO;
  4 +import com.diligrp.cashier.shared.spi.domain.CashierRefundBO;
  5 +import com.diligrp.cashier.shared.spi.domain.PaymentUrlBO;
  6 +import com.diligrp.cashier.shared.spi.domain.RefundResultBO;
  7 +
  8 +public interface ICashierDeskManager {
  9 +
  10 + /**
  11 + * 提交收银台订单
  12 + */
  13 + PaymentUrlBO submitOrder(CashierOrderBO request);
  14 +
  15 + /**
  16 + * 交易退款
  17 + */
  18 + RefundResultBO doRefund(CashierRefundBO request);
  19 +}
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/IPaymentEventListener.java
1 package com.diligrp.cashier.shared.spi; 1 package com.diligrp.cashier.shared.spi;
2 2
  3 +import com.diligrp.cashier.shared.spi.domain.PaymentResultBO;
  4 +import com.diligrp.cashier.shared.spi.domain.RefundResultBO;
  5 +
3 public interface IPaymentEventListener { 6 public interface IPaymentEventListener {
4 7
5 - void onEvent(PaymentEvent event); 8 + void onEvent(PaymentResultBO event);
6 9
7 - void onEvent(RefundEvent event); 10 + void onEvent(RefundResultBO event);
8 } 11 }
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/domain/CashierOrderBO.java 0 → 100644
  1 +package com.diligrp.cashier.shared.spi.domain;
  2 +
  3 +public class CashierOrderBO {
  4 + // 接入商户
  5 + private Long mchId;
  6 + // 业务系统用户标识
  7 + private String userId;
  8 + // 收银台类型 - H5收银台等
  9 + private Integer cashierType;
  10 + // 商品描述
  11 + private String goods;
  12 + // 申请金额
  13 + private Long amount;
  14 + // 超时间隔时间 - 秒
  15 + private Integer timeout;
  16 + // 外部流水号
  17 + private String outTradeNo;
  18 + // 回调地址
  19 + private String notifyUrl;
  20 + // 页面回调地址
  21 + private String redirectUrl;
  22 + // 交易描述
  23 + private String description;
  24 + // 附加数据
  25 + private String attach;
  26 +
  27 + public Long getMchId() {
  28 + return mchId;
  29 + }
  30 +
  31 + public void setMchId(Long mchId) {
  32 + this.mchId = mchId;
  33 + }
  34 +
  35 + public String getUserId() {
  36 + return userId;
  37 + }
  38 +
  39 + public void setUserId(String userId) {
  40 + this.userId = userId;
  41 + }
  42 +
  43 + public Integer getCashierType() {
  44 + return cashierType;
  45 + }
  46 +
  47 + public void setCashierType(Integer cashierType) {
  48 + this.cashierType = cashierType;
  49 + }
  50 +
  51 + public String getGoods() {
  52 + return goods;
  53 + }
  54 +
  55 + public void setGoods(String goods) {
  56 + this.goods = goods;
  57 + }
  58 +
  59 + public Long getAmount() {
  60 + return amount;
  61 + }
  62 +
  63 + public void setAmount(Long amount) {
  64 + this.amount = amount;
  65 + }
  66 +
  67 + public Integer getTimeout() {
  68 + return timeout;
  69 + }
  70 +
  71 + public void setTimeout(Integer timeout) {
  72 + this.timeout = timeout;
  73 + }
  74 +
  75 + public String getOutTradeNo() {
  76 + return outTradeNo;
  77 + }
  78 +
  79 + public void setOutTradeNo(String outTradeNo) {
  80 + this.outTradeNo = outTradeNo;
  81 + }
  82 +
  83 + public String getNotifyUrl() {
  84 + return notifyUrl;
  85 + }
  86 +
  87 + public void setNotifyUrl(String notifyUrl) {
  88 + this.notifyUrl = notifyUrl;
  89 + }
  90 +
  91 + public String getRedirectUrl() {
  92 + return redirectUrl;
  93 + }
  94 +
  95 + public void setRedirectUrl(String redirectUrl) {
  96 + this.redirectUrl = redirectUrl;
  97 + }
  98 +
  99 + public String getDescription() {
  100 + return description;
  101 + }
  102 +
  103 + public void setDescription(String description) {
  104 + this.description = description;
  105 + }
  106 +
  107 + public String getAttach() {
  108 + return attach;
  109 + }
  110 +
  111 + public void setAttach(String attach) {
  112 + this.attach = attach;
  113 + }
  114 +}
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/domain/CashierRefundBO.java 0 → 100644
  1 +package com.diligrp.cashier.shared.spi.domain;
  2 +
  3 +/**
  4 + * 退款申请
  5 + */
  6 +public class CashierRefundBO {
  7 + // 原支付号
  8 + private final String tradeId;
  9 + // 退款金额
  10 + private final Long amount;
  11 + // 回调地址
  12 + private final String notifyUrl;
  13 + // 退款原因
  14 + private final String description;
  15 +
  16 + public CashierRefundBO(String tradeId, Long amount, String notifyUrl, String description) {
  17 + this.tradeId = tradeId;
  18 + this.amount = amount;
  19 + this.notifyUrl = notifyUrl;
  20 + this.description = description;
  21 + }
  22 +
  23 + public String getTradeId() {
  24 + return tradeId;
  25 + }
  26 +
  27 + public Long getAmount() {
  28 + return amount;
  29 + }
  30 +
  31 + public String getNotifyUrl() {
  32 + return notifyUrl;
  33 + }
  34 +
  35 + public String getDescription() {
  36 + return description;
  37 + }
  38 +}
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/PaymentEvent.java renamed to cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/domain/PaymentResultBO.java
1 -package com.diligrp.cashier.shared.spi; 1 +package com.diligrp.cashier.shared.spi.domain;
2 2
3 import java.time.LocalDateTime; 3 import java.time.LocalDateTime;
4 4
5 -public class PaymentEvent { 5 +public class PaymentResultBO {
6 // 交易号 6 // 交易号
7 private final String tradeId; 7 private final String tradeId;
8 // 支付ID 8 // 支付ID
@@ -20,8 +20,8 @@ public class PaymentEvent { @@ -20,8 +20,8 @@ public class PaymentEvent {
20 // 交易描述 20 // 交易描述
21 private final String message; 21 private final String message;
22 22
23 - public PaymentEvent(String tradeId, String paymentId, int state, String outTradeNo, Integer outPayType,  
24 - String payerId, LocalDateTime when, String message) { 23 + public PaymentResultBO(String tradeId, String paymentId, Integer state, String outTradeNo, Integer outPayType,
  24 + String payerId, LocalDateTime when, String message) {
25 this.tradeId = tradeId; 25 this.tradeId = tradeId;
26 this.paymentId = paymentId; 26 this.paymentId = paymentId;
27 this.state = state; 27 this.state = state;
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/domain/PaymentUrlBO.java 0 → 100644
  1 +package com.diligrp.cashier.shared.spi.domain;
  2 +
  3 +public record PaymentUrlBO(String tradeId, String paymentUrl) {
  4 +}
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/RefundEvent.java renamed to cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/domain/RefundResultBO.java
1 -package com.diligrp.cashier.shared.spi; 1 +package com.diligrp.cashier.shared.spi.domain;
2 2
3 import java.time.LocalDateTime; 3 import java.time.LocalDateTime;
4 4
5 -public class RefundEvent { 5 +public class RefundResultBO {
6 // 退款单号 6 // 退款单号
7 private final String refundId; 7 private final String refundId;
8 // 原支付ID 8 // 原支付ID
@@ -14,7 +14,7 @@ public class RefundEvent { @@ -14,7 +14,7 @@ public class RefundEvent {
14 // 交易描述 14 // 交易描述
15 private final String message; 15 private final String message;
16 16
17 - public RefundEvent(String refundId, String tradeId, int state, LocalDateTime when, String message) { 17 + public RefundResultBO(String refundId, String tradeId, int state, LocalDateTime when, String message) {
18 this.refundId = refundId; 18 this.refundId = refundId;
19 this.tradeId = tradeId; 19 this.tradeId = tradeId;
20 this.state = state; 20 this.state = state;
cashier-trade/src/main/java/com/diligrp/cashier/trade/Constants.java
@@ -11,16 +11,19 @@ public final class Constants { @@ -11,16 +11,19 @@ public final class Constants {
11 // 支付通道延时路由KEY 11 // 支付通道延时路由KEY
12 public static final String PAYMENT_DELAY_KEY = "cashier.payment.delayKey"; 12 public static final String PAYMENT_DELAY_KEY = "cashier.payment.delayKey";
13 13
14 - // 默认订单超时时间-秒, 十分钟  
15 - public static final int DEFAULT_ORDER_TIMEOUT_SECONDS = 10 * 60 * 1000; 14 + // 默认交易订单超时时间-秒, 5分钟
  15 + public static final int DEFAULT_TRADE_TIMEOUT = 5 * 60;
16 16
17 - // 最小订单超时时间-秒, 一分钟  
18 - public static final int MIN_ORDER_TIMEOUT_SECONDS = 60 * 1000; 17 + // 最大交易订单超时时间-秒, 10分钟
  18 + public static final int MAX_TRADE_TIMEOUT = 10 * 60;
  19 +
  20 + // 最小交易订单超时时间-秒, 1分钟
  21 + public static final int MIN_TRADE_TIMEOUT = 60;
19 22
20 // 支付订单分布式锁 23 // 支付订单分布式锁
21 public static final String TRADE_LOCK_REDIS_KEY = "cashier:lock:trade:%s"; 24 public static final String TRADE_LOCK_REDIS_KEY = "cashier:lock:trade:%s";
22 25
23 - // 支付订单分布式锁超时时长-秒  
24 - public static final int TRADE_LOCK_TIMEOUT_SECONDS = 15 * 1000; 26 + // 支付订单分布式锁超时时长-秒, 15秒
  27 + public static final int TRADE_LOCK_TIMEOUT = 15;
25 28
26 } 29 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/CashierOrder.java
@@ -17,6 +17,8 @@ public class CashierOrder { @@ -17,6 +17,8 @@ public class CashierOrder {
17 private String outTradeNo; 17 private String outTradeNo;
18 // 回调地址 18 // 回调地址
19 private String notifyUrl; 19 private String notifyUrl;
  20 + // 页面回调地址
  21 + private String redirectUrl;
20 // 交易描述 22 // 交易描述
21 private String description; 23 private String description;
22 // 附加数据 24 // 附加数据
@@ -78,6 +80,14 @@ public class CashierOrder { @@ -78,6 +80,14 @@ public class CashierOrder {
78 this.notifyUrl = notifyUrl; 80 this.notifyUrl = notifyUrl;
79 } 81 }
80 82
  83 + public String getRedirectUrl() {
  84 + return redirectUrl;
  85 + }
  86 +
  87 + public void setRedirectUrl(String redirectUrl) {
  88 + this.redirectUrl = redirectUrl;
  89 + }
  90 +
81 public String getDescription() { 91 public String getDescription() {
82 return description; 92 return description;
83 } 93 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/MerchantParams.java
@@ -7,7 +7,6 @@ import java.util.Objects; @@ -7,7 +7,6 @@ import java.util.Objects;
7 public class MerchantParams { 7 public class MerchantParams {
8 // 收银台配置 8 // 收银台配置
9 private CashierParams cashier; 9 private CashierParams cashier;
10 - // TODO: 支付结果页面-跳转大润发使用  
11 10
12 public static MerchantParams decode(String params) { 11 public static MerchantParams decode(String params) {
13 return JsonUtils.fromJsonString(params, MerchantParams.class); 12 return JsonUtils.fromJsonString(params, MerchantParams.class);
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/OnlinePaymentResult.java
@@ -2,14 +2,30 @@ package com.diligrp.cashier.trade.domain; @@ -2,14 +2,30 @@ package com.diligrp.cashier.trade.domain;
2 2
3 import com.diligrp.cashier.pipeline.type.OutPaymentType; 3 import com.diligrp.cashier.pipeline.type.OutPaymentType;
4 import com.diligrp.cashier.pipeline.type.PaymentState; 4 import com.diligrp.cashier.pipeline.type.PaymentState;
5 -import com.diligrp.cashier.shared.spi.PaymentEvent;  
6 5
7 import java.time.LocalDateTime; 6 import java.time.LocalDateTime;
8 7
9 /** 8 /**
10 * 在线支付结果 - 用于业务系统支付结果通知 9 * 在线支付结果 - 用于业务系统支付结果通知
11 */ 10 */
12 -public class OnlinePaymentResult extends PaymentEvent { 11 +public class OnlinePaymentResult {
  12 + // 交易号
  13 + private final String tradeId;
  14 + // 支付ID
  15 + private final String paymentId;
  16 + // 支付状态
  17 + private final Integer state;
  18 + // 业务系统订单号
  19 + private final String outTradeNo;
  20 + // 实际支付方式
  21 + private final Integer outPayType;
  22 + // 支付人信息
  23 + private final String payerId;
  24 + // 发生时间
  25 + private final LocalDateTime when;
  26 + // 交易描述
  27 + private final String message;
  28 +
13 public static OnlinePaymentResult of(String tradeId, String paymentId, PaymentState state, String outTradeNo, 29 public static OnlinePaymentResult of(String tradeId, String paymentId, PaymentState state, String outTradeNo,
14 OutPaymentType outPayType, String payerId, LocalDateTime when, String message) { 30 OutPaymentType outPayType, String payerId, LocalDateTime when, String message) {
15 Integer outPayTypeCode = outPayType != null ? outPayType.getCode() : null; 31 Integer outPayTypeCode = outPayType != null ? outPayType.getCode() : null;
@@ -18,6 +34,45 @@ public class OnlinePaymentResult extends PaymentEvent { @@ -18,6 +34,45 @@ public class OnlinePaymentResult extends PaymentEvent {
18 34
19 public OnlinePaymentResult(String tradeId, String paymentId, int state, String outTradeNo, Integer outPayType, 35 public OnlinePaymentResult(String tradeId, String paymentId, int state, String outTradeNo, Integer outPayType,
20 String payerId, LocalDateTime when, String message) { 36 String payerId, LocalDateTime when, String message) {
21 - super(tradeId, paymentId, state, outTradeNo, outPayType, payerId, when, message); 37 + this.tradeId = tradeId;
  38 + this.paymentId = paymentId;
  39 + this.state = state;
  40 + this.outTradeNo = outTradeNo;
  41 + this.outPayType = outPayType;
  42 + this.payerId = payerId;
  43 + this.when = when;
  44 + this.message = message;
  45 + }
  46 +
  47 + public String getTradeId() {
  48 + return tradeId;
  49 + }
  50 +
  51 + public String getPaymentId() {
  52 + return paymentId;
  53 + }
  54 +
  55 + public Integer getState() {
  56 + return state;
  57 + }
  58 +
  59 + public String getOutTradeNo() {
  60 + return outTradeNo;
  61 + }
  62 +
  63 + public Integer getOutPayType() {
  64 + return outPayType;
  65 + }
  66 +
  67 + public String getPayerId() {
  68 + return payerId;
  69 + }
  70 +
  71 + public LocalDateTime getWhen() {
  72 + return when;
  73 + }
  74 +
  75 + public String getMessage() {
  76 + return message;
22 } 77 }
23 } 78 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/OnlineRefundDTO.java
@@ -9,7 +9,7 @@ public class OnlineRefundDTO { @@ -9,7 +9,7 @@ public class OnlineRefundDTO {
9 // 退款金额 9 // 退款金额
10 private Long amount; 10 private Long amount;
11 // 回调地址 11 // 回调地址
12 - private String notifyUri; 12 + private String notifyUrl;
13 // 退款原因 13 // 退款原因
14 private String description; 14 private String description;
15 15
@@ -29,12 +29,12 @@ public class OnlineRefundDTO { @@ -29,12 +29,12 @@ public class OnlineRefundDTO {
29 this.amount = amount; 29 this.amount = amount;
30 } 30 }
31 31
32 - public String getNotifyUri() {  
33 - return notifyUri; 32 + public String getNotifyUrl() {
  33 + return notifyUrl;
34 } 34 }
35 35
36 - public void setNotifyUri(String notifyUri) {  
37 - this.notifyUri = notifyUri; 36 + public void setNotifyUrl(String notifyUrl) {
  37 + this.notifyUrl = notifyUrl;
38 } 38 }
39 39
40 public String getDescription() { 40 public String getDescription() {
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/OnlineRefundResult.java
1 package com.diligrp.cashier.trade.domain; 1 package com.diligrp.cashier.trade.domain;
2 2
3 -import com.diligrp.cashier.shared.spi.RefundEvent;  
4 -  
5 import java.time.LocalDateTime; 3 import java.time.LocalDateTime;
6 4
7 /** 5 /**
8 * 退款结果 6 * 退款结果
9 */ 7 */
10 -public class OnlineRefundResult extends RefundEvent { 8 +public class OnlineRefundResult {
  9 + // 退款单号
  10 + private final String refundId;
  11 + // 原支付ID
  12 + private final String tradeId;
  13 + // 支付状态
  14 + private final Integer state;
  15 + // 发生时间
  16 + private final LocalDateTime when;
  17 + // 交易描述
  18 + private final String message;
  19 +
11 public OnlineRefundResult(String refundId, String tradeId, int state, LocalDateTime when, String message) { 20 public OnlineRefundResult(String refundId, String tradeId, int state, LocalDateTime when, String message) {
12 - super(refundId, tradeId, state, when, message); 21 + this.refundId = refundId;
  22 + this.tradeId = tradeId;
  23 + this.state = state;
  24 + this.when = when;
  25 + this.message = message;
  26 + }
  27 +
  28 + public String getRefundId() {
  29 + return refundId;
  30 + }
  31 +
  32 + public String getTradeId() {
  33 + return tradeId;
  34 + }
  35 +
  36 + public Integer getState() {
  37 + return state;
  38 + }
  39 +
  40 + public LocalDateTime getWhen() {
  41 + return when;
  42 + }
  43 +
  44 + public String getMessage() {
  45 + return message;
13 } 46 }
14 } 47 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/PaymentResultManager.java
@@ -3,10 +3,12 @@ package com.diligrp.cashier.trade.manager; @@ -3,10 +3,12 @@ package com.diligrp.cashier.trade.manager;
3 import com.diligrp.cashier.shared.service.ServiceEndpointSupport; 3 import com.diligrp.cashier.shared.service.ServiceEndpointSupport;
4 import com.diligrp.cashier.shared.service.ThreadPoolService; 4 import com.diligrp.cashier.shared.service.ThreadPoolService;
5 import com.diligrp.cashier.shared.spi.IPaymentEventListener; 5 import com.diligrp.cashier.shared.spi.IPaymentEventListener;
  6 +import com.diligrp.cashier.shared.spi.domain.PaymentResultBO;
  7 +import com.diligrp.cashier.shared.spi.domain.RefundResultBO;
6 import com.diligrp.cashier.shared.util.JsonUtils; 8 import com.diligrp.cashier.shared.util.JsonUtils;
7 import com.diligrp.cashier.shared.util.ObjectUtils; 9 import com.diligrp.cashier.shared.util.ObjectUtils;
8 -import com.diligrp.cashier.trade.domain.OnlineRefundResult;  
9 import com.diligrp.cashier.trade.domain.OnlinePaymentResult; 10 import com.diligrp.cashier.trade.domain.OnlinePaymentResult;
  11 +import com.diligrp.cashier.trade.domain.OnlineRefundResult;
10 import jakarta.annotation.Resource; 12 import jakarta.annotation.Resource;
11 import org.slf4j.Logger; 13 import org.slf4j.Logger;
12 import org.slf4j.LoggerFactory; 14 import org.slf4j.LoggerFactory;
@@ -14,6 +16,8 @@ import org.springframework.beans.factory.ObjectProvider; @@ -14,6 +16,8 @@ import org.springframework.beans.factory.ObjectProvider;
14 import org.springframework.stereotype.Service; 16 import org.springframework.stereotype.Service;
15 17
16 import java.util.List; 18 import java.util.List;
  19 +import java.util.concurrent.Future;
  20 +import java.util.concurrent.TimeUnit;
17 21
18 @Service("paymentResultManager") 22 @Service("paymentResultManager")
19 public class PaymentResultManager { 23 public class PaymentResultManager {
@@ -24,34 +28,46 @@ public class PaymentResultManager { @@ -24,34 +28,46 @@ public class PaymentResultManager {
24 private ObjectProvider<IPaymentEventListener> eventListeners; 28 private ObjectProvider<IPaymentEventListener> eventListeners;
25 29
26 /** 30 /**
  31 + * 通知业务系统在线支付通道处理结果,并阻塞一段时间保证通知完成
  32 + */
  33 + public void notifyPaymentResult(String uri, OnlinePaymentResult paymentResult, long waitMillis) {
  34 + Future<?> future = notifyPaymentResult(uri, paymentResult);
  35 + try {
  36 + future.get(waitMillis, TimeUnit.MILLISECONDS);
  37 + } catch (Exception ex) {
  38 + // Ignore exception
  39 + }
  40 + }
  41 + /**
27 * 通知业务系统在线支付通道处理结果 42 * 通知业务系统在线支付通道处理结果
28 */ 43 */
29 - public void notifyPaymentResult(String uri, OnlinePaymentResult payload) {  
30 - ThreadPoolService.getIoThreadPoll().submit(() -> { 44 + public Future<?> notifyPaymentResult(String uri, OnlinePaymentResult paymentResult) {
  45 + return ThreadPoolService.getIoThreadPoll().submit(() -> {
31 List<IPaymentEventListener> lifeCycles = eventListeners.stream().toList(); 46 List<IPaymentEventListener> lifeCycles = eventListeners.stream().toList();
32 - for (IPaymentEventListener listener : lifeCycles) {  
33 - try {  
34 - listener.onEvent(payload);  
35 - } catch (Exception ex) {  
36 - LOG.error("Failed to notify trade payment result", ex); 47 + LOG.info("Notifying online payment result: {}, {}", paymentResult.getTradeId(), paymentResult.getPaymentId());
  48 + if (!lifeCycles.isEmpty()) {
  49 + PaymentResultBO paymentEvent = new PaymentResultBO(paymentResult.getTradeId(), paymentResult.getPaymentId(),
  50 + paymentResult.getState(), paymentResult.getOutTradeNo(), paymentResult.getOutPayType(),
  51 + paymentResult.getPayerId(), paymentResult.getWhen(), paymentResult.getMessage());
  52 + for (IPaymentEventListener listener : lifeCycles) {
  53 + try {
  54 + listener.onEvent(paymentEvent);
  55 + } catch (Exception ex) {
  56 + LOG.error("Failed to notify online payment result", ex);
  57 + }
37 } 58 }
38 } 59 }
39 - });  
40 60
41 - if (ObjectUtils.isEmpty(uri)) {  
42 - return;  
43 - }  
44 -  
45 - ThreadPoolService.getIoThreadPoll().submit(() -> {  
46 - try {  
47 - String body = JsonUtils.toJsonString(payload);  
48 - LOG.info("Notifying online trade payment result: {}", body);  
49 - ServiceEndpointSupport.HttpResult httpResult = new NotifyHttpClient(uri).send(body);  
50 - if (httpResult.statusCode != 200) {  
51 - LOG.error("Failed to notify trade payment result");  
52 - }  
53 - } catch (Exception ex) {  
54 - LOG.error("Failed to notify trade payment result", ex); 61 + if (ObjectUtils.isEmpty(uri)) {
  62 + try {
  63 + String payload = JsonUtils.toJsonString(paymentResult);
  64 + ServiceEndpointSupport.HttpResult httpResult = new NotifyHttpClient(uri).send(payload);
  65 + if (httpResult.statusCode != 200) {
  66 + LOG.error("Failed to notify online payment result");
  67 + }
  68 + } catch (Exception ex) {
  69 + LOG.error("Failed to notify online payment result", ex);
  70 + };
55 } 71 }
56 }); 72 });
57 } 73 }
@@ -59,14 +75,18 @@ public class PaymentResultManager { @@ -59,14 +75,18 @@ public class PaymentResultManager {
59 /** 75 /**
60 * 通知业务系统退款处理结果 76 * 通知业务系统退款处理结果
61 */ 77 */
62 - public void notifyRefundResult(String uri, OnlineRefundResult payload) { 78 + public void notifyRefundResult(String uri, OnlineRefundResult refundResult) {
63 ThreadPoolService.getIoThreadPoll().submit(() -> { 79 ThreadPoolService.getIoThreadPoll().submit(() -> {
64 List<IPaymentEventListener> lifeCycles = eventListeners.stream().toList(); 80 List<IPaymentEventListener> lifeCycles = eventListeners.stream().toList();
65 - for (IPaymentEventListener listener : lifeCycles) {  
66 - try {  
67 - listener.onEvent(payload);  
68 - } catch (Exception ex) {  
69 - LOG.error("Failed to notify trade refund result", ex); 81 + if (!lifeCycles.isEmpty()) {
  82 + RefundResultBO refundEvent = new RefundResultBO(refundResult.getRefundId(), refundResult.getTradeId(),
  83 + refundResult.getState(), refundResult.getWhen(), refundResult.getMessage());
  84 + for (IPaymentEventListener listener : lifeCycles) {
  85 + try {
  86 + listener.onEvent(refundEvent);
  87 + } catch (Exception ex) {
  88 + LOG.error("Failed to notify trade refund result", ex);
  89 + }
70 } 90 }
71 } 91 }
72 }); 92 });
@@ -77,9 +97,9 @@ public class PaymentResultManager { @@ -77,9 +97,9 @@ public class PaymentResultManager {
77 97
78 ThreadPoolService.getIoThreadPoll().submit(() -> { 98 ThreadPoolService.getIoThreadPoll().submit(() -> {
79 try { 99 try {
80 - String body = JsonUtils.toJsonString(payload);  
81 - LOG.info("Notifying online trade refund result: {}", body);  
82 - ServiceEndpointSupport.HttpResult httpResult = new NotifyHttpClient(uri).send(body); 100 + String payload = JsonUtils.toJsonString(refundResult);
  101 + LOG.info("Notifying online trade refund result: {}", payload);
  102 + ServiceEndpointSupport.HttpResult httpResult = new NotifyHttpClient(uri).send(payload);
83 if (httpResult.statusCode != 200) { 103 if (httpResult.statusCode != 200) {
84 LOG.error("Failed to notify trade refund result"); 104 LOG.error("Failed to notify trade refund result");
85 } 105 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/TaskMessageConsumer.java
@@ -35,7 +35,7 @@ public class TaskMessageConsumer { @@ -35,7 +35,7 @@ public class TaskMessageConsumer {
35 ? properties.getContentEncoding() : StandardCharsets.UTF_8.name(); 35 ? properties.getContentEncoding() : StandardCharsets.UTF_8.name();
36 try { 36 try {
37 String body = new String(packet, charSet); 37 String body = new String(packet, charSet);
38 - LOG.info("Receiving online pipeline async task request: {}", body); 38 + LOG.info("Receiving async delay task message: {}", body);
39 TaskMessage task = TaskMessage.fromJson(body); 39 TaskMessage task = TaskMessage.fromJson(body);
40 int times = NumberUtils.str2Int(task.getParams(), Integer.MAX_VALUE); 40 int times = NumberUtils.str2Int(task.getParams(), Integer.MAX_VALUE);
41 if (task.getType() == TaskMessage.TYPE_CASHIER_ORDER_SCAN) { 41 if (task.getType() == TaskMessage.TYPE_CASHIER_ORDER_SCAN) {
@@ -46,7 +46,7 @@ public class TaskMessageConsumer { @@ -46,7 +46,7 @@ public class TaskMessageConsumer {
46 LOG.error("Never happened"); 46 LOG.error("Never happened");
47 } 47 }
48 } catch (Exception ex) { 48 } catch (Exception ex) {
49 - LOG.error("Consume online pipeline async message exception", ex); 49 + LOG.error("Consume async delay task message exception", ex);
50 } 50 }
51 } 51 }
52 } 52 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/TaskMessageSender.java
@@ -47,10 +47,10 @@ public class TaskMessageSender { @@ -47,10 +47,10 @@ public class TaskMessageSender {
47 properties.setHeader("x-delay", String.valueOf(delayInMillis)); 47 properties.setHeader("x-delay", String.valueOf(delayInMillis));
48 String payload = JsonUtils.toJsonString(task); 48 String payload = JsonUtils.toJsonString(task);
49 Message message = new Message(payload.getBytes(StandardCharsets.UTF_8), properties); 49 Message message = new Message(payload.getBytes(StandardCharsets.UTF_8), properties);
50 - LOG.info("Sending online payment order scan request for {}", task.getPayload()); 50 + LOG.info("Sending async delay task message for {}", task.getPayload());
51 rabbitTemplate.send(Constants.PAYMENT_DELAY_EXCHANGE, Constants.PAYMENT_DELAY_KEY, message); 51 rabbitTemplate.send(Constants.PAYMENT_DELAY_EXCHANGE, Constants.PAYMENT_DELAY_KEY, message);
52 } catch (Exception ex) { 52 } catch (Exception ex) {
53 - LOG.error("Failed to send online payment order scan request for {}", task.getPayload(), ex); 53 + LOG.error("Failed to send async delay task message for {}", task.getPayload(), ex);
54 } 54 }
55 }); 55 });
56 } 56 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierAssistantServiceImpl.java
1 package com.diligrp.cashier.trade.service.impl; 1 package com.diligrp.cashier.trade.service.impl;
2 2
3 -import com.diligrp.cashier.pipeline.Constants;  
4 import com.diligrp.cashier.pipeline.core.OnlinePipeline; 3 import com.diligrp.cashier.pipeline.core.OnlinePipeline;
5 import com.diligrp.cashier.pipeline.core.PaymentPipeline; 4 import com.diligrp.cashier.pipeline.core.PaymentPipeline;
6 import com.diligrp.cashier.pipeline.domain.OnlinePaymentResponse; 5 import com.diligrp.cashier.pipeline.domain.OnlinePaymentResponse;
@@ -9,6 +8,7 @@ import com.diligrp.cashier.pipeline.domain.OnlineRefundOrder; @@ -9,6 +8,7 @@ import com.diligrp.cashier.pipeline.domain.OnlineRefundOrder;
9 import com.diligrp.cashier.pipeline.domain.OnlineRefundResponse; 8 import com.diligrp.cashier.pipeline.domain.OnlineRefundResponse;
10 import com.diligrp.cashier.pipeline.service.IPaymentPipelineManager; 9 import com.diligrp.cashier.pipeline.service.IPaymentPipelineManager;
11 import com.diligrp.cashier.pipeline.type.PaymentState; 10 import com.diligrp.cashier.pipeline.type.PaymentState;
  11 +import com.diligrp.cashier.trade.Constants;
12 import com.diligrp.cashier.trade.dao.IOnlinePaymentDao; 12 import com.diligrp.cashier.trade.dao.IOnlinePaymentDao;
13 import com.diligrp.cashier.trade.domain.TradeStateDTO; 13 import com.diligrp.cashier.trade.domain.TradeStateDTO;
14 import com.diligrp.cashier.trade.model.OnlinePayment; 14 import com.diligrp.cashier.trade.model.OnlinePayment;
@@ -49,13 +49,13 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { @@ -49,13 +49,13 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
49 49
50 @Override 50 @Override
51 public void scanCashierTradeOrder(String tradeId, int times) { 51 public void scanCashierTradeOrder(String tradeId, int times) {
52 - LOG.debug("scanCashierTradeOrder{}: processing cashier order {}", times, tradeId);  
53 - String lockKey = String.format(com.diligrp.cashier.trade.Constants.TRADE_LOCK_REDIS_KEY, tradeId); 52 + LOG.debug("scanCashierTradeOrder{}: processing cashier trade order {}", times, tradeId);
  53 + String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, tradeId);
54 RLock lock = redissonClient.getLock(lockKey); 54 RLock lock = redissonClient.getLock(lockKey);
55 try { 55 try {
56 lock.lock(); 56 lock.lock();
57 LocalDateTime now = LocalDateTime.now(); 57 LocalDateTime now = LocalDateTime.now();
58 - // 理论上只会存在一条支付中的支付订单 58 + // 查询交易订单下状态为支付中的支付订单, 理论上只有一条支付记录
59 List<OnlinePayment> onlinePayments = onlinePaymentDao.listOnlinePayments(tradeId, 59 List<OnlinePayment> onlinePayments = onlinePaymentDao.listOnlinePayments(tradeId,
60 TradeType.TRADE.getCode(), PaymentState.PROCESSING.getCode()); 60 TradeType.TRADE.getCode(), PaymentState.PROCESSING.getCode());
61 // 关闭所有未支付完成的支付订单 61 // 关闭所有未支付完成的支付订单
@@ -65,7 +65,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { @@ -65,7 +65,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
65 if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { 65 if (pipeline instanceof OnlinePipeline<?> onlinePipeline) {
66 OnlinePrepayOrder order = new OnlinePrepayOrder(payment.getPaymentId(), payment.getOutTradeNo()); 66 OnlinePrepayOrder order = new OnlinePrepayOrder(payment.getPaymentId(), payment.getOutTradeNo());
67 // 微信服务商模式,还需子商户 67 // 微信服务商模式,还需子商户
68 - order.attach(Constants.PARAM_MCH_ID, payment.getOutMchId()); 68 + order.attach(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID, payment.getOutMchId());
69 OnlinePaymentResponse response = onlinePipeline.queryPrepayResponse(order); 69 OnlinePaymentResponse response = onlinePipeline.queryPrepayResponse(order);
70 if (!PaymentState.isFinished(response.getState().getCode())) { 70 if (!PaymentState.isFinished(response.getState().getCode())) {
71 try { 71 try {
@@ -75,7 +75,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { @@ -75,7 +75,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
75 response.getOutPayType(), response.getPayerId(), response.getWhen(), 75 response.getOutPayType(), response.getPayerId(), response.getWhen(),
76 PaymentState.FAILED, "自动关闭超时的支付订单"); 76 PaymentState.FAILED, "自动关闭超时的支付订单");
77 } catch (Exception ex) { 77 } catch (Exception ex) {
78 - LOG.error("scanOnlinePrepayOrder: close online prepare order exception", ex); 78 + LOG.error("scanCashierTradeOrder: close online prepare order exception", ex);
79 } 79 }
80 } 80 }
81 cashierPaymentService.notifyPaymentResponse(response); 81 cashierPaymentService.notifyPaymentResponse(response);
@@ -84,7 +84,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { @@ -84,7 +84,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
84 // 交易订单仍然未完成则关闭交易订单,交易订单不能继续支付 84 // 交易订单仍然未完成则关闭交易订单,交易订单不能继续支付
85 TradeOrder trade = tradeAssistantService.findByTradeId(tradeId); 85 TradeOrder trade = tradeAssistantService.findByTradeId(tradeId);
86 if (!TradeState.isFinished(trade.getState())) { 86 if (!TradeState.isFinished(trade.getState())) {
87 - TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.FAILED, trade.getVersion(), now); 87 + TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.CLOSED, trade.getVersion(), now);
88 tradeAssistantService.proceedTradeOrder(tradeStateDTO); 88 tradeAssistantService.proceedTradeOrder(tradeStateDTO);
89 } 89 }
90 } finally { 90 } finally {
@@ -106,7 +106,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { @@ -106,7 +106,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
106 OnlinePipeline<?> pipeline = paymentPipelineManager.findPipelineById(refund.getPipelineId(), OnlinePipeline.class); 106 OnlinePipeline<?> pipeline = paymentPipelineManager.findPipelineById(refund.getPipelineId(), OnlinePipeline.class);
107 OnlineRefundOrder order = new OnlineRefundOrder(refundId, refund.getOutTradeNo()); 107 OnlineRefundOrder order = new OnlineRefundOrder(refundId, refund.getOutTradeNo());
108 // 微信服务商模式,还需子商户 108 // 微信服务商模式,还需子商户
109 - order.attach(Constants.PARAM_MCH_ID, refund.getOutMchId()); 109 + order.attach(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID, refund.getOutMchId());
110 OnlineRefundResponse response = pipeline.queryRefundResponse(order); 110 OnlineRefundResponse response = pipeline.queryRefundResponse(order);
111 cashierPaymentService.notifyRefundResult(response); 111 cashierPaymentService.notifyRefundResult(response);
112 } 112 }
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierPaymentServiceImpl.java
@@ -20,8 +20,8 @@ import com.diligrp.cashier.trade.dao.IOnlinePaymentDao; @@ -20,8 +20,8 @@ import com.diligrp.cashier.trade.dao.IOnlinePaymentDao;
20 import com.diligrp.cashier.trade.dao.ITradeOrderDao; 20 import com.diligrp.cashier.trade.dao.ITradeOrderDao;
21 import com.diligrp.cashier.trade.domain.*; 21 import com.diligrp.cashier.trade.domain.*;
22 import com.diligrp.cashier.trade.exception.TradePaymentException; 22 import com.diligrp.cashier.trade.exception.TradePaymentException;
23 -import com.diligrp.cashier.trade.manager.TaskMessageSender;  
24 import com.diligrp.cashier.trade.manager.PaymentResultManager; 23 import com.diligrp.cashier.trade.manager.PaymentResultManager;
  24 +import com.diligrp.cashier.trade.manager.TaskMessageSender;
25 import com.diligrp.cashier.trade.model.OnlinePayment; 25 import com.diligrp.cashier.trade.model.OnlinePayment;
26 import com.diligrp.cashier.trade.model.TradeOrder; 26 import com.diligrp.cashier.trade.model.TradeOrder;
27 import com.diligrp.cashier.trade.service.ICashierPaymentService; 27 import com.diligrp.cashier.trade.service.ICashierPaymentService;
@@ -84,8 +84,9 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { @@ -84,8 +84,9 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
84 public String doSubmit(Merchant merchant, CashierOrder cashierOrder) { 84 public String doSubmit(Merchant merchant, CashierOrder cashierOrder) {
85 LocalDateTime now = LocalDateTime.now(); 85 LocalDateTime now = LocalDateTime.now();
86 String tradeId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.TRADE_ID).nextId(); 86 String tradeId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.TRADE_ID).nextId();
87 - int timeout = Objects.isNull(cashierOrder.getTimeout()) ? Constants.DEFAULT_ORDER_TIMEOUT_SECONDS : cashierOrder.getTimeout();  
88 - timeout = Math.max(timeout, Constants.MIN_ORDER_TIMEOUT_SECONDS); 87 + // 订单超时时间在1至10分钟之间,默认为5分钟
  88 + int timeout = Objects.isNull(cashierOrder.getTimeout()) ? Constants.DEFAULT_TRADE_TIMEOUT : cashierOrder.getTimeout();
  89 + timeout = Math.min(Math.max(timeout, Constants.MIN_TRADE_TIMEOUT), Constants.MAX_TRADE_TIMEOUT);
89 TradeOrder tradeOrder = TradeOrder.builder().mchId(merchant.getMchId()).tradeId(tradeId) 90 TradeOrder tradeOrder = TradeOrder.builder().mchId(merchant.getMchId()).tradeId(tradeId)
90 .type(cashierOrder.getType().getCode()).outTradeNo(cashierOrder.getOutTradeNo()).amount(cashierOrder.getAmount()) 91 .type(cashierOrder.getType().getCode()).outTradeNo(cashierOrder.getOutTradeNo()).amount(cashierOrder.getAmount())
91 .maxAmount(cashierOrder.getAmount()).goods(cashierOrder.getGoods()).timeout(timeout).state(TradeState.PENDING.getCode()) 92 .maxAmount(cashierOrder.getAmount()).goods(cashierOrder.getGoods()).timeout(timeout).state(TradeState.PENDING.getCode())
@@ -93,10 +94,9 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { @@ -93,10 +94,9 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
93 .source(0).version(0).createdTime(now).modifiedTime(now).build(); 94 .source(0).version(0).createdTime(now).modifiedTime(now).build();
94 tradeOrderDao.insertTradeOrder(tradeOrder); 95 tradeOrderDao.insertTradeOrder(tradeOrder);
95 96
96 - // TODO: userId是否需要存储  
97 // 兜底处理交易订单,根据支付结果选择关闭或完成交易订单 97 // 兜底处理交易订单,根据支付结果选择关闭或完成交易订单
98 TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_ORDER_SCAN, tradeId, "1"); 98 TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_ORDER_SCAN, tradeId, "1");
99 - taskMessageSender.sendDelayTaskMessage(message, timeout); 99 + taskMessageSender.sendDelayTaskMessage(message, timeout * 1000); // 转换成毫秒
100 return tradeId; 100 return tradeId;
101 } 101 }
102 102
@@ -113,7 +113,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { @@ -113,7 +113,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
113 String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, cashierPayment.getTradeId()); 113 String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, cashierPayment.getTradeId());
114 RLock lock = redissonClient.getLock(lockKey); 114 RLock lock = redissonClient.getLock(lockKey);
115 try { 115 try {
116 - boolean locked = lock.tryLock(Constants.TRADE_LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS); 116 + boolean locked = lock.tryLock(Constants.TRADE_LOCK_TIMEOUT, TimeUnit.SECONDS);
117 if (locked) { 117 if (locked) {
118 TradeOrder trade = tradeAssistantService.findByTradeId(cashierPayment.getTradeId()); 118 TradeOrder trade = tradeAssistantService.findByTradeId(cashierPayment.getTradeId());
119 CashierType cashierType = CashierType.getByCode(trade.getType()); 119 CashierType cashierType = CashierType.getByCode(trade.getType());
@@ -131,52 +131,50 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { @@ -131,52 +131,50 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
131 131
132 LocalDateTime now = LocalDateTime.now(); 132 LocalDateTime now = LocalDateTime.now();
133 // 获取支付通道 133 // 获取支付通道
134 - PaymentPipeline<?> paymentPipeline = paymentPipelineManager.findPipelineById( 134 + PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(
135 cashierPayment.getPipelineId(), PaymentPipeline.class); 135 cashierPayment.getPipelineId(), PaymentPipeline.class);
136 String paymentId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID).nextId(); 136 String paymentId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID).nextId();
137 - if (paymentPipeline instanceof OnlinePipeline<?> pipeline) { // 在线支付通道 137 + if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { // 在线支付通道
138 // 在线支付通道: 不同的收银台类型使用不同的支付方式(目前只支持小程序收银台) 138 // 在线支付通道: 不同的收银台类型使用不同的支付方式(目前只支持小程序收银台)
139 // 小程序收银台将使用在线支付通道的小程序支付 139 // 小程序收银台将使用在线支付通道的小程序支付
140 MiniProPrepayRequest request = new MiniProPaymentConverter(trade, paymentId, now).convert(cashierPayment); 140 MiniProPrepayRequest request = new MiniProPaymentConverter(trade, paymentId, now).convert(cashierPayment);
141 - MiniProPrepayResponse response = pipeline.sendMiniProPrepayRequest(request); 141 + MiniProPrepayResponse response = onlinePipeline.sendMiniProPrepayRequest(request);
142 // 微信服务商模式下outMchId为签约子商户 142 // 微信服务商模式下outMchId为签约子商户
143 String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID); 143 String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID);
144 OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId()) 144 OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId())
145 - .type(TradeType.TRADE).paymentId(paymentId).channelId(pipeline.supportedChannel())  
146 - .payType(PaymentType.MINI_PRO).pipelineId(pipeline.pipelineId()).goods(trade.getGoods()) 145 + .type(TradeType.TRADE).paymentId(paymentId).channelId(onlinePipeline.supportedChannel())
  146 + .payType(PaymentType.MINI_PRO).pipelineId(onlinePipeline.pipelineId()).goods(trade.getGoods())
147 .amount(trade.getAmount()).payerId(request.getOpenId()).outTradeNo(response.getOutTradeNo()) 147 .amount(trade.getAmount()).payerId(request.getOpenId()).outTradeNo(response.getOutTradeNo())
148 .state(response.getState()).version(0).createdTime(now).modifiedTime(now).build(); 148 .state(response.getState()).version(0).createdTime(now).modifiedTime(now).build();
149 onlinePaymentDao.insertOnlinePayment(payment); 149 onlinePaymentDao.insertOnlinePayment(payment);
150 return response; 150 return response;
151 } 151 }
152 - if (paymentPipeline instanceof DiliCardPipeline pipeline) { // 园区卡支付通道 152 + if (pipeline instanceof DiliCardPipeline cardPipeline) { // 园区卡支付通道
153 // 园区卡支付通道: 所有的收银台类型使用的是同一种园区卡支付流程 153 // 园区卡支付通道: 所有的收银台类型使用的是同一种园区卡支付流程
154 CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(cashierPayment); 154 CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(cashierPayment);
155 // 修改支付状态为支付中,防止重复支付 155 // 修改支付状态为支付中,防止重复支付
156 - CardPaymentResponse response = pipeline.sendPaymentRequest(request);  
157 - if (PaymentState.isFinished(response.getState().getCode())) { 156 + CardPaymentResponse response = cardPipeline.sendPaymentRequest(request);
  157 + // 支付成功插入支付记录并修改交易订单状态,失败可以继续支付
  158 + if (response.getState() == PaymentState.SUCCESS) {
158 // 园区卡支付通道outMchId为市场ID 159 // 园区卡支付通道outMchId为市场ID
159 - String outMchId = pipeline.params().getOutMchId(); 160 + String outMchId = cardPipeline.params().getOutMchId();
160 OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId()) 161 OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId())
161 - .type(TradeType.TRADE).paymentId(paymentId).channelId(pipeline.supportedChannel())  
162 - .payType(PaymentType.DIRECT).pipelineId(pipeline.pipelineId()).goods(trade.getGoods()) 162 + .type(TradeType.TRADE).paymentId(paymentId).channelId(cardPipeline.supportedChannel())
  163 + .payType(PaymentType.DIRECT).pipelineId(cardPipeline.pipelineId()).goods(trade.getGoods())
163 .amount(trade.getAmount()).payerId(response.getPayerId()) 164 .amount(trade.getAmount()).payerId(response.getPayerId())
164 .finishTime(response.getWhen()).outTradeNo(response.getOutTradeNo()) 165 .finishTime(response.getWhen()).outTradeNo(response.getOutTradeNo())
165 .outPayType(OutPaymentType.DILICARD).state(response.getState()).notifyUrl(trade.getNotifyUrl()) 166 .outPayType(OutPaymentType.DILICARD).state(response.getState()).notifyUrl(trade.getNotifyUrl())
166 .description(response.getMessage()).version(0).createdTime(now).modifiedTime(now).build(); 167 .description(response.getMessage()).version(0).createdTime(now).modifiedTime(now).build();
167 onlinePaymentDao.insertOnlinePayment(payment); 168 onlinePaymentDao.insertOnlinePayment(payment);
168 169
169 - // 只有成功才修改交易订单状态,此时交易订单仍然可以继续支付  
170 - if (response.getState() == PaymentState.SUCCESS) {  
171 - TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS,  
172 - trade.getVersion(), now);  
173 - tradeAssistantService.proceedTradeOrder(tradeStateDTO);  
174 - // 支付成功才通知业务系统支付结果,失败可以再次进行支付  
175 - OnlinePaymentResult paymentResult = new OnlinePaymentResult(trade.getTradeId(), paymentId,  
176 - response.getState().getCode(), trade.getOutTradeNo(), OutPaymentType.DILICARD.getCode(),  
177 - response.getPayerId(), response.getWhen(), response.getMessage());  
178 - paymentResultManager.notifyPaymentResult(trade.getNotifyUrl(), paymentResult);  
179 - } 170 + TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS,
  171 + trade.getVersion(), now);
  172 + tradeAssistantService.proceedTradeOrder(tradeStateDTO);
  173 + // 通知业务系统支付结果,
  174 + OnlinePaymentResult paymentResult = new OnlinePaymentResult(trade.getTradeId(), paymentId,
  175 + response.getState().getCode(), trade.getOutTradeNo(), OutPaymentType.DILICARD.getCode(),
  176 + response.getPayerId(), response.getWhen(), response.getMessage());
  177 + paymentResultManager.notifyPaymentResult(trade.getNotifyUrl(), paymentResult, 500);
180 } 178 }
181 return response; 179 return response;
182 } else { 180 } else {
@@ -205,10 +203,10 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { @@ -205,10 +203,10 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
205 public void notifyPaymentResponse(OnlinePaymentResponse response) { 203 public void notifyPaymentResponse(OnlinePaymentResponse response) {
206 OnlinePayment payment = tradeAssistantService.findByPaymentId(response.getPaymentId()); 204 OnlinePayment payment = tradeAssistantService.findByPaymentId(response.getPaymentId());
207 if (PaymentState.isFinished(payment.getState())) { 205 if (PaymentState.isFinished(payment.getState())) {
208 - LOG.warn("Duplicate process payment result notification for {}:{}", payment.getPaymentId(), response.getState()); 206 + LOG.warn("Duplicate process payment response: [{}:{}]", payment.getPaymentId(), response.getState());
209 return; 207 return;
210 } 208 }
211 - LOG.info("Processing payment result notification: [{},{}]", payment.getPaymentId(), response.getState()); 209 + LOG.info("Processing payment response: [{},{}]", payment.getPaymentId(), response.getState());
212 210
213 if (PaymentState.isFinished(response.getState().getCode())) { 211 if (PaymentState.isFinished(response.getState().getCode())) {
214 LocalDateTime now = LocalDateTime.now(); 212 LocalDateTime now = LocalDateTime.now();
@@ -224,14 +222,14 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { @@ -224,14 +222,14 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
224 tradeAssistantService.proceedOnlinePayment(paymentDTO); 222 tradeAssistantService.proceedOnlinePayment(paymentDTO);
225 223
226 // 交易订单未完成,支付订单成功支付时处理交易订单,并通知业务系统支付结果;如果支付订单支付失败,收银台交易订单可以继续支付 224 // 交易订单未完成,支付订单成功支付时处理交易订单,并通知业务系统支付结果;如果支付订单支付失败,收银台交易订单可以继续支付
227 - if (TradeState.PENDING.equalTo(trade.getState()) && PaymentState.SUCCESS == response.getState()) { 225 + if (PaymentState.SUCCESS == response.getState() && TradeState.PENDING.equalTo(trade.getState())) {
228 TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS, trade.getVersion(), now); 226 TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS, trade.getVersion(), now);
229 tradeAssistantService.proceedTradeOrder(tradeStateDTO); 227 tradeAssistantService.proceedTradeOrder(tradeStateDTO);
230 - 228 + LOG.debug("Accomplish cashier order[{}] successfully", trade.getTradeId());
231 OnlinePaymentResult paymentResult = OnlinePaymentResult.of(trade.getTradeId(), payment.getPaymentId(), 229 OnlinePaymentResult paymentResult = OnlinePaymentResult.of(trade.getTradeId(), payment.getPaymentId(),
232 response.getState(), trade.getOutTradeNo(), response.getOutPayType(), response.getPayerId(), 230 response.getState(), trade.getOutTradeNo(), response.getOutPayType(), response.getPayerId(),
233 response.getWhen() != null ? response.getWhen() : now, response.getMessage()); 231 response.getWhen() != null ? response.getWhen() : now, response.getMessage());
234 - paymentResultManager.notifyPaymentResult(trade.getNotifyUrl(), paymentResult); 232 + paymentResultManager.notifyPaymentResult(trade.getNotifyUrl(), paymentResult, 500);
235 } 233 }
236 } finally { 234 } finally {
237 if (lock.isHeldByCurrentThread()) { 235 if (lock.isHeldByCurrentThread()) {
@@ -280,6 +278,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { @@ -280,6 +278,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
280 278
281 @Override 279 @Override
282 public OnlinePaymentResult queryPaymentState(String paymentId, String mode) { 280 public OnlinePaymentResult queryPaymentState(String paymentId, String mode) {
  281 + // TODO: 支付成功后返回支付成功的页面地址
283 OnlinePayment payment = tradeAssistantService.findByPaymentId(paymentId); 282 OnlinePayment payment = tradeAssistantService.findByPaymentId(paymentId);
284 TradeOrder trade = tradeAssistantService.findByTradeId(payment.getTradeId()); 283 TradeOrder trade = tradeAssistantService.findByTradeId(payment.getTradeId());
285 284
scripts/cashier-data.sql 0 → 100644
  1 +INSERT INTO upay_merchant(mch_id, name, param, address, linkman, telephone, state, created_time, modified_time)
  2 +VALUES (1001, '安徽省中瑞农副产品有限责任公司', '{"cashier":{"miniProUrl": "https://cashier.pay.gszdtop.com/merchant/mp"}}', '安徽省濉溪县南环路中瑞农产品批发市场', '赵静', '0561-6863420', 1, now(), now());
0 \ No newline at end of file 3 \ No newline at end of file