Commit 65220cfeeffdbd45574f880099a0d53a8863acf9
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 | 3 | public final class Constants { |
| 4 | 4 | // 商户信息缓存Key |
| 5 | 5 | public static final String MERCHANT_REDIS_KEY = "cashier:merchant:%s"; |
| 6 | + // 商户信息过期时长-单位秒 - 1个小时 | |
| 7 | + public static final int MERCHANT_TIMEOUT_SECONDS = 60 * 60; | |
| 6 | 8 | // TOKEN信息缓存Key |
| 7 | 9 | public static final String TOKEN_REDIS_KEY = "cashier:token:%s"; |
| 8 | 10 | // TOKEN参数名称 |
| ... | ... | @@ -11,8 +13,8 @@ public final class Constants { |
| 11 | 13 | public static final String TOKEN_SIGN_ALGORITHM = "HmacSHA256"; |
| 12 | 14 | // TOKEN的签名长度 |
| 13 | 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 | 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 | 35 | AssertUtils.notNull(request.getAmount(), "amount missed"); |
| 36 | 36 | AssertUtils.isTrue(request.getAmount() > 0, "Invalid amount"); |
| 37 | 37 | AssertUtils.notEmpty(request.getOutTradeNo(), "outTradeNo missed"); |
| 38 | + AssertUtils.notEmpty(request.getRedirectUrl(), "redirectUrl missed"); | |
| 38 | 39 | |
| 39 | 40 | CashierOrder cashierOrder = CashierOrderConverter.INSTANCE.convert(request); |
| 40 | 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 | 17 | private String outTradeNo; |
| 18 | 18 | // 回调地址 |
| 19 | 19 | private String notifyUrl; |
| 20 | + // 页面回调地址 | |
| 21 | + private String redirectUrl; | |
| 20 | 22 | // 交易描述 |
| 21 | 23 | private String description; |
| 22 | 24 | // 附加数据 |
| ... | ... | @@ -86,6 +88,14 @@ public class CashierOrderDTO { |
| 86 | 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 | 99 | public String getDescription() { |
| 90 | 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 | 21 | private Integer cashierType; |
| 22 | 22 | // 业务系统用户标识 |
| 23 | 23 | private String userId; |
| 24 | + // 页面回调地址 | |
| 25 | + private String redirectUrl; | |
| 24 | 26 | |
| 25 | 27 | public static String encode(Long tokenId, SecretKeySpec secretKey) { |
| 26 | 28 | try { |
| ... | ... | @@ -70,11 +72,12 @@ public class CashierOrderToken { |
| 70 | 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 | 76 | this.mchId = mchId; |
| 75 | 77 | this.tradeId = tradeId; |
| 76 | 78 | this.cashierType = cashierType; |
| 77 | 79 | this.userId = userId; |
| 80 | + this.redirectUrl = redirectUrl; | |
| 78 | 81 | } |
| 79 | 82 | |
| 80 | 83 | public Long getMchId() { |
| ... | ... | @@ -109,6 +112,14 @@ public class CashierOrderToken { |
| 109 | 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 | 123 | @Override |
| 113 | 124 | public String toString() { |
| 114 | 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 | 1 | package com.diligrp.cashier.boss.domain; |
| 2 | 2 | |
| 3 | +import com.diligrp.cashier.pipeline.type.ChannelType; | |
| 4 | + | |
| 3 | 5 | import java.util.List; |
| 4 | 6 | |
| 5 | -public class CashierOrderInfo { | |
| 7 | +public class CashierOrderVO { | |
| 6 | 8 | // 业务系统用户标识 |
| 7 | 9 | private final String userId; |
| 10 | + // 页面回调地址 | |
| 11 | + private final String redirectUrl; | |
| 8 | 12 | // 支付通道 |
| 9 | 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 | 16 | this.userId = userId; |
| 17 | + this.redirectUrl = redirectUrl; | |
| 13 | 18 | this.pipelines = pipelines; |
| 14 | 19 | } |
| 15 | 20 | |
| ... | ... | @@ -17,6 +22,10 @@ public class CashierOrderInfo { |
| 17 | 22 | return userId; |
| 18 | 23 | } |
| 19 | 24 | |
| 25 | + public String getRedirectUrl() { | |
| 26 | + return redirectUrl; | |
| 27 | + } | |
| 28 | + | |
| 20 | 29 | public List<PaymentPipeline> getPipelines() { |
| 21 | 30 | return pipelines; |
| 22 | 31 | } |
| ... | ... | @@ -27,9 +36,12 @@ public class CashierOrderInfo { |
| 27 | 36 | // 支付渠道 |
| 28 | 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 | 42 | this.pipelineId = pipelineId; |
| 32 | - this.channelId = channelId; | |
| 43 | + this.channelId = channelType.getCode(); | |
| 44 | + this.channelName = channelType.getName(); | |
| 33 | 45 | } |
| 34 | 46 | |
| 35 | 47 | public Long getPipelineId() { |
| ... | ... | @@ -39,5 +51,9 @@ public class CashierOrderInfo { |
| 39 | 51 | public Integer getChannelId() { |
| 40 | 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 | 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 | 4 | import com.diligrp.cashier.boss.domain.CashierPaymentUrl; |
| 5 | 5 | import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus; |
| 6 | 6 | import com.diligrp.cashier.trade.domain.*; |
| ... | ... | @@ -18,7 +18,7 @@ public interface ICashierDeskService { |
| 18 | 18 | /** |
| 19 | 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 | 2 | |
| 3 | 3 | import com.diligrp.cashier.boss.CashierDeskProperties; |
| 4 | 4 | import com.diligrp.cashier.boss.Constants; |
| 5 | -import com.diligrp.cashier.boss.domain.CashierOrderInfo; | |
| 5 | +import com.diligrp.cashier.boss.domain.CashierOrderVO; | |
| 6 | 6 | import com.diligrp.cashier.boss.domain.CashierOrderToken; |
| 7 | 7 | import com.diligrp.cashier.boss.domain.CashierPaymentUrl; |
| 8 | 8 | import com.diligrp.cashier.boss.exception.BossServiceException; |
| ... | ... | @@ -53,7 +53,8 @@ public class CashierDeskServiceImpl implements ICashierDeskService { |
| 53 | 53 | public CashierPaymentUrl doSubmit(Merchant merchant, CashierOrder order) { |
| 54 | 54 | String tradeId = cashierPaymentService.doSubmit(merchant, order); |
| 55 | 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 | 59 | String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token); |
| 59 | 60 | stringRedisTemplate.opsForValue().set(tokenKey, orderToken.toString(), Constants.TOKEN_TIMEOUT_SECONDS, TimeUnit.SECONDS); |
| ... | ... | @@ -68,12 +69,12 @@ public class CashierDeskServiceImpl implements ICashierDeskService { |
| 68 | 69 | } |
| 69 | 70 | |
| 70 | 71 | @Override |
| 71 | - public CashierOrderInfo getCashierOrderByToken(String token) { | |
| 72 | + public CashierOrderVO getCashierOrderByToken(String token) { | |
| 72 | 73 | CashierOrderToken.decode(token, cashierDeskProperties.getSecretKey()); |
| 73 | 74 | String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token); |
| 74 | 75 | String payload = stringRedisTemplate.opsForValue().get(tokenKey); |
| 75 | 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 | 80 | CashierOrderToken orderToken = CashierOrderToken.decodeCashierOrder(payload); |
| ... | ... | @@ -85,9 +86,9 @@ public class CashierDeskServiceImpl implements ICashierDeskService { |
| 85 | 86 | if (pipelines.isEmpty()) { |
| 86 | 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 | 13 | import org.springframework.stereotype.Service; |
| 14 | 14 | |
| 15 | 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 | 37 | Merchant merchant = Merchant.decode(payload); |
| 37 | 38 | if (Objects.isNull(merchant)) { |
| 38 | 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 | 44 | return merchant; | ... | ... |
cashier-boss/src/main/java/com/diligrp/cashier/boss/util/CashierOrderConverter.java
| ... | ... | @@ -19,6 +19,7 @@ public class CashierOrderConverter implements IConverter<CashierOrderDTO, Cashie |
| 19 | 19 | cashierOrder.setTimeout(cashierOrderDTO.getTimeout()); |
| 20 | 20 | cashierOrder.setOutTradeNo(cashierOrderDTO.getOutTradeNo()); |
| 21 | 21 | cashierOrder.setNotifyUrl(cashierOrderDTO.getNotifyUrl()); |
| 22 | + cashierOrder.setRedirectUrl(cashierOrderDTO.getRedirectUrl()); | |
| 22 | 23 | cashierOrder.setDescription(cashierOrderDTO.getDescription()); |
| 23 | 24 | cashierOrder.setAttach(cashierOrderDTO.getAttach()); |
| 24 | 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
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/ChannelType.java
| ... | ... | @@ -15,11 +15,11 @@ import java.util.stream.Stream; |
| 15 | 15 | */ |
| 16 | 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 | 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 | 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 | 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 | 3 | import java.time.LocalDateTime; |
| 4 | 4 | |
| 5 | -public class PaymentEvent { | |
| 5 | +public class PaymentResultBO { | |
| 6 | 6 | // 交易号 |
| 7 | 7 | private final String tradeId; |
| 8 | 8 | // 支付ID |
| ... | ... | @@ -20,8 +20,8 @@ public class PaymentEvent { |
| 20 | 20 | // 交易描述 |
| 21 | 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 | 25 | this.tradeId = tradeId; |
| 26 | 26 | this.paymentId = paymentId; |
| 27 | 27 | this.state = state; | ... | ... |
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/domain/PaymentUrlBO.java
0 → 100644
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 | 3 | import java.time.LocalDateTime; |
| 4 | 4 | |
| 5 | -public class RefundEvent { | |
| 5 | +public class RefundResultBO { | |
| 6 | 6 | // 退款单号 |
| 7 | 7 | private final String refundId; |
| 8 | 8 | // 原支付ID |
| ... | ... | @@ -14,7 +14,7 @@ public class RefundEvent { |
| 14 | 14 | // 交易描述 |
| 15 | 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 | 18 | this.refundId = refundId; |
| 19 | 19 | this.tradeId = tradeId; |
| 20 | 20 | this.state = state; | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/Constants.java
| ... | ... | @@ -11,16 +11,19 @@ public final class Constants { |
| 11 | 11 | // 支付通道延时路由KEY |
| 12 | 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 | 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 | 17 | private String outTradeNo; |
| 18 | 18 | // 回调地址 |
| 19 | 19 | private String notifyUrl; |
| 20 | + // 页面回调地址 | |
| 21 | + private String redirectUrl; | |
| 20 | 22 | // 交易描述 |
| 21 | 23 | private String description; |
| 22 | 24 | // 附加数据 |
| ... | ... | @@ -78,6 +80,14 @@ public class CashierOrder { |
| 78 | 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 | 91 | public String getDescription() { |
| 82 | 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 | public class MerchantParams { |
| 8 | 8 | // 收银台配置 |
| 9 | 9 | private CashierParams cashier; |
| 10 | - // TODO: 支付结果页面-跳转大润发使用 | |
| 11 | 10 | |
| 12 | 11 | public static MerchantParams decode(String params) { |
| 13 | 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 | 2 | |
| 3 | 3 | import com.diligrp.cashier.pipeline.type.OutPaymentType; |
| 4 | 4 | import com.diligrp.cashier.pipeline.type.PaymentState; |
| 5 | -import com.diligrp.cashier.shared.spi.PaymentEvent; | |
| 6 | 5 | |
| 7 | 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 | 29 | public static OnlinePaymentResult of(String tradeId, String paymentId, PaymentState state, String outTradeNo, |
| 14 | 30 | OutPaymentType outPayType, String payerId, LocalDateTime when, String message) { |
| 15 | 31 | Integer outPayTypeCode = outPayType != null ? outPayType.getCode() : null; |
| ... | ... | @@ -18,6 +34,45 @@ public class OnlinePaymentResult extends PaymentEvent { |
| 18 | 34 | |
| 19 | 35 | public OnlinePaymentResult(String tradeId, String paymentId, int state, String outTradeNo, Integer outPayType, |
| 20 | 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 | 9 | // 退款金额 |
| 10 | 10 | private Long amount; |
| 11 | 11 | // 回调地址 |
| 12 | - private String notifyUri; | |
| 12 | + private String notifyUrl; | |
| 13 | 13 | // 退款原因 |
| 14 | 14 | private String description; |
| 15 | 15 | |
| ... | ... | @@ -29,12 +29,12 @@ public class OnlineRefundDTO { |
| 29 | 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 | 40 | public String getDescription() { | ... | ... |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/OnlineRefundResult.java
| 1 | 1 | package com.diligrp.cashier.trade.domain; |
| 2 | 2 | |
| 3 | -import com.diligrp.cashier.shared.spi.RefundEvent; | |
| 4 | - | |
| 5 | 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 | 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 | 3 | import com.diligrp.cashier.shared.service.ServiceEndpointSupport; |
| 4 | 4 | import com.diligrp.cashier.shared.service.ThreadPoolService; |
| 5 | 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 | 8 | import com.diligrp.cashier.shared.util.JsonUtils; |
| 7 | 9 | import com.diligrp.cashier.shared.util.ObjectUtils; |
| 8 | -import com.diligrp.cashier.trade.domain.OnlineRefundResult; | |
| 9 | 10 | import com.diligrp.cashier.trade.domain.OnlinePaymentResult; |
| 11 | +import com.diligrp.cashier.trade.domain.OnlineRefundResult; | |
| 10 | 12 | import jakarta.annotation.Resource; |
| 11 | 13 | import org.slf4j.Logger; |
| 12 | 14 | import org.slf4j.LoggerFactory; |
| ... | ... | @@ -14,6 +16,8 @@ import org.springframework.beans.factory.ObjectProvider; |
| 14 | 16 | import org.springframework.stereotype.Service; |
| 15 | 17 | |
| 16 | 18 | import java.util.List; |
| 19 | +import java.util.concurrent.Future; | |
| 20 | +import java.util.concurrent.TimeUnit; | |
| 17 | 21 | |
| 18 | 22 | @Service("paymentResultManager") |
| 19 | 23 | public class PaymentResultManager { |
| ... | ... | @@ -24,34 +28,46 @@ public class PaymentResultManager { |
| 24 | 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 | 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 | 75 | /** |
| 60 | 76 | * 通知业务系统退款处理结果 |
| 61 | 77 | */ |
| 62 | - public void notifyRefundResult(String uri, OnlineRefundResult payload) { | |
| 78 | + public void notifyRefundResult(String uri, OnlineRefundResult refundResult) { | |
| 63 | 79 | ThreadPoolService.getIoThreadPoll().submit(() -> { |
| 64 | 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 | 97 | |
| 78 | 98 | ThreadPoolService.getIoThreadPoll().submit(() -> { |
| 79 | 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 | 103 | if (httpResult.statusCode != 200) { |
| 84 | 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 | 35 | ? properties.getContentEncoding() : StandardCharsets.UTF_8.name(); |
| 36 | 36 | try { |
| 37 | 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 | 39 | TaskMessage task = TaskMessage.fromJson(body); |
| 40 | 40 | int times = NumberUtils.str2Int(task.getParams(), Integer.MAX_VALUE); |
| 41 | 41 | if (task.getType() == TaskMessage.TYPE_CASHIER_ORDER_SCAN) { |
| ... | ... | @@ -46,7 +46,7 @@ public class TaskMessageConsumer { |
| 46 | 46 | LOG.error("Never happened"); |
| 47 | 47 | } |
| 48 | 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 | 47 | properties.setHeader("x-delay", String.valueOf(delayInMillis)); |
| 48 | 48 | String payload = JsonUtils.toJsonString(task); |
| 49 | 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 | 51 | rabbitTemplate.send(Constants.PAYMENT_DELAY_EXCHANGE, Constants.PAYMENT_DELAY_KEY, message); |
| 52 | 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 | 1 | package com.diligrp.cashier.trade.service.impl; |
| 2 | 2 | |
| 3 | -import com.diligrp.cashier.pipeline.Constants; | |
| 4 | 3 | import com.diligrp.cashier.pipeline.core.OnlinePipeline; |
| 5 | 4 | import com.diligrp.cashier.pipeline.core.PaymentPipeline; |
| 6 | 5 | import com.diligrp.cashier.pipeline.domain.OnlinePaymentResponse; |
| ... | ... | @@ -9,6 +8,7 @@ import com.diligrp.cashier.pipeline.domain.OnlineRefundOrder; |
| 9 | 8 | import com.diligrp.cashier.pipeline.domain.OnlineRefundResponse; |
| 10 | 9 | import com.diligrp.cashier.pipeline.service.IPaymentPipelineManager; |
| 11 | 10 | import com.diligrp.cashier.pipeline.type.PaymentState; |
| 11 | +import com.diligrp.cashier.trade.Constants; | |
| 12 | 12 | import com.diligrp.cashier.trade.dao.IOnlinePaymentDao; |
| 13 | 13 | import com.diligrp.cashier.trade.domain.TradeStateDTO; |
| 14 | 14 | import com.diligrp.cashier.trade.model.OnlinePayment; |
| ... | ... | @@ -49,13 +49,13 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 49 | 49 | |
| 50 | 50 | @Override |
| 51 | 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 | 54 | RLock lock = redissonClient.getLock(lockKey); |
| 55 | 55 | try { |
| 56 | 56 | lock.lock(); |
| 57 | 57 | LocalDateTime now = LocalDateTime.now(); |
| 58 | - // 理论上只会存在一条支付中的支付订单 | |
| 58 | + // 查询交易订单下状态为支付中的支付订单, 理论上只有一条支付记录 | |
| 59 | 59 | List<OnlinePayment> onlinePayments = onlinePaymentDao.listOnlinePayments(tradeId, |
| 60 | 60 | TradeType.TRADE.getCode(), PaymentState.PROCESSING.getCode()); |
| 61 | 61 | // 关闭所有未支付完成的支付订单 |
| ... | ... | @@ -65,7 +65,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 65 | 65 | if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { |
| 66 | 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 | 69 | OnlinePaymentResponse response = onlinePipeline.queryPrepayResponse(order); |
| 70 | 70 | if (!PaymentState.isFinished(response.getState().getCode())) { |
| 71 | 71 | try { |
| ... | ... | @@ -75,7 +75,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 75 | 75 | response.getOutPayType(), response.getPayerId(), response.getWhen(), |
| 76 | 76 | PaymentState.FAILED, "自动关闭超时的支付订单"); |
| 77 | 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 | 81 | cashierPaymentService.notifyPaymentResponse(response); |
| ... | ... | @@ -84,7 +84,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 84 | 84 | // 交易订单仍然未完成则关闭交易订单,交易订单不能继续支付 |
| 85 | 85 | TradeOrder trade = tradeAssistantService.findByTradeId(tradeId); |
| 86 | 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 | 88 | tradeAssistantService.proceedTradeOrder(tradeStateDTO); |
| 89 | 89 | } |
| 90 | 90 | } finally { |
| ... | ... | @@ -106,7 +106,7 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService { |
| 106 | 106 | OnlinePipeline<?> pipeline = paymentPipelineManager.findPipelineById(refund.getPipelineId(), OnlinePipeline.class); |
| 107 | 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 | 110 | OnlineRefundResponse response = pipeline.queryRefundResponse(order); |
| 111 | 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 | 20 | import com.diligrp.cashier.trade.dao.ITradeOrderDao; |
| 21 | 21 | import com.diligrp.cashier.trade.domain.*; |
| 22 | 22 | import com.diligrp.cashier.trade.exception.TradePaymentException; |
| 23 | -import com.diligrp.cashier.trade.manager.TaskMessageSender; | |
| 24 | 23 | import com.diligrp.cashier.trade.manager.PaymentResultManager; |
| 24 | +import com.diligrp.cashier.trade.manager.TaskMessageSender; | |
| 25 | 25 | import com.diligrp.cashier.trade.model.OnlinePayment; |
| 26 | 26 | import com.diligrp.cashier.trade.model.TradeOrder; |
| 27 | 27 | import com.diligrp.cashier.trade.service.ICashierPaymentService; |
| ... | ... | @@ -84,8 +84,9 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 84 | 84 | public String doSubmit(Merchant merchant, CashierOrder cashierOrder) { |
| 85 | 85 | LocalDateTime now = LocalDateTime.now(); |
| 86 | 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 | 90 | TradeOrder tradeOrder = TradeOrder.builder().mchId(merchant.getMchId()).tradeId(tradeId) |
| 90 | 91 | .type(cashierOrder.getType().getCode()).outTradeNo(cashierOrder.getOutTradeNo()).amount(cashierOrder.getAmount()) |
| 91 | 92 | .maxAmount(cashierOrder.getAmount()).goods(cashierOrder.getGoods()).timeout(timeout).state(TradeState.PENDING.getCode()) |
| ... | ... | @@ -93,10 +94,9 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 93 | 94 | .source(0).version(0).createdTime(now).modifiedTime(now).build(); |
| 94 | 95 | tradeOrderDao.insertTradeOrder(tradeOrder); |
| 95 | 96 | |
| 96 | - // TODO: userId是否需要存储 | |
| 97 | 97 | // 兜底处理交易订单,根据支付结果选择关闭或完成交易订单 |
| 98 | 98 | TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_ORDER_SCAN, tradeId, "1"); |
| 99 | - taskMessageSender.sendDelayTaskMessage(message, timeout); | |
| 99 | + taskMessageSender.sendDelayTaskMessage(message, timeout * 1000); // 转换成毫秒 | |
| 100 | 100 | return tradeId; |
| 101 | 101 | } |
| 102 | 102 | |
| ... | ... | @@ -113,7 +113,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 113 | 113 | String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, cashierPayment.getTradeId()); |
| 114 | 114 | RLock lock = redissonClient.getLock(lockKey); |
| 115 | 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 | 117 | if (locked) { |
| 118 | 118 | TradeOrder trade = tradeAssistantService.findByTradeId(cashierPayment.getTradeId()); |
| 119 | 119 | CashierType cashierType = CashierType.getByCode(trade.getType()); |
| ... | ... | @@ -131,52 +131,50 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 131 | 131 | |
| 132 | 132 | LocalDateTime now = LocalDateTime.now(); |
| 133 | 133 | // 获取支付通道 |
| 134 | - PaymentPipeline<?> paymentPipeline = paymentPipelineManager.findPipelineById( | |
| 134 | + PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById( | |
| 135 | 135 | cashierPayment.getPipelineId(), PaymentPipeline.class); |
| 136 | 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 | 140 | MiniProPrepayRequest request = new MiniProPaymentConverter(trade, paymentId, now).convert(cashierPayment); |
| 141 | - MiniProPrepayResponse response = pipeline.sendMiniProPrepayRequest(request); | |
| 141 | + MiniProPrepayResponse response = onlinePipeline.sendMiniProPrepayRequest(request); | |
| 142 | 142 | // 微信服务商模式下outMchId为签约子商户 |
| 143 | 143 | String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID); |
| 144 | 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 | 147 | .amount(trade.getAmount()).payerId(request.getOpenId()).outTradeNo(response.getOutTradeNo()) |
| 148 | 148 | .state(response.getState()).version(0).createdTime(now).modifiedTime(now).build(); |
| 149 | 149 | onlinePaymentDao.insertOnlinePayment(payment); |
| 150 | 150 | return response; |
| 151 | 151 | } |
| 152 | - if (paymentPipeline instanceof DiliCardPipeline pipeline) { // 园区卡支付通道 | |
| 152 | + if (pipeline instanceof DiliCardPipeline cardPipeline) { // 园区卡支付通道 | |
| 153 | 153 | // 园区卡支付通道: 所有的收银台类型使用的是同一种园区卡支付流程 |
| 154 | 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 | 159 | // 园区卡支付通道outMchId为市场ID |
| 159 | - String outMchId = pipeline.params().getOutMchId(); | |
| 160 | + String outMchId = cardPipeline.params().getOutMchId(); | |
| 160 | 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 | 164 | .amount(trade.getAmount()).payerId(response.getPayerId()) |
| 164 | 165 | .finishTime(response.getWhen()).outTradeNo(response.getOutTradeNo()) |
| 165 | 166 | .outPayType(OutPaymentType.DILICARD).state(response.getState()).notifyUrl(trade.getNotifyUrl()) |
| 166 | 167 | .description(response.getMessage()).version(0).createdTime(now).modifiedTime(now).build(); |
| 167 | 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 | 179 | return response; |
| 182 | 180 | } else { |
| ... | ... | @@ -205,10 +203,10 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 205 | 203 | public void notifyPaymentResponse(OnlinePaymentResponse response) { |
| 206 | 204 | OnlinePayment payment = tradeAssistantService.findByPaymentId(response.getPaymentId()); |
| 207 | 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 | 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 | 211 | if (PaymentState.isFinished(response.getState().getCode())) { |
| 214 | 212 | LocalDateTime now = LocalDateTime.now(); |
| ... | ... | @@ -224,14 +222,14 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 224 | 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 | 226 | TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS, trade.getVersion(), now); |
| 229 | 227 | tradeAssistantService.proceedTradeOrder(tradeStateDTO); |
| 230 | - | |
| 228 | + LOG.debug("Accomplish cashier order[{}] successfully", trade.getTradeId()); | |
| 231 | 229 | OnlinePaymentResult paymentResult = OnlinePaymentResult.of(trade.getTradeId(), payment.getPaymentId(), |
| 232 | 230 | response.getState(), trade.getOutTradeNo(), response.getOutPayType(), response.getPayerId(), |
| 233 | 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 | 234 | } finally { |
| 237 | 235 | if (lock.isHeldByCurrentThread()) { |
| ... | ... | @@ -280,6 +278,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { |
| 280 | 278 | |
| 281 | 279 | @Override |
| 282 | 280 | public OnlinePaymentResult queryPaymentState(String paymentId, String mode) { |
| 281 | + // TODO: 支付成功后返回支付成功的页面地址 | |
| 283 | 282 | OnlinePayment payment = tradeAssistantService.findByPaymentId(paymentId); |
| 284 | 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 | 3 | \ No newline at end of file | ... | ... |