Commit e6fca59aabbbdcdf42a325bdab38c530274d9e7d
1 parent
1b8f43e7
trade payment supported
Showing
77 changed files
with
3078 additions
and
285 deletions
cashier-assistant/src/main/java/com/diligrp/cashier/assistant/pattern/OptionToken.java
| @@ -15,7 +15,7 @@ public class OptionToken extends Token { | @@ -15,7 +15,7 @@ public class OptionToken extends Token { | ||
| 15 | 15 | ||
| 16 | @Override | 16 | @Override |
| 17 | Converter<SequenceKey> getConverter() { | 17 | Converter<SequenceKey> getConverter() { |
| 18 | - throw new AssistantServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "Not supported converter"); | 18 | + throw new AssistantServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "Not supported codec"); |
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | public String toString() { | 21 | public String toString() { |
cashier-boss/src/main/java/com/diligrp/cashier/boss/BossConfiguration.java
| 1 | package com.diligrp.cashier.boss; | 1 | package com.diligrp.cashier.boss; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.shared.mybatis.MybatisMapperSupport; | ||
| 3 | import com.diligrp.cashier.shared.service.LifeCycle; | 4 | import com.diligrp.cashier.shared.service.LifeCycle; |
| 4 | -import org.springframework.beans.BeansException; | 5 | +import jakarta.annotation.Resource; |
| 6 | +import org.mybatis.spring.annotation.MapperScan; | ||
| 7 | +import org.springframework.beans.factory.ObjectProvider; | ||
| 5 | import org.springframework.boot.ApplicationArguments; | 8 | import org.springframework.boot.ApplicationArguments; |
| 6 | import org.springframework.boot.ApplicationRunner; | 9 | import org.springframework.boot.ApplicationRunner; |
| 7 | -import org.springframework.context.ApplicationContext; | ||
| 8 | -import org.springframework.context.ApplicationContextAware; | 10 | +import org.springframework.boot.context.properties.ConfigurationProperties; |
| 11 | +import org.springframework.context.annotation.Bean; | ||
| 9 | import org.springframework.context.annotation.ComponentScan; | 12 | import org.springframework.context.annotation.ComponentScan; |
| 10 | import org.springframework.context.annotation.Configuration; | 13 | import org.springframework.context.annotation.Configuration; |
| 11 | 14 | ||
| 12 | -import java.util.Map; | 15 | +import java.util.List; |
| 13 | 16 | ||
| 14 | @Configuration | 17 | @Configuration |
| 15 | @ComponentScan("com.diligrp.cashier.boss") | 18 | @ComponentScan("com.diligrp.cashier.boss") |
| 16 | -public class BossConfiguration implements ApplicationContextAware, ApplicationRunner { | 19 | +@MapperScan(basePackages = {"com.diligrp.cashier.boss.dao"}, markerInterface = MybatisMapperSupport.class) |
| 20 | +public class BossConfiguration implements ApplicationRunner { | ||
| 17 | 21 | ||
| 18 | - private ApplicationContext applicationContext; | 22 | + @Resource |
| 23 | + private ObjectProvider<LifeCycle> lifeCycleProvider; | ||
| 24 | + | ||
| 25 | + @Bean | ||
| 26 | + @ConfigurationProperties("merchant") | ||
| 27 | + public CashierDeskProperties cashierDeskProperties() { | ||
| 28 | + return new CashierDeskProperties(); | ||
| 29 | + } | ||
| 19 | 30 | ||
| 20 | @Override | 31 | @Override |
| 21 | public void run(ApplicationArguments args) throws Exception { | 32 | public void run(ApplicationArguments args) throws Exception { |
| 22 | - Map<String, LifeCycle> beans = applicationContext.getBeansOfType(LifeCycle.class); | ||
| 23 | - for (LifeCycle lifeCycle : beans.values()) { | 33 | + List<LifeCycle> lifeCycles = lifeCycleProvider.stream().toList(); |
| 34 | + for (LifeCycle lifeCycle : lifeCycles) { | ||
| 24 | lifeCycle.start(); | 35 | lifeCycle.start(); |
| 25 | } | 36 | } |
| 26 | } | 37 | } |
| 27 | - | ||
| 28 | - @Override | ||
| 29 | - public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { | ||
| 30 | - this.applicationContext = applicationContext; | ||
| 31 | - } | ||
| 32 | } | 38 | } |
cashier-boss/src/main/java/com/diligrp/cashier/boss/CashierDeskProperties.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.trade.domain.MerchantParams; | ||
| 4 | + | ||
| 5 | +import javax.crypto.spec.SecretKeySpec; | ||
| 6 | + | ||
| 7 | +public class CashierDeskProperties { | ||
| 8 | + // 密钥 | ||
| 9 | + private SecretKeySpec secretKey; | ||
| 10 | + // 收银台配置 | ||
| 11 | + private MerchantParams.CashierParams cashier; | ||
| 12 | + | ||
| 13 | + public SecretKeySpec getSecretKey() { | ||
| 14 | + return secretKey; | ||
| 15 | + } | ||
| 16 | + | ||
| 17 | + public void setSecretKey(SecretKeySpec secretKey) { | ||
| 18 | + this.secretKey = secretKey; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public MerchantParams.CashierParams getCashier() { | ||
| 22 | + return cashier; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + public void setCashier(MerchantParams.CashierParams cashier) { | ||
| 26 | + this.cashier = cashier; | ||
| 27 | + } | ||
| 28 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/CashierServiceBootstrap.java
| @@ -4,6 +4,7 @@ import com.diligrp.cashier.assistant.AssistantConfiguration; | @@ -4,6 +4,7 @@ import com.diligrp.cashier.assistant.AssistantConfiguration; | ||
| 4 | import com.diligrp.cashier.mall.MallConfiguration; | 4 | import com.diligrp.cashier.mall.MallConfiguration; |
| 5 | import com.diligrp.cashier.pipeline.PipelineConfiguration; | 5 | import com.diligrp.cashier.pipeline.PipelineConfiguration; |
| 6 | import com.diligrp.cashier.shared.SharedConfiguration; | 6 | import com.diligrp.cashier.shared.SharedConfiguration; |
| 7 | +import com.diligrp.cashier.trade.TradeConfiguration; | ||
| 7 | import org.springframework.boot.SpringApplication; | 8 | import org.springframework.boot.SpringApplication; |
| 8 | import org.springframework.boot.SpringBootConfiguration; | 9 | import org.springframework.boot.SpringBootConfiguration; |
| 9 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; | 10 | import org.springframework.boot.autoconfigure.EnableAutoConfiguration; |
| @@ -12,13 +13,12 @@ import org.springframework.context.annotation.Import; | @@ -12,13 +13,12 @@ import org.springframework.context.annotation.Import; | ||
| 12 | 13 | ||
| 13 | @SpringBootConfiguration | 14 | @SpringBootConfiguration |
| 14 | @EnableAutoConfiguration | 15 | @EnableAutoConfiguration |
| 15 | -@Import({BossConfiguration.class, PipelineConfiguration.class, | ||
| 16 | - AssistantConfiguration.class, SharedConfiguration.class, | ||
| 17 | - MallConfiguration.class | 16 | +@Import({BossConfiguration.class, TradeConfiguration.class, PipelineConfiguration.class, |
| 17 | + AssistantConfiguration.class, SharedConfiguration.class, MallConfiguration.class | ||
| 18 | }) | 18 | }) |
| 19 | @EnableDiscoveryClient | 19 | @EnableDiscoveryClient |
| 20 | public class CashierServiceBootstrap { | 20 | public class CashierServiceBootstrap { |
| 21 | public static void main(String[] args) { | 21 | public static void main(String[] args) { |
| 22 | SpringApplication.run(CashierServiceBootstrap.class, args); | 22 | SpringApplication.run(CashierServiceBootstrap.class, args); |
| 23 | } | 23 | } |
| 24 | -} | 24 | +} |
| 25 | \ No newline at end of file | 25 | \ No newline at end of file |
cashier-boss/src/main/java/com/diligrp/cashier/boss/Constants.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss; | ||
| 2 | + | ||
| 3 | +public final class Constants { | ||
| 4 | + // 商户信息缓存Key | ||
| 5 | + public static final String MERCHANT_REDIS_KEY = "cashier:merchant:%s"; | ||
| 6 | + // TOKEN信息缓存Key | ||
| 7 | + public static final String TOKEN_REDIS_KEY = "cashier:token:%s"; | ||
| 8 | + // TOKEN参数名称 | ||
| 9 | + public static final String TOKEN_PARAM_NAME = "token"; | ||
| 10 | + // TOKEN签名算法 | ||
| 11 | + public static final String TOKEN_SIGN_ALGORITHM = "HmacSHA256"; | ||
| 12 | + // TOKEN的签名长度 | ||
| 13 | + public static final int TOKEN_SIGN_LENGTH = 8; | ||
| 14 | + // TOKEN过期时长,单位秒 | ||
| 15 | + public static final long TOKEN_TIMEOUT_SECONDS = 60; | ||
| 16 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/controller/CashierDeskController.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.controller; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.boss.domain.CashierOrderDTO; | ||
| 4 | +import com.diligrp.cashier.boss.domain.CashierPaymentUrl; | ||
| 5 | +import com.diligrp.cashier.boss.service.ICashierDeskService; | ||
| 6 | +import com.diligrp.cashier.boss.service.IMerchantService; | ||
| 7 | +import com.diligrp.cashier.boss.util.CashierOrderConverter; | ||
| 8 | +import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus; | ||
| 9 | +import com.diligrp.cashier.shared.domain.Message; | ||
| 10 | +import com.diligrp.cashier.shared.util.AssertUtils; | ||
| 11 | +import com.diligrp.cashier.trade.domain.CashierOrder; | ||
| 12 | +import com.diligrp.cashier.trade.domain.CashierPayment; | ||
| 13 | +import com.diligrp.cashier.trade.domain.Merchant; | ||
| 14 | +import jakarta.annotation.Resource; | ||
| 15 | +import org.springframework.web.bind.annotation.RequestBody; | ||
| 16 | +import org.springframework.web.bind.annotation.RequestMapping; | ||
| 17 | +import org.springframework.web.bind.annotation.RestController; | ||
| 18 | + | ||
| 19 | +@RestController | ||
| 20 | +@RequestMapping("/payment/cashier") | ||
| 21 | +public class CashierDeskController { | ||
| 22 | + | ||
| 23 | + @Resource | ||
| 24 | + private IMerchantService merchantService; | ||
| 25 | + | ||
| 26 | + @Resource | ||
| 27 | + private ICashierDeskService cashierDeskService; | ||
| 28 | + | ||
| 29 | + @RequestMapping("/submitOrder") | ||
| 30 | + public Message<?> submitOrder(@RequestBody CashierOrderDTO request) { | ||
| 31 | + // 基本参数校验 | ||
| 32 | + AssertUtils.notNull(request.getMchId(), "mchId missed"); | ||
| 33 | + AssertUtils.notEmpty(request.getUserId(), "userId missed"); | ||
| 34 | + AssertUtils.notNull(request.getCashierType(), "cashierType missed"); | ||
| 35 | + AssertUtils.notEmpty(request.getGoods(), "goods missed"); | ||
| 36 | + AssertUtils.notNull(request.getAmount(), "amount missed"); | ||
| 37 | + AssertUtils.isTrue(request.getAmount() > 0, "Invalid amount"); | ||
| 38 | + AssertUtils.notEmpty(request.getOutTradeNo(), "outTradeNo missed"); | ||
| 39 | + | ||
| 40 | + CashierOrder cashierOrder = CashierOrderConverter.INSTANCE.convert(request); | ||
| 41 | + Merchant merchant = merchantService.loadCashierMerchant(request.getMchId()); | ||
| 42 | + CashierPaymentUrl paymentUrl = cashierDeskService.doSubmit(merchant, cashierOrder); | ||
| 43 | + return Message.success(paymentUrl); | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + @RequestMapping("/orderPayment") | ||
| 47 | + public Message<?> orderPayment(@RequestBody CashierPayment request) { | ||
| 48 | + // 基本参数校验 | ||
| 49 | + AssertUtils.notEmpty(request.getTradeId(), "paymentId missed"); | ||
| 50 | + AssertUtils.notNull(request.getPipelineId(), "pipelineId missed"); | ||
| 51 | + | ||
| 52 | + OnlinePaymentStatus paymentStatus = cashierDeskService.doPayment(request); | ||
| 53 | + return Message.success(paymentStatus); | ||
| 54 | + } | ||
| 55 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/dao/IMerchantDao.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.dao; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.mybatis.MybatisMapperSupport; | ||
| 4 | +import com.diligrp.cashier.boss.model.MerchantDO; | ||
| 5 | +import org.springframework.stereotype.Repository; | ||
| 6 | + | ||
| 7 | +import java.util.Optional; | ||
| 8 | + | ||
| 9 | +@Repository("merchantDao") | ||
| 10 | +public interface IMerchantDao extends MybatisMapperSupport { | ||
| 11 | + Optional<MerchantDO> findByMchId(Long mchId); | ||
| 12 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/domain/CashierOrderDTO.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.domain; | ||
| 2 | + | ||
| 3 | +public class CashierOrderDTO { | ||
| 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 description; | ||
| 22 | + // 附加数据 | ||
| 23 | + private String attach; | ||
| 24 | + | ||
| 25 | + public Long getMchId() { | ||
| 26 | + return mchId; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public void setMchId(Long mchId) { | ||
| 30 | + this.mchId = mchId; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public String getUserId() { | ||
| 34 | + return userId; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public void setUserId(String userId) { | ||
| 38 | + this.userId = userId; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public Integer getCashierType() { | ||
| 42 | + return cashierType; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public void setCashierType(Integer cashierType) { | ||
| 46 | + this.cashierType = cashierType; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public String getGoods() { | ||
| 50 | + return goods; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public void setGoods(String goods) { | ||
| 54 | + this.goods = goods; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public Long getAmount() { | ||
| 58 | + return amount; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public void setAmount(Long amount) { | ||
| 62 | + this.amount = amount; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + public Integer getTimeout() { | ||
| 66 | + return timeout; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + public void setTimeout(Integer timeout) { | ||
| 70 | + this.timeout = timeout; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public String getOutTradeNo() { | ||
| 74 | + return outTradeNo; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + public void setOutTradeNo(String outTradeNo) { | ||
| 78 | + this.outTradeNo = outTradeNo; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + public String getNotifyUrl() { | ||
| 82 | + return notifyUrl; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + public void setNotifyUrl(String notifyUrl) { | ||
| 86 | + this.notifyUrl = notifyUrl; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + public String getDescription() { | ||
| 90 | + return description; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + public void setDescription(String description) { | ||
| 94 | + this.description = description; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + public String getAttach() { | ||
| 98 | + return attach; | ||
| 99 | + } | ||
| 100 | + | ||
| 101 | + public void setAttach(String attach) { | ||
| 102 | + this.attach = attach; | ||
| 103 | + } | ||
| 104 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/domain/CashierOrderToken.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.domain; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.boss.Constants; | ||
| 4 | +import com.diligrp.cashier.boss.exception.BossServiceException; | ||
| 5 | +import com.diligrp.cashier.shared.ErrorCode; | ||
| 6 | +import com.diligrp.cashier.shared.security.Base62Cipher; | ||
| 7 | +import com.diligrp.cashier.shared.security.HexUtils; | ||
| 8 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 9 | + | ||
| 10 | +import javax.crypto.Mac; | ||
| 11 | +import javax.crypto.spec.SecretKeySpec; | ||
| 12 | +import java.nio.charset.StandardCharsets; | ||
| 13 | +import java.util.Objects; | ||
| 14 | + | ||
| 15 | +public class CashierOrderToken { | ||
| 16 | + // 商户号 | ||
| 17 | + private Long mchId; | ||
| 18 | + // 交易ID | ||
| 19 | + private String tradeId; | ||
| 20 | + // 收银台类型 | ||
| 21 | + private Integer cashierType; | ||
| 22 | + // 业务系统用户标识 | ||
| 23 | + private String userId; | ||
| 24 | + | ||
| 25 | + public static String encode(Long tokenId, SecretKeySpec secretKey) { | ||
| 26 | + try { | ||
| 27 | + String payload = Base62Cipher.encodeLong(tokenId); | ||
| 28 | + Mac mac = Mac.getInstance(Constants.TOKEN_SIGN_ALGORITHM); | ||
| 29 | + mac.init(secretKey); | ||
| 30 | + | ||
| 31 | + byte[] bytes = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8)); | ||
| 32 | + String signature = HexUtils.encodeHexStr(bytes).substring(0, Constants.TOKEN_SIGN_LENGTH); | ||
| 33 | + payload = payload + signature; | ||
| 34 | + return payload; | ||
| 35 | + } catch (Exception ex) { | ||
| 36 | + throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "Failed to generate order token"); | ||
| 37 | + } | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public static long decode(String token, SecretKeySpec secretKey) { | ||
| 41 | + if (token == null || token.length() <= Constants.TOKEN_SIGN_LENGTH) { | ||
| 42 | + throw new BossServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "Invalid order token"); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + String payload = token.substring(0, token.length() - Constants.TOKEN_SIGN_LENGTH); | ||
| 46 | + String signature = token.substring(token.length() - Constants.TOKEN_SIGN_LENGTH); | ||
| 47 | + String tokenSign; | ||
| 48 | + try { | ||
| 49 | + Mac mac = Mac.getInstance(Constants.TOKEN_SIGN_ALGORITHM); | ||
| 50 | + mac.init(secretKey); | ||
| 51 | + byte[] bytes = mac.doFinal(payload.getBytes(StandardCharsets.UTF_8)); | ||
| 52 | + tokenSign = HexUtils.encodeHexStr(bytes).substring(0, Constants.TOKEN_SIGN_LENGTH); | ||
| 53 | + } catch (Exception ex) { | ||
| 54 | + throw new BossServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "Invalid order token"); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + if (!Objects.equals(signature, tokenSign)) { | ||
| 58 | + throw new BossServiceException(ErrorCode.OPERATION_NOT_ALLOWED, "Invalid order token signature"); | ||
| 59 | + } | ||
| 60 | + return Base62Cipher.decodeLong(payload); | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public static CashierOrderToken decode(String payload) { | ||
| 64 | + if (payload != null) { | ||
| 65 | + return JsonUtils.fromJsonString(payload, CashierOrderToken.class); | ||
| 66 | + } | ||
| 67 | + return null; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + public CashierOrderToken() { | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public CashierOrderToken(Long mchId, String tradeId, Integer cashierType, String userId) { | ||
| 74 | + this.mchId = mchId; | ||
| 75 | + this.tradeId = tradeId; | ||
| 76 | + this.cashierType = cashierType; | ||
| 77 | + this.userId = userId; | ||
| 78 | + } | ||
| 79 | + | ||
| 80 | + public Long getMchId() { | ||
| 81 | + return mchId; | ||
| 82 | + } | ||
| 83 | + | ||
| 84 | + public void setMchId(Long mchId) { | ||
| 85 | + this.mchId = mchId; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | + public String getTradeId() { | ||
| 89 | + return tradeId; | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + public void setTradeId(String tradeId) { | ||
| 93 | + this.tradeId = tradeId; | ||
| 94 | + } | ||
| 95 | + | ||
| 96 | + public Integer getCashierType() { | ||
| 97 | + return cashierType; | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + public void setCashierType(Integer cashierType) { | ||
| 101 | + this.cashierType = cashierType; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + public String getUserId() { | ||
| 105 | + return userId; | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + public void setUserId(String userId) { | ||
| 109 | + this.userId = userId; | ||
| 110 | + } | ||
| 111 | + | ||
| 112 | + @Override | ||
| 113 | + public String toString() { | ||
| 114 | + return JsonUtils.toJsonString(this); | ||
| 115 | + } | ||
| 116 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/domain/CashierPaymentUrl.java
0 → 100644
cashier-boss/src/main/java/com/diligrp/cashier/boss/exception/BossServiceException.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.exception; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.exception.PlatformServiceException; | ||
| 4 | + | ||
| 5 | +public class BossServiceException extends PlatformServiceException { | ||
| 6 | + public BossServiceException(String message) { | ||
| 7 | + super(message); | ||
| 8 | + } | ||
| 9 | + | ||
| 10 | + public BossServiceException(String code, String message) { | ||
| 11 | + super(code, message); | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + public BossServiceException(String message, Throwable ex) { | ||
| 15 | + super(message, ex); | ||
| 16 | + } | ||
| 17 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/model/MerchantDO.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.model; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.domain.BaseDO; | ||
| 4 | + | ||
| 5 | +import java.time.LocalDateTime; | ||
| 6 | + | ||
| 7 | +public class MerchantDO extends BaseDO { | ||
| 8 | + // 商户ID | ||
| 9 | + private Long mchId; | ||
| 10 | + // 商户名称 | ||
| 11 | + private String name; | ||
| 12 | + // 参数配置 | ||
| 13 | + private String param; | ||
| 14 | + // 商户地址 | ||
| 15 | + private String address; | ||
| 16 | + // 联系人 | ||
| 17 | + private String linkman; | ||
| 18 | + // 手机号 | ||
| 19 | + private String telephone; | ||
| 20 | + // 商户状态 | ||
| 21 | + private Integer state; | ||
| 22 | + | ||
| 23 | + public Long getMchId() { | ||
| 24 | + return mchId; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public void setMchId(Long mchId) { | ||
| 28 | + this.mchId = mchId; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public String getName() { | ||
| 32 | + return name; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public void setName(String name) { | ||
| 36 | + this.name = name; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public String getParam() { | ||
| 40 | + return param; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public void setParam(String param) { | ||
| 44 | + this.param = param; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public String getAddress() { | ||
| 48 | + return address; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + public void setAddress(String address) { | ||
| 52 | + this.address = address; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public String getLinkman() { | ||
| 56 | + return linkman; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + public void setLinkman(String linkman) { | ||
| 60 | + this.linkman = linkman; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public String getTelephone() { | ||
| 64 | + return telephone; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + public void setTelephone(String telephone) { | ||
| 68 | + this.telephone = telephone; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + public Integer getState() { | ||
| 72 | + return state; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + public void setState(Integer state) { | ||
| 76 | + this.state = state; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + public static Builder builder() { | ||
| 80 | + return new MerchantDO().new Builder(); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + public class Builder { | ||
| 84 | + public Builder mchId(Long mchId) { | ||
| 85 | + MerchantDO.this.mchId = mchId; | ||
| 86 | + return this; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + public Builder name(String name) { | ||
| 90 | + MerchantDO.this.name = name; | ||
| 91 | + return this; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + public Builder param(String param) { | ||
| 95 | + MerchantDO.this.param = param; | ||
| 96 | + return this; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + public Builder address(String address) { | ||
| 100 | + MerchantDO.this.address = address; | ||
| 101 | + return this; | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + public Builder linkman(String linkman) { | ||
| 105 | + MerchantDO.this.linkman = linkman; | ||
| 106 | + return this; | ||
| 107 | + } | ||
| 108 | + | ||
| 109 | + public Builder telephone(String telephone) { | ||
| 110 | + MerchantDO.this.telephone = telephone; | ||
| 111 | + return this; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + public Builder state(Integer state) { | ||
| 115 | + MerchantDO.this.state = state; | ||
| 116 | + return this; | ||
| 117 | + } | ||
| 118 | + | ||
| 119 | + public Builder createdTime(LocalDateTime createdTime) { | ||
| 120 | + MerchantDO.this.createdTime = createdTime; | ||
| 121 | + return this; | ||
| 122 | + } | ||
| 123 | + | ||
| 124 | + public Builder modifiedTime(LocalDateTime modifiedTime) { | ||
| 125 | + MerchantDO.this.modifiedTime = modifiedTime; | ||
| 126 | + return this; | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + public MerchantDO build() { | ||
| 130 | + return MerchantDO.this; | ||
| 131 | + } | ||
| 132 | + } | ||
| 133 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/ICashierDeskService.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.service; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.boss.domain.CashierPaymentUrl; | ||
| 4 | +import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus; | ||
| 5 | +import com.diligrp.cashier.trade.domain.CashierOrder; | ||
| 6 | +import com.diligrp.cashier.trade.domain.CashierPayment; | ||
| 7 | +import com.diligrp.cashier.trade.domain.Merchant; | ||
| 8 | + | ||
| 9 | +public interface ICashierDeskService { | ||
| 10 | + /** | ||
| 11 | + * 提交收银台订单 | ||
| 12 | + * | ||
| 13 | + * @param merchant - 接入商户 | ||
| 14 | + * @param order - 交易订单 | ||
| 15 | + * @return 交易订单 | ||
| 16 | + */ | ||
| 17 | + CashierPaymentUrl doSubmit(Merchant merchant, CashierOrder order); | ||
| 18 | + | ||
| 19 | + /** | ||
| 20 | + * 提交收银台支付 | ||
| 21 | + * | ||
| 22 | + * @param payment - 支付信息 | ||
| 23 | + * @return 支付状态 | ||
| 24 | + */ | ||
| 25 | + OnlinePaymentStatus doPayment(CashierPayment payment); | ||
| 26 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/IMerchantService.java
0 → 100644
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/impl/CashierDeskServiceImpl.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.service.impl; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.boss.CashierDeskProperties; | ||
| 4 | +import com.diligrp.cashier.boss.Constants; | ||
| 5 | +import com.diligrp.cashier.boss.domain.CashierOrderToken; | ||
| 6 | +import com.diligrp.cashier.boss.domain.CashierPaymentUrl; | ||
| 7 | +import com.diligrp.cashier.boss.service.ICashierDeskService; | ||
| 8 | +import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus; | ||
| 9 | +import com.diligrp.cashier.trade.domain.CashierOrder; | ||
| 10 | +import com.diligrp.cashier.trade.domain.CashierPayment; | ||
| 11 | +import com.diligrp.cashier.trade.domain.Merchant; | ||
| 12 | +import com.diligrp.cashier.trade.domain.MerchantParams; | ||
| 13 | +import com.diligrp.cashier.trade.service.ICashierPaymentService; | ||
| 14 | +import jakarta.annotation.Resource; | ||
| 15 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 16 | +import org.springframework.stereotype.Service; | ||
| 17 | + | ||
| 18 | +import java.util.concurrent.TimeUnit; | ||
| 19 | + | ||
| 20 | +@Service("cashierDeskService") | ||
| 21 | +public class CashierDeskServiceImpl implements ICashierDeskService { | ||
| 22 | + | ||
| 23 | + @Resource | ||
| 24 | + private ICashierPaymentService cashierPaymentService; | ||
| 25 | + | ||
| 26 | + @Resource | ||
| 27 | + private CashierDeskProperties cashierDeskProperties; | ||
| 28 | + | ||
| 29 | + @Resource | ||
| 30 | + private StringRedisTemplate stringRedisTemplate; | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 提交收银台订单 | ||
| 34 | + * | ||
| 35 | + * @param merchant - 接入商户 | ||
| 36 | + * @param order - 交易订单 | ||
| 37 | + * @return 交易订单 | ||
| 38 | + */ | ||
| 39 | + @Override | ||
| 40 | + public CashierPaymentUrl doSubmit(Merchant merchant, CashierOrder order) { | ||
| 41 | + String tradeId = cashierPaymentService.doSubmit(merchant, order); | ||
| 42 | + String token = CashierOrderToken.encode(Long.valueOf(tradeId), cashierDeskProperties.getSecretKey()); | ||
| 43 | + CashierOrderToken orderToken = new CashierOrderToken(merchant.getMchId(), tradeId, order.getType().getCode(), order.getUserId()); | ||
| 44 | + | ||
| 45 | + String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token); | ||
| 46 | + stringRedisTemplate.opsForValue().set(tokenKey, orderToken.toString(), Constants.TOKEN_TIMEOUT_SECONDS, TimeUnit.SECONDS); | ||
| 47 | + MerchantParams params = merchant.getParams(); | ||
| 48 | + String paymentUrl = switch (order.getType()) { | ||
| 49 | + case MINIPRO -> String.format("%s?%s=%s", params.getCashier().getMiniProUrl(), Constants.TOKEN_PARAM_NAME, token); | ||
| 50 | + case H5 -> String.format("%s?%s=%s", params.getCashier().getH5Url(), Constants.TOKEN_PARAM_NAME, token); | ||
| 51 | + case APP -> String.format("%s?%s=%s", params.getCashier().getAppUrl(), Constants.TOKEN_PARAM_NAME, token); | ||
| 52 | + default -> String.format("%s?%s=%s", params.getCashier().getPcUrl(), Constants.TOKEN_PARAM_NAME, token); | ||
| 53 | + }; | ||
| 54 | + return new CashierPaymentUrl(tradeId, paymentUrl); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 提交收银台支付 | ||
| 59 | + * | ||
| 60 | + * @param payment - 支付信息 | ||
| 61 | + * @return 支付状态 | ||
| 62 | + */ | ||
| 63 | + @Override | ||
| 64 | + public OnlinePaymentStatus doPayment(CashierPayment payment) { | ||
| 65 | + return cashierPaymentService.doPayment(payment); | ||
| 66 | + // TODO 是否需要删除token | ||
| 67 | +// String token = CashierOrderToken.encode(Long.valueOf(payment.getTradeId()), cashierDeskProperties.getSecretKey()); | ||
| 68 | +// String tokenKey = String.format(Constants.TOKEN_REDIS_KEY, token); | ||
| 69 | +// redisTemplate.delete(tokenKey); | ||
| 70 | + } | ||
| 71 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/service/impl/MerchantServiceImpl.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.service.impl; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.boss.CashierDeskProperties; | ||
| 4 | +import com.diligrp.cashier.boss.Constants; | ||
| 5 | +import com.diligrp.cashier.boss.dao.IMerchantDao; | ||
| 6 | +import com.diligrp.cashier.boss.exception.BossServiceException; | ||
| 7 | +import com.diligrp.cashier.boss.service.IMerchantService; | ||
| 8 | +import com.diligrp.cashier.boss.util.MerchantConverter; | ||
| 9 | +import com.diligrp.cashier.shared.ErrorCode; | ||
| 10 | +import com.diligrp.cashier.trade.domain.Merchant; | ||
| 11 | +import jakarta.annotation.Resource; | ||
| 12 | +import org.springframework.data.redis.core.StringRedisTemplate; | ||
| 13 | +import org.springframework.stereotype.Service; | ||
| 14 | + | ||
| 15 | +import java.util.Objects; | ||
| 16 | + | ||
| 17 | +/** | ||
| 18 | + * 支付平台接入许可服务 | ||
| 19 | + */ | ||
| 20 | +@Service("merchantService") | ||
| 21 | +public class MerchantServiceImpl implements IMerchantService { | ||
| 22 | + | ||
| 23 | + @Resource | ||
| 24 | + private IMerchantDao merchantDao; | ||
| 25 | + | ||
| 26 | + @Resource | ||
| 27 | + private CashierDeskProperties cashierDeskProperties; | ||
| 28 | + | ||
| 29 | + @Resource | ||
| 30 | + private StringRedisTemplate stringRedisTemplate; | ||
| 31 | + | ||
| 32 | + @Override | ||
| 33 | + public Merchant loadCashierMerchant(Long mchId) { | ||
| 34 | + String cacheKey = String.format(Constants.MERCHANT_REDIS_KEY, mchId); | ||
| 35 | + String payload = stringRedisTemplate.opsForValue().get(cacheKey); | ||
| 36 | + Merchant merchant = Merchant.decode(payload); | ||
| 37 | + if (Objects.isNull(merchant)) { | ||
| 38 | + merchant = merchantDao.findByMchId(mchId).map(new MerchantConverter(cashierDeskProperties)::convert) | ||
| 39 | + .orElseThrow(() -> new BossServiceException(ErrorCode.OBJECT_NOT_FOUND, "商家信息未注册")); | ||
| 40 | + stringRedisTemplate.opsForValue().set(cacheKey, merchant.toString()); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + return merchant; | ||
| 44 | + } | ||
| 45 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/util/CashierOrderConverter.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.util; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.boss.domain.CashierOrderDTO; | ||
| 4 | +import com.diligrp.cashier.pipeline.type.CashierType; | ||
| 5 | +import com.diligrp.cashier.shared.codec.IConverter; | ||
| 6 | +import com.diligrp.cashier.trade.domain.CashierOrder; | ||
| 7 | + | ||
| 8 | +public class CashierOrderConverter implements IConverter<CashierOrderDTO, CashierOrder> { | ||
| 9 | + | ||
| 10 | + public static IConverter<CashierOrderDTO, CashierOrder> INSTANCE = new CashierOrderConverter(); | ||
| 11 | + | ||
| 12 | + @Override | ||
| 13 | + public CashierOrder convert(CashierOrderDTO 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.setDescription(cashierOrderDTO.getDescription()); | ||
| 23 | + cashierOrder.setAttach(cashierOrderDTO.getAttach()); | ||
| 24 | + return cashierOrder; | ||
| 25 | + } | ||
| 26 | +} |
cashier-boss/src/main/java/com/diligrp/cashier/boss/util/MerchantConverter.java
0 → 100644
| 1 | +package com.diligrp.cashier.boss.util; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.boss.CashierDeskProperties; | ||
| 4 | +import com.diligrp.cashier.boss.model.MerchantDO; | ||
| 5 | +import com.diligrp.cashier.shared.codec.IConverter; | ||
| 6 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 7 | +import com.diligrp.cashier.trade.domain.Merchant; | ||
| 8 | +import com.diligrp.cashier.trade.domain.MerchantParams; | ||
| 9 | + | ||
| 10 | +import java.util.Objects; | ||
| 11 | + | ||
| 12 | +public class MerchantConverter implements IConverter<MerchantDO, Merchant> { | ||
| 13 | + | ||
| 14 | + private final CashierDeskProperties cashierProperties; | ||
| 15 | + | ||
| 16 | + public MerchantConverter(CashierDeskProperties cashierProperties) { | ||
| 17 | + this.cashierProperties = cashierProperties; | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + @Override | ||
| 21 | + public Merchant convert(MerchantDO merchantDO) { | ||
| 22 | + Merchant merchant = new Merchant(); | ||
| 23 | + merchant.setMchId(merchantDO.getMchId()); | ||
| 24 | + merchant.setName(merchantDO.getName()); | ||
| 25 | + if (Objects.nonNull(merchantDO.getParam())) { | ||
| 26 | + merchant.setParams(JsonUtils.fromJsonString(merchantDO.getParam(), MerchantParams.class)); | ||
| 27 | + } else { | ||
| 28 | + merchant.setParams(new MerchantParams()); | ||
| 29 | + } | ||
| 30 | + MerchantParams params = merchant.getParams(); | ||
| 31 | + | ||
| 32 | + if (Objects.isNull(params.getCashier())) { | ||
| 33 | + params.setCashier(new MerchantParams.CashierParams()); | ||
| 34 | + } | ||
| 35 | + params.getCashier().override(cashierProperties.getCashier()); | ||
| 36 | + | ||
| 37 | + return merchant; | ||
| 38 | + } | ||
| 39 | +} |
cashier-boss/src/main/resources/com/diligrp/cashier/dao/mapper/IMerchantDao.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
| 3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 4 | + | ||
| 5 | +<mapper namespace="com.diligrp.cashier.boss.dao.IMerchantDao"> | ||
| 6 | + <resultMap id="MerchantMap" type="com.diligrp.cashier.boss.model.MerchantDO"> | ||
| 7 | + <result column="id" property="id"/> | ||
| 8 | + <result column="mch_id" property="mchId"/> | ||
| 9 | + <result column="name" property="name"/> | ||
| 10 | + <result column="param" property="param"/> | ||
| 11 | + <result column="address" property="address"/> | ||
| 12 | + <result column="linkman" property="linkman"/> | ||
| 13 | + <result column="telephone" property="telephone"/> | ||
| 14 | + <result column="state" property="state"/> | ||
| 15 | + <result column="created_time" property="createdTime"/> | ||
| 16 | + <result column="modified_time" property="modifiedTime"/> | ||
| 17 | + </resultMap> | ||
| 18 | + | ||
| 19 | + <select id="findByMchId" parameterType="long" resultMap="MerchantMap"> | ||
| 20 | + SELECT * FROM upay_merchant WHERE mch_id = #{mchId} | ||
| 21 | + </select> | ||
| 22 | +</mapper> |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/CardPaymentHttpClient.java
| 1 | package com.diligrp.cashier.pipeline.client; | 1 | package com.diligrp.cashier.pipeline.client; |
| 2 | 2 | ||
| 3 | import com.diligrp.cashier.pipeline.domain.*; | 3 | import com.diligrp.cashier.pipeline.domain.*; |
| 4 | +import com.diligrp.cashier.pipeline.domain.card.CardPaymentRequest; | ||
| 5 | +import com.diligrp.cashier.pipeline.domain.card.CardPaymentResponse; | ||
| 4 | import com.diligrp.cashier.pipeline.type.PaymentState; | 6 | import com.diligrp.cashier.pipeline.type.PaymentState; |
| 5 | import com.diligrp.cashier.shared.service.ServiceEndpointSupport; | 7 | import com.diligrp.cashier.shared.service.ServiceEndpointSupport; |
| 6 | import org.slf4j.Logger; | 8 | import org.slf4j.Logger; |
| @@ -20,11 +22,11 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { | @@ -20,11 +22,11 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { | ||
| 20 | this.baseUri = baseUri; | 22 | this.baseUri = baseUri; |
| 21 | } | 23 | } |
| 22 | 24 | ||
| 23 | - public OnlinePaymentResponse sendPaymentRequest(OnlinePaymentRequest request) { | 25 | + public CardPaymentResponse sendPaymentRequest(CardPaymentRequest request) { |
| 24 | return null; | 26 | return null; |
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | - public OnlinePaymentResponse queryPrepayResponse(OnlinePrepayOrder order) { | 29 | + public CardPaymentResponse queryPaymentResponse(OnlinePrepayOrder order) { |
| 28 | return null; | 30 | return null; |
| 29 | } | 31 | } |
| 30 | 32 |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/WechatDirectHttpClient.java
| @@ -68,7 +68,7 @@ public class WechatDirectHttpClient extends WechatHttpClient { | @@ -68,7 +68,7 @@ public class WechatDirectHttpClient extends WechatHttpClient { | ||
| 68 | verifyHttpResult(result); | 68 | verifyHttpResult(result); |
| 69 | if (result.statusCode == 200) { // 200 处理成功有返回,204处理成功无返回 | 69 | if (result.statusCode == 200) { // 200 处理成功有返回,204处理成功无返回 |
| 70 | Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); | 70 | Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 71 | - return NativePrepayResponse.of(request.getPaymentId(), null, (String) response.get("code_url")); | 71 | + return NativePrepayResponse.of(request.getPaymentId(), (String) response.get("code_url")); |
| 72 | } else { | 72 | } else { |
| 73 | LOG.error("Wechat native prepay failed: {}\n{}", result.statusCode, result.responseText); | 73 | LOG.error("Wechat native prepay failed: {}\n{}", result.statusCode, result.responseText); |
| 74 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); | 74 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); |
| @@ -131,7 +131,7 @@ public class WechatDirectHttpClient extends WechatHttpClient { | @@ -131,7 +131,7 @@ public class WechatDirectHttpClient extends WechatHttpClient { | ||
| 131 | String openId = payer == null ? null : (String) payer.get("openid"); | 131 | String openId = payer == null ? null : (String) payer.get("openid"); |
| 132 | PaymentState state = WechatStateUtils.getPaymentState((String) response.get("trade_state")); | 132 | PaymentState state = WechatStateUtils.getPaymentState((String) response.get("trade_state")); |
| 133 | return OnlinePaymentResponse.of((String) response.get("out_trade_no"), (String) response.get("transaction_id"), | 133 | return OnlinePaymentResponse.of((String) response.get("out_trade_no"), (String) response.get("transaction_id"), |
| 134 | - openId, when, state.getCode(), (String) response.get("trade_state_desc")); | 134 | + openId, when, state, (String) response.get("trade_state_desc")); |
| 135 | } else { | 135 | } else { |
| 136 | LOG.info("Wechat query transaction status failed: {}", result.statusCode); | 136 | LOG.info("Wechat query transaction status failed: {}", result.statusCode); |
| 137 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); | 137 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/WechatPartnerHttpClient.java
| @@ -69,7 +69,7 @@ public class WechatPartnerHttpClient extends WechatHttpClient { | @@ -69,7 +69,7 @@ public class WechatPartnerHttpClient extends WechatHttpClient { | ||
| 69 | verifyHttpResult(result); | 69 | verifyHttpResult(result); |
| 70 | if (result.statusCode == 200) { // 200 处理成功有返回,204处理成功无返回 | 70 | if (result.statusCode == 200) { // 200 处理成功有返回,204处理成功无返回 |
| 71 | Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); | 71 | Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {}); |
| 72 | - return NativePrepayResponse.of(request.getPaymentId(), null, (String) response.get("code_url")); | 72 | + return NativePrepayResponse.of(request.getPaymentId(), (String) response.get("code_url")); |
| 73 | } else { | 73 | } else { |
| 74 | LOG.error("Wechat native prepay failed: {}\n{}", result.statusCode, result.responseText); | 74 | LOG.error("Wechat native prepay failed: {}\n{}", result.statusCode, result.responseText); |
| 75 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); | 75 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); |
| @@ -135,7 +135,7 @@ public class WechatPartnerHttpClient extends WechatHttpClient { | @@ -135,7 +135,7 @@ public class WechatPartnerHttpClient extends WechatHttpClient { | ||
| 135 | String openId = payer == null ? null : (String) payer.get("sp_openid"); // 获取服务商APPID下的openId,而非子商户APPID下的openId | 135 | String openId = payer == null ? null : (String) payer.get("sp_openid"); // 获取服务商APPID下的openId,而非子商户APPID下的openId |
| 136 | PaymentState state = WechatStateUtils.getPaymentState((String) response.get("trade_state")); | 136 | PaymentState state = WechatStateUtils.getPaymentState((String) response.get("trade_state")); |
| 137 | return OnlinePaymentResponse.of((String) response.get("out_trade_no"), (String) response.get("transaction_id"), | 137 | return OnlinePaymentResponse.of((String) response.get("out_trade_no"), (String) response.get("transaction_id"), |
| 138 | - openId, when, state.getCode(), (String) response.get("trade_state_desc")); | 138 | + openId, when, state, (String) response.get("trade_state_desc")); |
| 139 | } else { | 139 | } else { |
| 140 | LOG.info("Wechat query transaction status failed: {}", result.statusCode); | 140 | LOG.info("Wechat query transaction status failed: {}", result.statusCode); |
| 141 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); | 141 | ErrorMessage message = JsonUtils.fromJsonString(result.responseText, ErrorMessage.class); |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/core/CardPipeline.java deleted
100644 → 0
| 1 | -package com.diligrp.cashier.pipeline.core; | ||
| 2 | - | ||
| 3 | -import com.diligrp.cashier.pipeline.client.CardPaymentHttpClient; | ||
| 4 | -import com.diligrp.cashier.pipeline.domain.*; | ||
| 5 | -import com.diligrp.cashier.pipeline.exception.PaymentPipelineException; | ||
| 6 | -import com.diligrp.cashier.shared.ErrorCode; | ||
| 7 | -import org.slf4j.Logger; | ||
| 8 | -import org.slf4j.LoggerFactory; | ||
| 9 | - | ||
| 10 | -/** | ||
| 11 | - * 园区卡支付通道抽象模型 | ||
| 12 | - */ | ||
| 13 | -public abstract class CardPipeline extends PaymentPipeline<CardPipeline.CardParams> { | ||
| 14 | - | ||
| 15 | - private static final Logger LOG = LoggerFactory.getLogger(CardPipeline.class); | ||
| 16 | - | ||
| 17 | - private final ScanTimeStrategy strategy; | ||
| 18 | - | ||
| 19 | - private final CardPaymentHttpClient client; | ||
| 20 | - | ||
| 21 | - public CardPipeline(long mchId, long pipelineId, String name, String uri, String params) throws Exception { | ||
| 22 | - super(mchId, pipelineId, name, uri, params); | ||
| 23 | - this.strategy = new DefaultTimeStrategy(); | ||
| 24 | - this.client = new CardPaymentHttpClient(uri); | ||
| 25 | - } | ||
| 26 | - | ||
| 27 | - /** | ||
| 28 | - * 发送预支付订单的支付申请 - 目前针对园区卡扫码支付 | ||
| 29 | - */ | ||
| 30 | - public OnlinePaymentResponse sendPaymentRequest(OnlinePaymentRequest request) { | ||
| 31 | - try { | ||
| 32 | - return client.sendPaymentRequest(request); | ||
| 33 | - } catch (PaymentPipelineException | IllegalArgumentException pse) { | ||
| 34 | - throw pse; | ||
| 35 | - } catch (Exception ex) { | ||
| 36 | - LOG.error("Send card payment request exception", ex); | ||
| 37 | - throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "发起地利支付申请失败"); | ||
| 38 | - } | ||
| 39 | - } | ||
| 40 | - | ||
| 41 | - /** | ||
| 42 | - * 查询支付订单状态 | ||
| 43 | - */ | ||
| 44 | - public OnlinePaymentResponse queryPrepayResponse(OnlinePrepayOrder order) { | ||
| 45 | - try { | ||
| 46 | - return client.queryPrepayResponse(order); | ||
| 47 | - } catch (PaymentPipelineException | IllegalArgumentException pse) { | ||
| 48 | - throw pse; | ||
| 49 | - } catch (Exception ex) { | ||
| 50 | - LOG.error("Query card payment state request exception", ex); | ||
| 51 | - throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "查询地利支付状态失败"); | ||
| 52 | - } | ||
| 53 | - } | ||
| 54 | - | ||
| 55 | - /** | ||
| 56 | - * 关闭预支付订单 | ||
| 57 | - */ | ||
| 58 | - public void closePrepayOrder(OnlinePrepayOrder request) { | ||
| 59 | - // 不调用远程关单接口 | ||
| 60 | - } | ||
| 61 | - | ||
| 62 | - /** | ||
| 63 | - * 退款申请 | ||
| 64 | - */ | ||
| 65 | - public OnlineRefundResponse sendRefundRequest(OnlineRefundRequest request) { | ||
| 66 | - try { | ||
| 67 | - return client.sendRefundRequest(request); | ||
| 68 | - } catch (PaymentPipelineException | IllegalArgumentException pse) { | ||
| 69 | - throw pse; | ||
| 70 | - } catch (Exception ex) { | ||
| 71 | - LOG.error("Send card refund request exception", ex); | ||
| 72 | - throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "发起微信退款失败"); | ||
| 73 | - } | ||
| 74 | - } | ||
| 75 | - | ||
| 76 | - public CardPaymentHttpClient getClient() { | ||
| 77 | - return this.client; | ||
| 78 | - } | ||
| 79 | - | ||
| 80 | - public ScanTimeStrategy getTimeStrategy() { | ||
| 81 | - return strategy; | ||
| 82 | - } | ||
| 83 | - | ||
| 84 | - @Override | ||
| 85 | - public Class<CardParams> paramClass() { | ||
| 86 | - return CardParams.class; | ||
| 87 | - } | ||
| 88 | - | ||
| 89 | - public static class CardParams extends PipelineParams { | ||
| 90 | - public CardParams(String params) { | ||
| 91 | - super(params); | ||
| 92 | - } | ||
| 93 | - } | ||
| 94 | -} |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/core/DiliCardPipeline.java
| 1 | package com.diligrp.cashier.pipeline.core; | 1 | package com.diligrp.cashier.pipeline.core; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.pipeline.client.CardPaymentHttpClient; | ||
| 4 | +import com.diligrp.cashier.pipeline.domain.OnlinePrepayOrder; | ||
| 5 | +import com.diligrp.cashier.pipeline.domain.OnlineRefundRequest; | ||
| 6 | +import com.diligrp.cashier.pipeline.domain.OnlineRefundResponse; | ||
| 7 | +import com.diligrp.cashier.pipeline.domain.card.CardPaymentRequest; | ||
| 8 | +import com.diligrp.cashier.pipeline.domain.card.CardPaymentResponse; | ||
| 9 | +import com.diligrp.cashier.pipeline.exception.PaymentPipelineException; | ||
| 3 | import com.diligrp.cashier.pipeline.type.ChannelType; | 10 | import com.diligrp.cashier.pipeline.type.ChannelType; |
| 11 | +import com.diligrp.cashier.shared.ErrorCode; | ||
| 12 | +import org.slf4j.Logger; | ||
| 13 | +import org.slf4j.LoggerFactory; | ||
| 4 | 14 | ||
| 5 | /** | 15 | /** |
| 6 | - * 地利园区支付通道模型 | 16 | + * 地利园区卡支付通道模型 |
| 7 | */ | 17 | */ |
| 8 | -public class DiliCardPipeline extends CardPipeline { | 18 | +public class DiliCardPipeline extends OnlinePipeline<DiliCardPipeline.CardParams> { |
| 19 | + | ||
| 20 | + private static final Logger LOG = LoggerFactory.getLogger(DiliCardPipeline.class); | ||
| 21 | + | ||
| 22 | + private final ScanTimeStrategy strategy; | ||
| 23 | + | ||
| 24 | + private final CardPaymentHttpClient client; | ||
| 9 | 25 | ||
| 10 | public DiliCardPipeline(long mchId, long pipelineId, String name, String uri, String params) throws Exception { | 26 | public DiliCardPipeline(long mchId, long pipelineId, String name, String uri, String params) throws Exception { |
| 11 | super(mchId, pipelineId, name, uri, params); | 27 | super(mchId, pipelineId, name, uri, params); |
| 28 | + this.strategy = new DefaultTimeStrategy(); | ||
| 29 | + this.client = new CardPaymentHttpClient(uri); | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + /** | ||
| 33 | + * 发送预支付订单的支付申请 - 目前针对园区卡扫码支付 | ||
| 34 | + */ | ||
| 35 | + public CardPaymentResponse sendPaymentRequest(CardPaymentRequest request) { | ||
| 36 | + try { | ||
| 37 | + return client.sendPaymentRequest(request); | ||
| 38 | + } catch (PaymentPipelineException | IllegalArgumentException pse) { | ||
| 39 | + throw pse; | ||
| 40 | + } catch (Exception ex) { | ||
| 41 | + LOG.error("Send card payment request exception", ex); | ||
| 42 | + throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "发起地利支付申请失败"); | ||
| 43 | + } | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + /** | ||
| 47 | + * 查询支付订单状态 | ||
| 48 | + */ | ||
| 49 | + public CardPaymentResponse queryPaymentResponse(OnlinePrepayOrder order) { | ||
| 50 | + try { | ||
| 51 | + return client.queryPaymentResponse(order); | ||
| 52 | + } catch (PaymentPipelineException | IllegalArgumentException pse) { | ||
| 53 | + throw pse; | ||
| 54 | + } catch (Exception ex) { | ||
| 55 | + LOG.error("Query card payment state request exception", ex); | ||
| 56 | + throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "查询地利支付状态失败"); | ||
| 57 | + } | ||
| 58 | + } | ||
| 59 | + | ||
| 60 | + /** | ||
| 61 | + * 关闭预支付订单 | ||
| 62 | + */ | ||
| 63 | + public void closePrepayOrder(OnlinePrepayOrder request) { | ||
| 64 | + // 不调用远程关单接口 | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * 退款申请 | ||
| 69 | + */ | ||
| 70 | + public OnlineRefundResponse sendRefundRequest(OnlineRefundRequest request) { | ||
| 71 | + try { | ||
| 72 | + return client.sendRefundRequest(request); | ||
| 73 | + } catch (PaymentPipelineException | IllegalArgumentException pse) { | ||
| 74 | + throw pse; | ||
| 75 | + } catch (Exception ex) { | ||
| 76 | + LOG.error("Send card refund request exception", ex); | ||
| 77 | + throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "发起微信退款失败"); | ||
| 78 | + } | ||
| 12 | } | 79 | } |
| 13 | 80 | ||
| 14 | @Override | 81 | @Override |
| 15 | public ChannelType supportedChannel() { | 82 | public ChannelType supportedChannel() { |
| 16 | return ChannelType.DILIPAY; | 83 | return ChannelType.DILIPAY; |
| 17 | } | 84 | } |
| 85 | + | ||
| 86 | + public ScanTimeStrategy getTimeStrategy() { | ||
| 87 | + return strategy; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + @Override | ||
| 91 | + public Class<CardParams> paramClass() { | ||
| 92 | + return CardParams.class; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + public static class CardParams extends PipelineParams { | ||
| 96 | + // 园区卡所属市场 | ||
| 97 | + private String outMchId; | ||
| 98 | + | ||
| 99 | + public CardParams(String params) { | ||
| 100 | + super(params); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + public String getOutMchId() { | ||
| 104 | + return outMchId; | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + public void setOutMchId(String outMchId) { | ||
| 108 | + this.outMchId = outMchId; | ||
| 109 | + } | ||
| 110 | + } | ||
| 18 | } | 111 | } |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/core/OnlinePipeline.java
| @@ -5,9 +5,7 @@ import com.diligrp.cashier.pipeline.exception.PaymentPipelineException; | @@ -5,9 +5,7 @@ import com.diligrp.cashier.pipeline.exception.PaymentPipelineException; | ||
| 5 | import com.diligrp.cashier.shared.ErrorCode; | 5 | import com.diligrp.cashier.shared.ErrorCode; |
| 6 | 6 | ||
| 7 | /** | 7 | /** |
| 8 | - * 在线支付通道抽象模型 | ||
| 9 | - * | ||
| 10 | - * TODO: 此支付通道类是否所有支付通道的基类(微信、支付宝、银行聚合支付),还是仅仅作为银行聚合支付的基类,需要仔细斟酌 | 8 | + * 在线支付通道抽象模型: 支持微信、支付宝、各类银行聚合支付, 但不包括园区卡支付通道 |
| 11 | */ | 9 | */ |
| 12 | public abstract class OnlinePipeline<T extends PaymentPipeline.PipelineParams> extends PaymentPipeline<T> { | 10 | public abstract class OnlinePipeline<T extends PaymentPipeline.PipelineParams> extends PaymentPipeline<T> { |
| 13 | 11 | ||
| @@ -23,17 +21,17 @@ public abstract class OnlinePipeline<T extends PaymentPipeline.PipelineParams> e | @@ -23,17 +21,17 @@ public abstract class OnlinePipeline<T extends PaymentPipeline.PipelineParams> e | ||
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | /** | 23 | /** |
| 26 | - * 付款码支付 - 商户扫客户付款码 | 24 | + * 小程序支付 |
| 27 | */ | 25 | */ |
| 28 | - public OnlinePaymentResponse sendQrCodePaymentRequest(OnlinePaymentRequest request) { | ||
| 29 | - throw new PaymentPipelineException(ErrorCode.OPERATION_NOT_ALLOWED, "支付通道暂不支持付款码支付"); | 26 | + public MiniProPrepayResponse sendMiniProPrepayRequest(MiniProPrepayRequest request) { |
| 27 | + throw new PaymentPipelineException(ErrorCode.OPERATION_NOT_ALLOWED, "支付通道暂不支持小程序支付"); | ||
| 30 | } | 28 | } |
| 31 | 29 | ||
| 32 | /** | 30 | /** |
| 33 | - * 小程序支付 | 31 | + * 直接支付 - 比如: 微信付款码, 园区卡支付等 |
| 34 | */ | 32 | */ |
| 35 | - public MiniProPrepayResponse sendMiniProPrepayRequest(MiniProPrepayRequest request) { | ||
| 36 | - throw new PaymentPipelineException(ErrorCode.OPERATION_NOT_ALLOWED, "支付通道暂不支持小程序支付"); | 33 | + public OnlinePaymentResponse sendQrCodePaymentRequest(QrCodePaymentRequest request) { |
| 34 | + throw new PaymentPipelineException(ErrorCode.OPERATION_NOT_ALLOWED, "支付通道暂不支持付款码支付"); | ||
| 37 | } | 35 | } |
| 38 | 36 | ||
| 39 | /** | 37 | /** |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/core/PaymentPipeline.java
| @@ -8,6 +8,12 @@ import com.diligrp.cashier.shared.util.ObjectUtils; | @@ -8,6 +8,12 @@ import com.diligrp.cashier.shared.util.ObjectUtils; | ||
| 8 | import java.lang.reflect.Constructor; | 8 | import java.lang.reflect.Constructor; |
| 9 | import java.lang.reflect.InvocationTargetException; | 9 | import java.lang.reflect.InvocationTargetException; |
| 10 | 10 | ||
| 11 | +/** | ||
| 12 | + * 所有支付通道的基类, 目前分两类支付通道: 在线支付通道、园区卡支付通道 | ||
| 13 | + * | ||
| 14 | + * 在线支付通道支持: 微信支付、支付宝、各类银行聚合支付 | ||
| 15 | + * 园区卡支付通道是指地利一卡通支付 | ||
| 16 | + */ | ||
| 11 | public abstract class PaymentPipeline<T extends PaymentPipeline.PipelineParams> implements IPipeline<T> { | 17 | public abstract class PaymentPipeline<T extends PaymentPipeline.PipelineParams> implements IPipeline<T> { |
| 12 | // 通道所属商户 | 18 | // 通道所属商户 |
| 13 | private final long mchId; | 19 | private final long mchId; |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/core/WechatPipeline.java
| @@ -97,14 +97,6 @@ public abstract class WechatPipeline extends OnlinePipeline<WechatPipeline.Wecha | @@ -97,14 +97,6 @@ public abstract class WechatPipeline extends OnlinePipeline<WechatPipeline.Wecha | ||
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | /** | 99 | /** |
| 100 | - * 付款码支付 - 商户扫客户付款码 | ||
| 101 | - */ | ||
| 102 | - @Override | ||
| 103 | - public OnlinePaymentResponse sendQrCodePaymentRequest(OnlinePaymentRequest request) { | ||
| 104 | - return super.sendQrCodePaymentRequest(request); | ||
| 105 | - } | ||
| 106 | - | ||
| 107 | - /** | ||
| 108 | * 小程序预支付下单 | 100 | * 小程序预支付下单 |
| 109 | */ | 101 | */ |
| 110 | public MiniProPrepayResponse sendMiniProPrepayRequest(MiniProPrepayRequest request) { | 102 | public MiniProPrepayResponse sendMiniProPrepayRequest(MiniProPrepayRequest request) { |
| @@ -129,6 +121,14 @@ public abstract class WechatPipeline extends OnlinePipeline<WechatPipeline.Wecha | @@ -129,6 +121,14 @@ public abstract class WechatPipeline extends OnlinePipeline<WechatPipeline.Wecha | ||
| 129 | } | 121 | } |
| 130 | 122 | ||
| 131 | /** | 123 | /** |
| 124 | + * 付款码支付 - 商户扫客户付款码 | ||
| 125 | + */ | ||
| 126 | + @Override | ||
| 127 | + public OnlinePaymentResponse sendQrCodePaymentRequest(QrCodePaymentRequest request) { | ||
| 128 | + return super.sendQrCodePaymentRequest(request); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | * 查询预支付订单状态 | 132 | * 查询预支付订单状态 |
| 133 | */ | 133 | */ |
| 134 | public OnlinePaymentResponse queryPrepayResponse(OnlinePrepayOrder order) { | 134 | public OnlinePaymentResponse queryPrepayResponse(OnlinePrepayOrder order) { |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/MiniProPrepayResponse.java
| 1 | package com.diligrp.cashier.pipeline.domain; | 1 | package com.diligrp.cashier.pipeline.domain; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 4 | + | ||
| 3 | /** | 5 | /** |
| 4 | * 小程序预支付响应 | 6 | * 小程序预支付响应 |
| 5 | */ | 7 | */ |
| 6 | -public class MiniProPrepayResponse extends OnlinePrepayResponse { | 8 | +public class MiniProPrepayResponse extends OnlinePaymentStatus { |
| 7 | // 微信预支付ID | 9 | // 微信预支付ID |
| 8 | protected String prepayId; | 10 | protected String prepayId; |
| 9 | // 时间戳 | 11 | // 时间戳 |
| @@ -17,16 +19,18 @@ public class MiniProPrepayResponse extends OnlinePrepayResponse { | @@ -17,16 +19,18 @@ public class MiniProPrepayResponse extends OnlinePrepayResponse { | ||
| 17 | 19 | ||
| 18 | public static MiniProPrepayResponse of(String paymentId, String outTradeNo, String prepayId, String timeStamp, | 20 | public static MiniProPrepayResponse of(String paymentId, String outTradeNo, String prepayId, String timeStamp, |
| 19 | String nonceStr, String signType, String paySign) { | 21 | String nonceStr, String signType, String paySign) { |
| 20 | - MiniProPrepayResponse response = new MiniProPrepayResponse(); | ||
| 21 | - response.paymentId = paymentId; | ||
| 22 | - response.outTradeNo = outTradeNo; | ||
| 23 | - response.prepayId = prepayId; | ||
| 24 | - response.timeStamp = timeStamp; | ||
| 25 | - response.nonceStr = nonceStr; | ||
| 26 | - response.signType = signType; | ||
| 27 | - response.paySign = paySign; | ||
| 28 | - | ||
| 29 | - return response; | 22 | + return new MiniProPrepayResponse(paymentId, outTradeNo, PaymentState.PROCESSING, prepayId, timeStamp, |
| 23 | + nonceStr, signType, paySign); | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public MiniProPrepayResponse(String paymentId, String outTradeNo, PaymentState state, String prepayId, | ||
| 27 | + String timeStamp, String nonceStr, String signType, String paySign) { | ||
| 28 | + super(paymentId, outTradeNo, state); | ||
| 29 | + this.prepayId = prepayId; | ||
| 30 | + this.timeStamp = timeStamp; | ||
| 31 | + this.nonceStr = nonceStr; | ||
| 32 | + this.signType = signType; | ||
| 33 | + this.paySign = paySign; | ||
| 30 | } | 34 | } |
| 31 | 35 | ||
| 32 | public String getPrepayId() { | 36 | public String getPrepayId() { |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/NativePrepayResponse.java
| 1 | package com.diligrp.cashier.pipeline.domain; | 1 | package com.diligrp.cashier.pipeline.domain; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 4 | + | ||
| 3 | /** | 5 | /** |
| 4 | * 扫码预支付响应 | 6 | * 扫码预支付响应 |
| 5 | */ | 7 | */ |
| 6 | -public class NativePrepayResponse extends OnlinePrepayResponse { | 8 | +public class NativePrepayResponse extends OnlinePaymentStatus { |
| 7 | // 二维码链接 | 9 | // 二维码链接 |
| 8 | - protected String codeUri; | 10 | + protected String codeUrl; |
| 11 | + | ||
| 12 | + public static NativePrepayResponse of(String paymentId, String codeUrl) { | ||
| 13 | + return new NativePrepayResponse(paymentId, null, PaymentState.PROCESSING, codeUrl); | ||
| 14 | + } | ||
| 9 | 15 | ||
| 10 | - public static NativePrepayResponse of(String paymentId, String outTradeNo, String codeUri) { | ||
| 11 | - NativePrepayResponse response = new NativePrepayResponse(); | ||
| 12 | - response.paymentId = paymentId; | ||
| 13 | - response.outTradeNo = outTradeNo; | ||
| 14 | - response.codeUri = codeUri; | ||
| 15 | - return response; | 16 | + public NativePrepayResponse(String paymentId, String outTradeNo, PaymentState state, String codeUrl) { |
| 17 | + super(paymentId, outTradeNo, state); | ||
| 18 | + this.codeUrl = codeUrl; | ||
| 16 | } | 19 | } |
| 17 | 20 | ||
| 18 | - public String getCodeUri() { | ||
| 19 | - return codeUri; | 21 | + public String getCodeUrl() { |
| 22 | + return codeUrl; | ||
| 20 | } | 23 | } |
| 21 | } | 24 | } |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/OnlinePaymentRequest.java
| @@ -10,15 +10,15 @@ import java.util.Map; | @@ -10,15 +10,15 @@ import java.util.Map; | ||
| 10 | */ | 10 | */ |
| 11 | public class OnlinePaymentRequest extends ContainerSupport { | 11 | public class OnlinePaymentRequest extends ContainerSupport { |
| 12 | // 支付ID | 12 | // 支付ID |
| 13 | - protected String paymentId; | 13 | + protected final String paymentId; |
| 14 | // 交易金额 - 分 | 14 | // 交易金额 - 分 |
| 15 | - protected long amount; | 15 | + protected final long amount; |
| 16 | // 商品描述 | 16 | // 商品描述 |
| 17 | - protected String goods; | 17 | + protected final String goods; |
| 18 | // 交易备注 | 18 | // 交易备注 |
| 19 | - protected String description; | 19 | + protected final String description; |
| 20 | // 交易时间 | 20 | // 交易时间 |
| 21 | - protected LocalDateTime when; | 21 | + protected final LocalDateTime when; |
| 22 | 22 | ||
| 23 | public OnlinePaymentRequest(String paymentId, long amount, String goods, String description, LocalDateTime when) { | 23 | public OnlinePaymentRequest(String paymentId, long amount, String goods, String description, LocalDateTime when) { |
| 24 | this.paymentId = paymentId; | 24 | this.paymentId = paymentId; |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/OnlinePaymentResponse.java
| 1 | package com.diligrp.cashier.pipeline.domain; | 1 | package com.diligrp.cashier.pipeline.domain; |
| 2 | 2 | ||
| 3 | -import com.diligrp.cashier.shared.domain.ContainerSupport; | 3 | +import com.diligrp.cashier.pipeline.type.OutPaymentType; |
| 4 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 4 | 5 | ||
| 5 | import java.time.LocalDateTime; | 6 | import java.time.LocalDateTime; |
| 6 | 7 | ||
| 7 | /** | 8 | /** |
| 8 | * 在线支付结果领域模型 | 9 | * 在线支付结果领域模型 |
| 9 | */ | 10 | */ |
| 10 | -public class OnlinePaymentResponse extends ContainerSupport { | ||
| 11 | - // 支付ID | ||
| 12 | - private String paymentId; | ||
| 13 | - // 支付通道订单号 | ||
| 14 | - private String outTradeNo; | 11 | +public class OnlinePaymentResponse extends OnlinePaymentStatus { |
| 12 | + // 实际支付方式-聚合支付时 | ||
| 13 | + private final OutPaymentType outPayType; | ||
| 15 | // 支付方Id - 比如微信OpenId | 14 | // 支付方Id - 比如微信OpenId |
| 16 | - private String payerId; | 15 | + private final String payerId; |
| 17 | // 支付时间 | 16 | // 支付时间 |
| 18 | - private LocalDateTime when; | ||
| 19 | - // 支付状态 | ||
| 20 | - private Integer state; | 17 | + private final LocalDateTime when; |
| 21 | // 交易备注 | 18 | // 交易备注 |
| 22 | - private String message; | 19 | + private final String message; |
| 20 | + | ||
| 21 | + public static OnlinePaymentResponse of(String paymentId, String outTradeNo, LocalDateTime when, | ||
| 22 | + PaymentState state, String message) { | ||
| 23 | + return new OnlinePaymentResponse(paymentId, outTradeNo, null, null, when, state, message); | ||
| 24 | + } | ||
| 23 | 25 | ||
| 24 | public static OnlinePaymentResponse of(String paymentId, String outTradeNo, String payerId, | 26 | public static OnlinePaymentResponse of(String paymentId, String outTradeNo, String payerId, |
| 25 | - LocalDateTime when, Integer state, String message) { | ||
| 26 | - OnlinePaymentResponse response = new OnlinePaymentResponse(); | ||
| 27 | - response.paymentId = paymentId; | ||
| 28 | - response.outTradeNo = outTradeNo; | ||
| 29 | - response.payerId = payerId; | ||
| 30 | - response.when = when; | ||
| 31 | - response.state = state; | ||
| 32 | - response.message = message; | ||
| 33 | - return response; | 27 | + LocalDateTime when, PaymentState state, String message) { |
| 28 | + return new OnlinePaymentResponse(paymentId, outTradeNo, null, payerId, when, state, message); | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public static OnlinePaymentResponse of(String paymentId, String outTradeNo, OutPaymentType outPayType, | ||
| 32 | + LocalDateTime when, PaymentState state, String message) { | ||
| 33 | + return new OnlinePaymentResponse(paymentId, outTradeNo, outPayType, null, when, state, message); | ||
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | - public String getPaymentId() { | ||
| 37 | - return paymentId; | 36 | + public OnlinePaymentResponse(String paymentId, String outTradeNo, OutPaymentType outPayType, |
| 37 | + String payerId, LocalDateTime when, PaymentState state, String message) { | ||
| 38 | + super(paymentId, outTradeNo, state); | ||
| 39 | + this.outPayType = outPayType; | ||
| 40 | + this.payerId = payerId; | ||
| 41 | + this.when = when; | ||
| 42 | + this.message = message; | ||
| 38 | } | 43 | } |
| 39 | 44 | ||
| 40 | - public String getOutTradeNo() { | ||
| 41 | - return outTradeNo; | 45 | + public OutPaymentType getOutPayType() { |
| 46 | + return outPayType; | ||
| 42 | } | 47 | } |
| 43 | 48 | ||
| 44 | public String getPayerId() { | 49 | public String getPayerId() { |
| @@ -49,10 +54,6 @@ public class OnlinePaymentResponse extends ContainerSupport { | @@ -49,10 +54,6 @@ public class OnlinePaymentResponse extends ContainerSupport { | ||
| 49 | return when; | 54 | return when; |
| 50 | } | 55 | } |
| 51 | 56 | ||
| 52 | - public Integer getState() { | ||
| 53 | - return state; | ||
| 54 | - } | ||
| 55 | - | ||
| 56 | public String getMessage() { | 57 | public String getMessage() { |
| 57 | return message; | 58 | return message; |
| 58 | } | 59 | } |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/OnlinePrepayResponse.java renamed to cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/OnlinePaymentStatus.java
| 1 | package com.diligrp.cashier.pipeline.domain; | 1 | package com.diligrp.cashier.pipeline.domain; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 4 | + | ||
| 3 | /** | 5 | /** |
| 4 | - * 预支付响应 | 6 | + * 在线支付状态,所有支付结果的抽象类 |
| 5 | */ | 7 | */ |
| 6 | -public class OnlinePrepayResponse { | 8 | +public class OnlinePaymentStatus { |
| 7 | // 支付订单号 | 9 | // 支付订单号 |
| 8 | protected String paymentId; | 10 | protected String paymentId; |
| 9 | // 通道订单号 | 11 | // 通道订单号 |
| 10 | protected String outTradeNo; | 12 | protected String outTradeNo; |
| 13 | + // 支付状态 | ||
| 14 | + protected PaymentState state; | ||
| 15 | + | ||
| 16 | + public OnlinePaymentStatus(String paymentId, String outTradeNo, PaymentState state) { | ||
| 17 | + this.paymentId = paymentId; | ||
| 18 | + this.outTradeNo = outTradeNo; | ||
| 19 | + this.state = state; | ||
| 20 | + } | ||
| 11 | 21 | ||
| 12 | public String getPaymentId() { | 22 | public String getPaymentId() { |
| 13 | return paymentId; | 23 | return paymentId; |
| @@ -16,4 +26,8 @@ public class OnlinePrepayResponse { | @@ -16,4 +26,8 @@ public class OnlinePrepayResponse { | ||
| 16 | public String getOutTradeNo() { | 26 | public String getOutTradeNo() { |
| 17 | return outTradeNo; | 27 | return outTradeNo; |
| 18 | } | 28 | } |
| 29 | + | ||
| 30 | + public PaymentState getState() { | ||
| 31 | + return state; | ||
| 32 | + } | ||
| 19 | } | 33 | } |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/OnlineRefundResponse.java
| 1 | package com.diligrp.cashier.pipeline.domain; | 1 | package com.diligrp.cashier.pipeline.domain; |
| 2 | 2 | ||
| 3 | -import com.diligrp.cashier.shared.domain.ContainerSupport; | ||
| 4 | - | ||
| 5 | import java.time.LocalDateTime; | 3 | import java.time.LocalDateTime; |
| 6 | 4 | ||
| 7 | /** | 5 | /** |
| 8 | * 退款结果领域模型 | 6 | * 退款结果领域模型 |
| 9 | */ | 7 | */ |
| 10 | -public class OnlineRefundResponse extends ContainerSupport { | 8 | +public class OnlineRefundResponse { |
| 11 | // 商户退款单号 | 9 | // 商户退款单号 |
| 12 | private String refundId; | 10 | private String refundId; |
| 13 | // 通道退款订单号 | 11 | // 通道退款订单号 |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/QrCodePaymentRequest.java
0 → 100644
| 1 | +package com.diligrp.cashier.pipeline.domain; | ||
| 2 | + | ||
| 3 | +import java.time.LocalDateTime; | ||
| 4 | + | ||
| 5 | +/** | ||
| 6 | + * 付款码支付 | ||
| 7 | + */ | ||
| 8 | +public class QrCodePaymentRequest extends OnlinePaymentRequest { | ||
| 9 | + private final String qrCode; | ||
| 10 | + | ||
| 11 | + public QrCodePaymentRequest(String paymentId, long amount, String goods, String description, LocalDateTime when, String qrCode) { | ||
| 12 | + super(paymentId, amount, goods, description, when); | ||
| 13 | + this.qrCode = qrCode; | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + public String getQrCode() { | ||
| 17 | + return qrCode; | ||
| 18 | + } | ||
| 19 | +} |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/card/CardPaymentRequest.java
0 → 100644
| 1 | +package com.diligrp.cashier.pipeline.domain.card; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.domain.OnlinePaymentRequest; | ||
| 4 | + | ||
| 5 | +import java.time.LocalDateTime; | ||
| 6 | + | ||
| 7 | +public class CardPaymentRequest extends OnlinePaymentRequest { | ||
| 8 | + private final Long accountId; | ||
| 9 | + private final String cardNo; | ||
| 10 | + | ||
| 11 | + public CardPaymentRequest(String paymentId, long amount, String goods, String description, LocalDateTime when, | ||
| 12 | + Long accountId, String cardNo) { | ||
| 13 | + super(paymentId, amount, goods, description, when); | ||
| 14 | + this.accountId = accountId; | ||
| 15 | + this.cardNo = cardNo; | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + public Long getAccountId() { | ||
| 19 | + return accountId; | ||
| 20 | + } | ||
| 21 | + | ||
| 22 | + public String getCardNo() { | ||
| 23 | + return cardNo; | ||
| 24 | + } | ||
| 25 | +} |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/domain/card/CardPaymentResponse.java
0 → 100644
| 1 | +package com.diligrp.cashier.pipeline.domain.card; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.domain.OnlinePaymentResponse; | ||
| 4 | +import com.diligrp.cashier.pipeline.type.OutPaymentType; | ||
| 5 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 6 | + | ||
| 7 | +import java.time.LocalDateTime; | ||
| 8 | + | ||
| 9 | +public class CardPaymentResponse extends OnlinePaymentResponse { | ||
| 10 | + | ||
| 11 | + public CardPaymentResponse(String paymentId, String outTradeNo, OutPaymentType outPayType, String payerId, LocalDateTime when, PaymentState state, String message) { | ||
| 12 | + super(paymentId, outTradeNo, outPayType, payerId, when, state, message); | ||
| 13 | + } | ||
| 14 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/type/CashierDesk.java renamed to cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/CashierType.java
| 1 | -package com.diligrp.cashier.trade.type; | 1 | +package com.diligrp.cashier.pipeline.type; |
| 2 | 2 | ||
| 3 | -import com.diligrp.cashier.shared.ErrorCode; | ||
| 4 | import com.diligrp.cashier.shared.type.IEnumType; | 3 | import com.diligrp.cashier.shared.type.IEnumType; |
| 5 | -import com.diligrp.cashier.trade.exception.TradePaymentException; | ||
| 6 | 4 | ||
| 7 | import java.util.Arrays; | 5 | import java.util.Arrays; |
| 8 | import java.util.Objects; | 6 | import java.util.Objects; |
| @@ -10,24 +8,23 @@ import java.util.Optional; | @@ -10,24 +8,23 @@ import java.util.Optional; | ||
| 10 | import java.util.stream.Stream; | 8 | import java.util.stream.Stream; |
| 11 | 9 | ||
| 12 | /** | 10 | /** |
| 13 | - * 终端来源 | 11 | + * 收银台类型 |
| 14 | */ | 12 | */ |
| 15 | -public enum CashierDesk implements IEnumType { | ||
| 16 | - | ||
| 17 | - NOP("无收银台", 0), | 13 | +public enum CashierType implements IEnumType { |
| 18 | 14 | ||
| 19 | PC("PC收银台", 1), | 15 | PC("PC收银台", 1), |
| 20 | 16 | ||
| 21 | MINIPRO("小程序收银台", 2), | 17 | MINIPRO("小程序收银台", 2), |
| 22 | 18 | ||
| 23 | - H5("H5收银台", 2), | 19 | + H5("H5收银台", 3), |
| 20 | + | ||
| 21 | + APP("APP收银台", 4); | ||
| 24 | 22 | ||
| 25 | - APP("APP收银台", 3); | ||
| 26 | 23 | ||
| 27 | private final String name; | 24 | private final String name; |
| 28 | private final int code; | 25 | private final int code; |
| 29 | 26 | ||
| 30 | - CashierDesk(String name, int code) { | 27 | + CashierType(String name, int code) { |
| 31 | this.name = name; | 28 | this.name = name; |
| 32 | this.code = code; | 29 | this.code = code; |
| 33 | } | 30 | } |
| @@ -36,24 +33,26 @@ public enum CashierDesk implements IEnumType { | @@ -36,24 +33,26 @@ public enum CashierDesk implements IEnumType { | ||
| 36 | return this.code == code; | 33 | return this.code == code; |
| 37 | } | 34 | } |
| 38 | 35 | ||
| 39 | - public static Optional<CashierDesk> getType(int code) { | ||
| 40 | - Stream<CashierDesk> TYPES = Arrays.stream(CashierDesk.values()); | 36 | + public static Optional<CashierType> getType(int code) { |
| 37 | + Stream<CashierType> TYPES = Arrays.stream(CashierType.values()); | ||
| 41 | return TYPES.filter(type -> type.getCode() == code).findFirst(); | 38 | return TYPES.filter(type -> type.getCode() == code).findFirst(); |
| 42 | } | 39 | } |
| 43 | 40 | ||
| 44 | - public static CashierDesk getByCode(int code) { | ||
| 45 | - return getType(code).orElseThrow(() -> new TradePaymentException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "系统暂不支持此收银台类型")); | 41 | + public static CashierType getByCode(int code) { |
| 42 | + return getType(code).orElseThrow(() -> new IllegalArgumentException("系统暂不支持此收银台类型")); | ||
| 46 | } | 43 | } |
| 47 | 44 | ||
| 48 | - public static void validateIfNonNull(Integer code) { | 45 | + public static CashierType getIfNonNull(Integer code) { |
| 49 | if (Objects.nonNull(code)) { | 46 | if (Objects.nonNull(code)) { |
| 50 | - Stream<CashierDesk> TYPES = Arrays.stream(CashierDesk.values()); | ||
| 51 | - TYPES.filter(type -> type.getCode() == code).findFirst().orElseThrow(() -> new IllegalArgumentException("Invalid cashier desk")); | 47 | + Stream<CashierType> TYPES = Arrays.stream(CashierType.values()); |
| 48 | + return TYPES.filter(type -> type.getCode() == code).findFirst() | ||
| 49 | + .orElseThrow(() -> new IllegalArgumentException("Invalid cashier desk")); | ||
| 52 | } | 50 | } |
| 51 | + return null; | ||
| 53 | } | 52 | } |
| 54 | 53 | ||
| 55 | public static String getName(int code) { | 54 | public static String getName(int code) { |
| 56 | - return getType(code).map(CashierDesk::getName).orElse(null); | 55 | + return getType(code).map(CashierType::getName).orElse(null); |
| 57 | } | 56 | } |
| 58 | 57 | ||
| 59 | @Override | 58 | @Override |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/ChannelType.java
| 1 | package com.diligrp.cashier.pipeline.type; | 1 | package com.diligrp.cashier.pipeline.type; |
| 2 | 2 | ||
| 3 | -import com.diligrp.cashier.pipeline.exception.PaymentPipelineException; | ||
| 4 | import com.diligrp.cashier.shared.ErrorCode; | 3 | import com.diligrp.cashier.shared.ErrorCode; |
| 4 | +import com.diligrp.cashier.shared.exception.PlatformServiceException; | ||
| 5 | import com.diligrp.cashier.shared.type.IEnumType; | 5 | import com.diligrp.cashier.shared.type.IEnumType; |
| 6 | 6 | ||
| 7 | import java.util.Arrays; | 7 | import java.util.Arrays; |
| @@ -15,13 +15,11 @@ import java.util.stream.Stream; | @@ -15,13 +15,11 @@ import java.util.stream.Stream; | ||
| 15 | */ | 15 | */ |
| 16 | public enum ChannelType implements IEnumType { | 16 | public enum ChannelType implements IEnumType { |
| 17 | 17 | ||
| 18 | - NOP("未知渠道", 0), | ||
| 19 | - | ||
| 20 | WXPAY("微信渠道", 10), | 18 | WXPAY("微信渠道", 10), |
| 21 | 19 | ||
| 22 | ALIPAY("支付宝渠道", 11), | 20 | ALIPAY("支付宝渠道", 11), |
| 23 | 21 | ||
| 24 | - DILIPAY("地利渠道", 18), // 地利园区卡支付 | 22 | + DILIPAY("地利渠道", 19), // 地利园区卡支付 |
| 25 | 23 | ||
| 26 | ICBC("工商银行", 20), | 24 | ICBC("工商银行", 20), |
| 27 | 25 | ||
| @@ -61,7 +59,7 @@ public enum ChannelType implements IEnumType { | @@ -61,7 +59,7 @@ public enum ChannelType implements IEnumType { | ||
| 61 | } | 59 | } |
| 62 | 60 | ||
| 63 | public static ChannelType getByCode(int code) { | 61 | public static ChannelType getByCode(int code) { |
| 64 | - return getType(code).orElseThrow(() -> new PaymentPipelineException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "系统不支持此支付渠道")); | 62 | + return getType(code).orElseThrow(() -> new PlatformServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "系统不支持此支付渠道")); |
| 65 | } | 63 | } |
| 66 | 64 | ||
| 67 | public static String getName(int code) { | 65 | public static String getName(int code) { |
cashier-trade/src/main/java/com/diligrp/cashier/trade/type/OutPaymentType.java renamed to cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/OutPaymentType.java
| 1 | -package com.diligrp.cashier.trade.type; | 1 | +package com.diligrp.cashier.pipeline.type; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.pipeline.exception.PaymentPipelineException; | ||
| 3 | import com.diligrp.cashier.shared.ErrorCode; | 4 | import com.diligrp.cashier.shared.ErrorCode; |
| 4 | import com.diligrp.cashier.shared.type.IEnumType; | 5 | import com.diligrp.cashier.shared.type.IEnumType; |
| 5 | -import com.diligrp.cashier.trade.exception.TradePaymentException; | ||
| 6 | 6 | ||
| 7 | import java.util.Arrays; | 7 | import java.util.Arrays; |
| 8 | import java.util.Optional; | 8 | import java.util.Optional; |
| 9 | import java.util.stream.Stream; | 9 | import java.util.stream.Stream; |
| 10 | 10 | ||
| 11 | /** | 11 | /** |
| 12 | - * 聚合支付时实际使用的支付方式 | 12 | + * 聚合支付通道实际使用的支付方式 |
| 13 | */ | 13 | */ |
| 14 | public enum OutPaymentType implements IEnumType { | 14 | public enum OutPaymentType implements IEnumType { |
| 15 | - NOP("其他方式", 0), | ||
| 16 | 15 | ||
| 17 | WXPAY("微信支付", 10), | 16 | WXPAY("微信支付", 10), |
| 18 | 17 | ||
| @@ -22,6 +21,8 @@ public enum OutPaymentType implements IEnumType { | @@ -22,6 +21,8 @@ public enum OutPaymentType implements IEnumType { | ||
| 22 | 21 | ||
| 23 | APP("掌银支付", 13), | 22 | APP("掌银支付", 13), |
| 24 | 23 | ||
| 24 | + DILICARD("园区卡支付", 19), | ||
| 25 | + | ||
| 25 | BANKCARD("银行卡支付", 20); | 26 | BANKCARD("银行卡支付", 20); |
| 26 | 27 | ||
| 27 | private final String name; | 28 | private final String name; |
| @@ -42,7 +43,7 @@ public enum OutPaymentType implements IEnumType { | @@ -42,7 +43,7 @@ public enum OutPaymentType implements IEnumType { | ||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | public static OutPaymentType getByCode(int code) { | 45 | public static OutPaymentType getByCode(int code) { |
| 45 | - return getType(code).orElseThrow(() -> new TradePaymentException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "系统暂不支持该支付方式")); | 46 | + return getType(code).orElseThrow(() -> new PaymentPipelineException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "系统暂不支持该支付方式")); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 48 | public static String getName(int code) { | 49 | public static String getName(int code) { |
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/PaymentState.java
| 1 | package com.diligrp.cashier.pipeline.type; | 1 | package com.diligrp.cashier.pipeline.type; |
| 2 | 2 | ||
| 3 | import com.diligrp.cashier.shared.type.IEnumType; | 3 | import com.diligrp.cashier.shared.type.IEnumType; |
| 4 | +import com.fasterxml.jackson.annotation.JsonValue; | ||
| 4 | 5 | ||
| 5 | import java.util.Arrays; | 6 | import java.util.Arrays; |
| 6 | import java.util.List; | 7 | import java.util.List; |
| @@ -45,12 +46,25 @@ public enum PaymentState implements IEnumType { | @@ -45,12 +46,25 @@ public enum PaymentState implements IEnumType { | ||
| 45 | return Arrays.asList(PaymentState.values()); | 46 | return Arrays.asList(PaymentState.values()); |
| 46 | } | 47 | } |
| 47 | 48 | ||
| 49 | + public static boolean isPending(int code) { | ||
| 50 | + return PaymentState.PENDING.equalTo(code); | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public static boolean isProcessing(int code) { | ||
| 54 | + return PaymentState.PROCESSING.equalTo(code); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public static boolean isFinished(int code) { | ||
| 58 | + return PaymentState.SUCCESS.equalTo(code) || PaymentState.FAILED.equalTo(code); | ||
| 59 | + } | ||
| 60 | + | ||
| 48 | @Override | 61 | @Override |
| 49 | public String getName() { | 62 | public String getName() { |
| 50 | return name; | 63 | return name; |
| 51 | } | 64 | } |
| 52 | 65 | ||
| 53 | @Override | 66 | @Override |
| 67 | + @JsonValue | ||
| 54 | public int getCode() { | 68 | public int getCode() { |
| 55 | return code; | 69 | return code; |
| 56 | } | 70 | } |
cashier-trade/src/main/java/com/diligrp/cashier/trade/type/PaymentType.java renamed to cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/type/PaymentType.java
| 1 | -package com.diligrp.cashier.trade.type; | 1 | +package com.diligrp.cashier.pipeline.type; |
| 2 | 2 | ||
| 3 | import com.diligrp.cashier.shared.ErrorCode; | 3 | import com.diligrp.cashier.shared.ErrorCode; |
| 4 | +import com.diligrp.cashier.shared.exception.PlatformServiceException; | ||
| 4 | import com.diligrp.cashier.shared.type.IEnumType; | 5 | import com.diligrp.cashier.shared.type.IEnumType; |
| 5 | -import com.diligrp.cashier.trade.exception.TradePaymentException; | ||
| 6 | 6 | ||
| 7 | import java.util.Arrays; | 7 | import java.util.Arrays; |
| 8 | import java.util.Optional; | 8 | import java.util.Optional; |
| @@ -12,11 +12,14 @@ import java.util.stream.Stream; | @@ -12,11 +12,14 @@ import java.util.stream.Stream; | ||
| 12 | * 支付方式 | 12 | * 支付方式 |
| 13 | */ | 13 | */ |
| 14 | public enum PaymentType implements IEnumType { | 14 | public enum PaymentType implements IEnumType { |
| 15 | - NATIVE("扫码支付", 1), // 客户扫商户收款码 | ||
| 16 | - | ||
| 17 | - QRCODE("付款码支付", 2), // 商户扫客户付款码 | ||
| 18 | - | ||
| 19 | - MINI_PRO("小程序支付", 3); // 目前特指微信小程序支付 | 15 | + // 直接支付, 使用PaymentPipeline.sendPaymentRequest |
| 16 | + DIRECT("直接支付", 0), | ||
| 17 | + // 客户扫商户收款码, 使用PaymentPipeline.sendNativePrepayRequest | ||
| 18 | + NATIVE("扫码支付", 1), | ||
| 19 | + // 商户扫客户付款码, 使用PaymentPipeline.sendQrCodePaymentRequest | ||
| 20 | + QRCODE("付款码支付", 2), | ||
| 21 | + // 目前特指微信小程序支付, 使用PaymentPipeline.sendMiniProPrepayRequest | ||
| 22 | + MINI_PRO("小程序支付", 3); | ||
| 20 | 23 | ||
| 21 | private final String name; | 24 | private final String name; |
| 22 | private final int code; | 25 | private final int code; |
| @@ -36,7 +39,7 @@ public enum PaymentType implements IEnumType { | @@ -36,7 +39,7 @@ public enum PaymentType implements IEnumType { | ||
| 36 | } | 39 | } |
| 37 | 40 | ||
| 38 | public static PaymentType getByCode(int code) { | 41 | public static PaymentType getByCode(int code) { |
| 39 | - return getType(code).orElseThrow(() -> new TradePaymentException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "系统不支持此类支付方式")); | 42 | + return getType(code).orElseThrow(() -> new PlatformServiceException(ErrorCode.ILLEGAL_ARGUMENT_ERROR, "系统不支持此类支付方式")); |
| 40 | } | 43 | } |
| 41 | 44 | ||
| 42 | public static String getName(int code) { | 45 | public static String getName(int code) { |
cashier-shared/src/main/java/com/diligrp/cashier/shared/SharedConfiguration.java
| @@ -15,11 +15,14 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; | @@ -15,11 +15,14 @@ import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
| 15 | import org.springframework.data.redis.core.RedisTemplate; | 15 | import org.springframework.data.redis.core.RedisTemplate; |
| 16 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; | 16 | import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; |
| 17 | import org.springframework.data.redis.serializer.StringRedisSerializer; | 17 | import org.springframework.data.redis.serializer.StringRedisSerializer; |
| 18 | +import org.springframework.lang.NonNull; | ||
| 18 | import org.springframework.stereotype.Component; | 19 | import org.springframework.stereotype.Component; |
| 19 | import org.springframework.util.StringUtils; | 20 | import org.springframework.util.StringUtils; |
| 20 | import org.springframework.web.servlet.config.annotation.CorsRegistry; | 21 | import org.springframework.web.servlet.config.annotation.CorsRegistry; |
| 21 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; | 22 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
| 22 | 23 | ||
| 24 | +import javax.crypto.spec.SecretKeySpec; | ||
| 25 | +import java.nio.charset.StandardCharsets; | ||
| 23 | import java.security.PrivateKey; | 26 | import java.security.PrivateKey; |
| 24 | import java.security.PublicKey; | 27 | import java.security.PublicKey; |
| 25 | import java.text.SimpleDateFormat; | 28 | import java.text.SimpleDateFormat; |
| @@ -36,7 +39,7 @@ public class SharedConfiguration { | @@ -36,7 +39,7 @@ public class SharedConfiguration { | ||
| 36 | public WebMvcConfigurer corsConfigurer() { | 39 | public WebMvcConfigurer corsConfigurer() { |
| 37 | return new WebMvcConfigurer() { | 40 | return new WebMvcConfigurer() { |
| 38 | @Override | 41 | @Override |
| 39 | - public void addCorsMappings(CorsRegistry registry) { | 42 | + public void addCorsMappings(@NonNull CorsRegistry registry) { |
| 40 | registry.addMapping("/**") | 43 | registry.addMapping("/**") |
| 41 | .allowedOriginPatterns("*") | 44 | .allowedOriginPatterns("*") |
| 42 | .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") | 45 | .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") |
| @@ -71,7 +74,7 @@ public class SharedConfiguration { | @@ -71,7 +74,7 @@ public class SharedConfiguration { | ||
| 71 | // 不能使用lambda表达式,否则导致springboot启动问题 | 74 | // 不能使用lambda表达式,否则导致springboot启动问题 |
| 72 | return new Converter<String, LocalDateTime>() { | 75 | return new Converter<String, LocalDateTime>() { |
| 73 | @Override | 76 | @Override |
| 74 | - public LocalDateTime convert(String source) { | 77 | + public LocalDateTime convert(@NonNull String source) { |
| 75 | try { | 78 | try { |
| 76 | return StringUtils.hasText(source) ? LocalDateTime.parse(source, DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT)) : null; | 79 | return StringUtils.hasText(source) ? LocalDateTime.parse(source, DateTimeFormatter.ofPattern(Constants.DATE_TIME_FORMAT)) : null; |
| 77 | } catch (Exception ex) { | 80 | } catch (Exception ex) { |
| @@ -86,7 +89,7 @@ public class SharedConfiguration { | @@ -86,7 +89,7 @@ public class SharedConfiguration { | ||
| 86 | // 不能使用lambda表达式,否则导致springboot启动问题 | 89 | // 不能使用lambda表达式,否则导致springboot启动问题 |
| 87 | return new Converter<String, LocalDate>() { | 90 | return new Converter<String, LocalDate>() { |
| 88 | @Override | 91 | @Override |
| 89 | - public LocalDate convert(String source) { | 92 | + public LocalDate convert(@NonNull String source) { |
| 90 | try { | 93 | try { |
| 91 | return StringUtils.hasText(source) ? LocalDate.parse(source, DateTimeFormatter.ofPattern(Constants.DATE_FORMAT)) : null; | 94 | return StringUtils.hasText(source) ? LocalDate.parse(source, DateTimeFormatter.ofPattern(Constants.DATE_FORMAT)) : null; |
| 92 | } catch (Exception ex) { | 95 | } catch (Exception ex) { |
| @@ -101,7 +104,7 @@ public class SharedConfiguration { | @@ -101,7 +104,7 @@ public class SharedConfiguration { | ||
| 101 | // 不能使用lambda表达式,否则导致springboot启动问题 | 104 | // 不能使用lambda表达式,否则导致springboot启动问题 |
| 102 | return new Converter<String, LocalTime>() { | 105 | return new Converter<String, LocalTime>() { |
| 103 | @Override | 106 | @Override |
| 104 | - public LocalTime convert(String source) { | 107 | + public LocalTime convert(@NonNull String source) { |
| 105 | try { | 108 | try { |
| 106 | return StringUtils.hasText(source) ? LocalTime.parse(source, DateTimeFormatter.ofPattern(Constants.TIME_FORMAT)) : null; | 109 | return StringUtils.hasText(source) ? LocalTime.parse(source, DateTimeFormatter.ofPattern(Constants.TIME_FORMAT)) : null; |
| 107 | } catch (Exception ex) { | 110 | } catch (Exception ex) { |
| @@ -116,7 +119,7 @@ public class SharedConfiguration { | @@ -116,7 +119,7 @@ public class SharedConfiguration { | ||
| 116 | // 不能使用lambda表达式,否则导致springboot启动问题 | 119 | // 不能使用lambda表达式,否则导致springboot启动问题 |
| 117 | return new Converter<String, Date>() { | 120 | return new Converter<String, Date>() { |
| 118 | @Override | 121 | @Override |
| 119 | - public Date convert(String source) { | 122 | + public Date convert(@NonNull String source) { |
| 120 | try { | 123 | try { |
| 121 | return StringUtils.hasText(source) ? new SimpleDateFormat(Constants.DATE_TIME_FORMAT).parse(source) : null; | 124 | return StringUtils.hasText(source) ? new SimpleDateFormat(Constants.DATE_TIME_FORMAT).parse(source) : null; |
| 122 | } catch (Exception ex) { | 125 | } catch (Exception ex) { |
| @@ -128,9 +131,9 @@ public class SharedConfiguration { | @@ -128,9 +131,9 @@ public class SharedConfiguration { | ||
| 128 | 131 | ||
| 129 | @Component | 132 | @Component |
| 130 | @ConfigurationPropertiesBinding | 133 | @ConfigurationPropertiesBinding |
| 131 | - public class PrivateKeyConverter implements Converter<String, PrivateKey> { | 134 | + public static class PrivateKeyConverter implements Converter<String, PrivateKey> { |
| 132 | @Override | 135 | @Override |
| 133 | - public PrivateKey convert(String source) { | 136 | + public PrivateKey convert(@NonNull String source) { |
| 134 | try { | 137 | try { |
| 135 | return RsaCipher.getPrivateKey(source); | 138 | return RsaCipher.getPrivateKey(source); |
| 136 | } catch (Exception ex) { | 139 | } catch (Exception ex) { |
| @@ -141,9 +144,9 @@ public class SharedConfiguration { | @@ -141,9 +144,9 @@ public class SharedConfiguration { | ||
| 141 | 144 | ||
| 142 | @Component | 145 | @Component |
| 143 | @ConfigurationPropertiesBinding | 146 | @ConfigurationPropertiesBinding |
| 144 | - public class PublicKeyConverter implements Converter<String, PublicKey> { | 147 | + public static class PublicKeyConverter implements Converter<String, PublicKey> { |
| 145 | @Override | 148 | @Override |
| 146 | - public PublicKey convert(String source) { | 149 | + public PublicKey convert(@NonNull String source) { |
| 147 | try { | 150 | try { |
| 148 | return RsaCipher.getPublicKey(source); | 151 | return RsaCipher.getPublicKey(source); |
| 149 | } catch (Exception ex) { | 152 | } catch (Exception ex) { |
| @@ -151,4 +154,13 @@ public class SharedConfiguration { | @@ -151,4 +154,13 @@ public class SharedConfiguration { | ||
| 151 | } | 154 | } |
| 152 | } | 155 | } |
| 153 | } | 156 | } |
| 157 | + | ||
| 158 | + @Component | ||
| 159 | + @ConfigurationPropertiesBinding | ||
| 160 | + public static class SecretKeyConverter implements Converter<String, SecretKeySpec> { | ||
| 161 | + @Override | ||
| 162 | + public SecretKeySpec convert(@NonNull String source) { | ||
| 163 | + return new SecretKeySpec(source.getBytes(StandardCharsets.UTF_8), "HmacSHA256"); | ||
| 164 | + } | ||
| 165 | + } | ||
| 154 | } | 166 | } |
| 155 | \ No newline at end of file | 167 | \ No newline at end of file |
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/ByteCodec.java
0 → 100644
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/ByteDecoder.java deleted
100644 → 0
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/ByteEncoder.java deleted
100644 → 0
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/IConverter.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.codec; | ||
| 2 | + | ||
| 3 | +import java.util.Objects; | ||
| 4 | + | ||
| 5 | +@FunctionalInterface | ||
| 6 | +public interface IConverter<T, R> { | ||
| 7 | + R convert(T t); | ||
| 8 | + | ||
| 9 | + default <V> IConverter<T, V> andThen(IConverter<? super R, ? extends V> after) { | ||
| 10 | + Objects.requireNonNull(after); | ||
| 11 | + return (T t) -> after.convert(convert(t)); | ||
| 12 | + } | ||
| 13 | +} |
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/JsonCodec.java
0 → 100644
cashier-shared/src/main/java/com/diligrp/cashier/shared/codec/StringCodec.java
| @@ -2,32 +2,17 @@ package com.diligrp.cashier.shared.codec; | @@ -2,32 +2,17 @@ package com.diligrp.cashier.shared.codec; | ||
| 2 | 2 | ||
| 3 | import java.nio.charset.StandardCharsets; | 3 | import java.nio.charset.StandardCharsets; |
| 4 | 4 | ||
| 5 | -public final class StringCodec { | ||
| 6 | - public static ByteEncoder<String> getEncoder() { | ||
| 7 | - return StringEncoder.INSTANCE; | ||
| 8 | - } | ||
| 9 | - | ||
| 10 | - public static ByteDecoder<String> getDecoder() { | ||
| 11 | - return StringDecoder.INSTANCE; | ||
| 12 | - } | 5 | +public final class StringCodec implements ByteCodec<String> { |
| 13 | 6 | ||
| 14 | - static class StringEncoder implements ByteEncoder<String> { | 7 | + public static ByteCodec<String> INSTANCE = new StringCodec(); |
| 15 | 8 | ||
| 16 | - static final ByteEncoder<String> INSTANCE = new StringEncoder(); | ||
| 17 | - | ||
| 18 | - @Override | ||
| 19 | - public byte[] encode(String payload) { | ||
| 20 | - return payload.getBytes(StandardCharsets.UTF_8); | ||
| 21 | - } | 9 | + @Override |
| 10 | + public String decode(byte[] payload) { | ||
| 11 | + return new String(payload, StandardCharsets.UTF_8); | ||
| 22 | } | 12 | } |
| 23 | 13 | ||
| 24 | - static class StringDecoder implements ByteDecoder<String> { | ||
| 25 | - | ||
| 26 | - static final ByteDecoder<String> INSTANCE = new StringDecoder(); | ||
| 27 | - | ||
| 28 | - @Override | ||
| 29 | - public String decode(byte[] payload) { | ||
| 30 | - return new String(payload, StandardCharsets.UTF_8); | ||
| 31 | - } | 14 | + @Override |
| 15 | + public byte[] encode(String payload) { | ||
| 16 | + return payload.getBytes(StandardCharsets.UTF_8); | ||
| 32 | } | 17 | } |
| 33 | } | 18 | } |
cashier-shared/src/main/java/com/diligrp/cashier/shared/security/Base62Cipher.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.security; | ||
| 2 | + | ||
| 3 | +public final class Base62Cipher { | ||
| 4 | + | ||
| 5 | + private static final char[] BASE62_CHARS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); | ||
| 6 | + | ||
| 7 | + private static final int BASE = 62; | ||
| 8 | + | ||
| 9 | + public static String encodeLong(long data) { | ||
| 10 | + if (data < 0) { | ||
| 11 | + throw new IllegalArgumentException("cannot be negative"); | ||
| 12 | + } | ||
| 13 | + | ||
| 14 | + if (data == 0) { | ||
| 15 | + return String.valueOf(BASE62_CHARS[0]); | ||
| 16 | + } | ||
| 17 | + | ||
| 18 | + StringBuilder sb = new StringBuilder(); | ||
| 19 | + while (data > 0) { | ||
| 20 | + int remainder = (int) (data % BASE); | ||
| 21 | + sb.append(BASE62_CHARS[remainder]); | ||
| 22 | + data = data / BASE; | ||
| 23 | + } | ||
| 24 | + | ||
| 25 | + // 反转字符串(因为取余是从低位到高位,需要反转恢复顺序) | ||
| 26 | + return sb.reverse().toString(); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public static long decodeLong(String payload) { | ||
| 30 | + if (payload == null || payload.isEmpty()) { | ||
| 31 | + throw new IllegalArgumentException("Invalid base62 data"); | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + long result = 0; | ||
| 35 | + for (char c : payload.toCharArray()) { | ||
| 36 | + if (result > (Long.MAX_VALUE - getCharIndex(c)) / BASE) { | ||
| 37 | + throw new NumberFormatException("Invalid base62 data: overflow long"); | ||
| 38 | + } | ||
| 39 | + result = result * BASE + getCharIndex(c); | ||
| 40 | + } | ||
| 41 | + return result; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + private static int getCharIndex(char c) { | ||
| 45 | + if (c >= '0' && c <= '9') { | ||
| 46 | + return c - '0'; | ||
| 47 | + } else if (c >= 'a' && c <= 'z') { | ||
| 48 | + return 10 + (c - 'a'); | ||
| 49 | + } else if (c >= 'A' && c <= 'Z') { | ||
| 50 | + return 36 + (c - 'A'); | ||
| 51 | + } else { | ||
| 52 | + throw new IllegalArgumentException("invalid base62 data:" + c); | ||
| 53 | + } | ||
| 54 | + } | ||
| 55 | +} |
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/IPaymentEventListener.java
0 → 100644
cashier-shared/src/main/java/com/diligrp/cashier/shared/spi/PaymentEvent.java
0 → 100644
| 1 | +package com.diligrp.cashier.shared.spi; | ||
| 2 | + | ||
| 3 | +import java.time.LocalDateTime; | ||
| 4 | + | ||
| 5 | +public class PaymentEvent { | ||
| 6 | + // 支付ID | ||
| 7 | + private final String tradeId; | ||
| 8 | + // 支付状态 | ||
| 9 | + private final Integer state; | ||
| 10 | + // 业务系统订单号 | ||
| 11 | + private final String outTradeNo; | ||
| 12 | + // 实际支付方式 | ||
| 13 | + private final Integer outPayType; | ||
| 14 | + // 支付人信息 | ||
| 15 | + private final String payerId; | ||
| 16 | + // 发生时间 | ||
| 17 | + private final LocalDateTime when; | ||
| 18 | + // 交易描述 | ||
| 19 | + private final String message; | ||
| 20 | + | ||
| 21 | + public PaymentEvent(String tradeId, int state, String outTradeNo, Integer outPayType, String payerId, LocalDateTime when, String message) { | ||
| 22 | + this.tradeId = tradeId; | ||
| 23 | + this.state = state; | ||
| 24 | + this.outTradeNo = outTradeNo; | ||
| 25 | + this.outPayType = outPayType; | ||
| 26 | + this.payerId = payerId; | ||
| 27 | + this.when = when; | ||
| 28 | + this.message = message; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public String getTradeId() { | ||
| 32 | + return tradeId; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public Integer getState() { | ||
| 36 | + return state; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public String getOutTradeNo() { | ||
| 40 | + return outTradeNo; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public Integer getOutPayType() { | ||
| 44 | + return outPayType; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public String getPayerId() { | ||
| 48 | + return payerId; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + public LocalDateTime getWhen() { | ||
| 52 | + return when; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public String getMessage() { | ||
| 56 | + return message; | ||
| 57 | + } | ||
| 58 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/Constants.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade; | ||
| 2 | + | ||
| 3 | +public final class Constants { | ||
| 4 | + | ||
| 5 | + // 默认订单超时时间-秒, 十分钟 | ||
| 6 | + public static final int DEFAULT_ORDER_TIMEOUT_SECONDS = 10 * 60 * 1000; | ||
| 7 | + | ||
| 8 | + // 最小订单超时时间-秒, 一分钟 | ||
| 9 | + public static final int MIN_ORDER_TIMEOUT_SECONDS = 60 * 1000; | ||
| 10 | + | ||
| 11 | + // 支付订单分布式锁 | ||
| 12 | + public static final String TRADE_LOCK_REDIS_KEY = "cashier:lock:trade:%s"; | ||
| 13 | + | ||
| 14 | + // 支付订单分布式锁超时时长-秒 | ||
| 15 | + public static final int TRADE_LOCK_TIMEOUT_SECONDS = 15 * 1000; | ||
| 16 | + | ||
| 17 | + // 微信支付openId参数 | ||
| 18 | + private static final String PARAM_OPEN_ID = "openId"; | ||
| 19 | + | ||
| 20 | + // 微信服务商模式下mchId子商户号参数 | ||
| 21 | + public static final String PARAM_MCH_ID = "mchId"; | ||
| 22 | + | ||
| 23 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/TradeConfiguration.java
| 1 | package com.diligrp.cashier.trade; | 1 | package com.diligrp.cashier.trade; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.shared.mybatis.MybatisMapperSupport; | ||
| 4 | +import org.mybatis.spring.annotation.MapperScan; | ||
| 3 | import org.springframework.context.annotation.ComponentScan; | 5 | import org.springframework.context.annotation.ComponentScan; |
| 4 | import org.springframework.context.annotation.Configuration; | 6 | import org.springframework.context.annotation.Configuration; |
| 5 | 7 | ||
| 6 | @Configuration | 8 | @Configuration |
| 7 | @ComponentScan("com.diligrp.cashier.trade") | 9 | @ComponentScan("com.diligrp.cashier.trade") |
| 10 | +@MapperScan(basePackages = {"com.diligrp.cashier.trade.dao"}, markerInterface = MybatisMapperSupport.class) | ||
| 8 | public class TradeConfiguration { | 11 | public class TradeConfiguration { |
| 9 | } | 12 | } |
cashier-trade/src/main/java/com/diligrp/cashier/trade/dao/IOnlinePaymentDao.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.dao; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.mybatis.MybatisMapperSupport; | ||
| 4 | +import com.diligrp.cashier.trade.domain.PaymentStateDTO; | ||
| 5 | +import com.diligrp.cashier.trade.model.OnlinePayment; | ||
| 6 | +import org.apache.ibatis.annotations.Param; | ||
| 7 | +import org.springframework.stereotype.Repository; | ||
| 8 | + | ||
| 9 | +import java.util.List; | ||
| 10 | +import java.util.Optional; | ||
| 11 | + | ||
| 12 | +/** | ||
| 13 | + * 支付申请数据访问层 | ||
| 14 | + */ | ||
| 15 | +@Repository("onlinePaymentDao") | ||
| 16 | +public interface IOnlinePaymentDao extends MybatisMapperSupport { | ||
| 17 | + | ||
| 18 | + void insertOnlinePayment(OnlinePayment payment); | ||
| 19 | + | ||
| 20 | + Optional<OnlinePayment> findByPaymentId(String paymentId); | ||
| 21 | + | ||
| 22 | + int compareAndSetState(PaymentStateDTO paymentDTO); | ||
| 23 | + | ||
| 24 | + List<OnlinePayment> findByTradeId(@Param("tradeId") String tradeId, @Param("state") Integer state); | ||
| 25 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/dao/ITradeOrderDao.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.dao; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.mybatis.MybatisMapperSupport; | ||
| 4 | +import com.diligrp.cashier.trade.domain.TradeStateDTO; | ||
| 5 | +import com.diligrp.cashier.trade.model.TradeOrder; | ||
| 6 | +import org.apache.ibatis.annotations.Param; | ||
| 7 | +import org.springframework.stereotype.Repository; | ||
| 8 | + | ||
| 9 | +import java.util.Optional; | ||
| 10 | + | ||
| 11 | +/** | ||
| 12 | + * 交易订单数据访问层 | ||
| 13 | + */ | ||
| 14 | +@Repository("tradeOrderDao") | ||
| 15 | +public interface ITradeOrderDao extends MybatisMapperSupport { | ||
| 16 | + void insertTradeOrder(TradeOrder tradeOrder); | ||
| 17 | + | ||
| 18 | + Optional<TradeOrder> findByTradeId(String tradeId); | ||
| 19 | + | ||
| 20 | + Optional<TradeOrder> findByOutTradeNo(@Param("mchId") Long mchId, @Param("outTradeNo") String outTradeNo); | ||
| 21 | + | ||
| 22 | + int compareAndSetState(TradeStateDTO tradeState); | ||
| 23 | +} | ||
| 0 | \ No newline at end of file | 24 | \ No newline at end of file |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/CashierOrder.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.domain; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.type.CashierType; | ||
| 4 | + | ||
| 5 | +public class CashierOrder { | ||
| 6 | + // 业务系统用户标识 | ||
| 7 | + private String userId; | ||
| 8 | + // 收银台类型 - H5收银台等 | ||
| 9 | + private CashierType type; | ||
| 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 description; | ||
| 22 | + // 附加数据 | ||
| 23 | + private String attach; | ||
| 24 | + | ||
| 25 | + public String getUserId() { | ||
| 26 | + return userId; | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + public void setUserId(String userId) { | ||
| 30 | + this.userId = userId; | ||
| 31 | + } | ||
| 32 | + | ||
| 33 | + public CashierType getType() { | ||
| 34 | + return type; | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + public void setType(CashierType type) { | ||
| 38 | + this.type = type; | ||
| 39 | + } | ||
| 40 | + | ||
| 41 | + public String getGoods() { | ||
| 42 | + return goods; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public void setGoods(String goods) { | ||
| 46 | + this.goods = goods; | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public Long getAmount() { | ||
| 50 | + return amount; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public void setAmount(Long amount) { | ||
| 54 | + this.amount = amount; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public Integer getTimeout() { | ||
| 58 | + return timeout; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public void setTimeout(Integer timeout) { | ||
| 62 | + this.timeout = timeout; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + public String getOutTradeNo() { | ||
| 66 | + return outTradeNo; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + public void setOutTradeNo(String outTradeNo) { | ||
| 70 | + this.outTradeNo = outTradeNo; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public String getNotifyUrl() { | ||
| 74 | + return notifyUrl; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + public void setNotifyUrl(String notifyUrl) { | ||
| 78 | + this.notifyUrl = notifyUrl; | ||
| 79 | + } | ||
| 80 | + | ||
| 81 | + public String getDescription() { | ||
| 82 | + return description; | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + public void setDescription(String description) { | ||
| 86 | + this.description = description; | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + public String getAttach() { | ||
| 90 | + return attach; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + public void setAttach(String attach) { | ||
| 94 | + this.attach = attach; | ||
| 95 | + } | ||
| 96 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/CashierPayment.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.domain; | ||
| 2 | + | ||
| 3 | +import java.util.Map; | ||
| 4 | + | ||
| 5 | +public class CashierPayment { | ||
| 6 | + // 支付号 | ||
| 7 | + private String tradeId; | ||
| 8 | + // 选择的支付通道 | ||
| 9 | + private Long pipelineId; | ||
| 10 | + // 用户标识 | ||
| 11 | + private Long userId; | ||
| 12 | + // 支付参数 | ||
| 13 | + private Map<String, Object> params; | ||
| 14 | + | ||
| 15 | + public String getTradeId() { | ||
| 16 | + return tradeId; | ||
| 17 | + } | ||
| 18 | + | ||
| 19 | + public void setTradeId(String tradeId) { | ||
| 20 | + this.tradeId = tradeId; | ||
| 21 | + } | ||
| 22 | + | ||
| 23 | + public Long getPipelineId() { | ||
| 24 | + return pipelineId; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public void setPipelineId(Long pipelineId) { | ||
| 28 | + this.pipelineId = pipelineId; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public Long getUserId() { | ||
| 32 | + return userId; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public void setUserId(Long userId) { | ||
| 36 | + this.userId = userId; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public Map<String, Object> getParams() { | ||
| 40 | + return params; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public void setParams(Map<String, Object> params) { | ||
| 44 | + this.params = params; | ||
| 45 | + } | ||
| 46 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/Merchant.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.domain; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 4 | + | ||
| 5 | +public class Merchant { | ||
| 6 | + // 商户号 | ||
| 7 | + private Long mchId; | ||
| 8 | + // 商户名称 | ||
| 9 | + private String name; | ||
| 10 | + // 商户参数 | ||
| 11 | + private MerchantParams params; | ||
| 12 | + | ||
| 13 | + public static Merchant of(Long mchId, String name, MerchantParams params) { | ||
| 14 | + Merchant merchant = new Merchant(); | ||
| 15 | + merchant.mchId = mchId; | ||
| 16 | + merchant.name = name; | ||
| 17 | + merchant.params = params; | ||
| 18 | + return merchant; | ||
| 19 | + } | ||
| 20 | + | ||
| 21 | + public static Merchant decode(String payload) { | ||
| 22 | + if (payload != null) { | ||
| 23 | + return JsonUtils.fromJsonString(payload, Merchant.class); | ||
| 24 | + } | ||
| 25 | + return null; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + public Long getMchId() { | ||
| 29 | + return mchId; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + public void setMchId(Long mchId) { | ||
| 33 | + this.mchId = mchId; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + public String getName() { | ||
| 37 | + return name; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public void setName(String name) { | ||
| 41 | + this.name = name; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public MerchantParams getParams() { | ||
| 45 | + return params; | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + public void setParams(MerchantParams params) { | ||
| 49 | + this.params = params; | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + @Override | ||
| 53 | + public String toString() { | ||
| 54 | + return JsonUtils.toJsonString(this); | ||
| 55 | + } | ||
| 56 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/MerchantParams.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.domain; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 4 | + | ||
| 5 | +import java.util.Objects; | ||
| 6 | + | ||
| 7 | +public class MerchantParams { | ||
| 8 | + // 收银台配置 | ||
| 9 | + private CashierParams cashier; | ||
| 10 | + // TODO: 支付结果页面-跳转大润发使用 | ||
| 11 | + | ||
| 12 | + public static MerchantParams decode(String params) { | ||
| 13 | + return JsonUtils.fromJsonString(params, MerchantParams.class); | ||
| 14 | + } | ||
| 15 | + | ||
| 16 | + public CashierParams getCashier() { | ||
| 17 | + return cashier; | ||
| 18 | + } | ||
| 19 | + | ||
| 20 | + public void setCashier(CashierParams cashier) { | ||
| 21 | + this.cashier = cashier; | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + public static class CashierParams { | ||
| 25 | + // PC收银台地址 | ||
| 26 | + private String pcUrl; | ||
| 27 | + // 小程序收银台地址 | ||
| 28 | + private String miniProUrl; | ||
| 29 | + // H5收银台地址 | ||
| 30 | + private String h5Url; | ||
| 31 | + // 小程序收银台地址 | ||
| 32 | + private String appUrl; | ||
| 33 | + | ||
| 34 | + public void override(CashierParams params) { | ||
| 35 | + if (Objects.isNull(this.pcUrl)) { | ||
| 36 | + this.pcUrl = params.getPcUrl(); | ||
| 37 | + } | ||
| 38 | + if (Objects.isNull(this.miniProUrl)) { | ||
| 39 | + this.miniProUrl = params.getMiniProUrl(); | ||
| 40 | + } | ||
| 41 | + if (Objects.isNull(this.h5Url)) { | ||
| 42 | + this.h5Url = params.getH5Url(); | ||
| 43 | + } | ||
| 44 | + if (Objects.isNull(this.appUrl)) { | ||
| 45 | + this.appUrl = params.getAppUrl(); | ||
| 46 | + } | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + public String getPcUrl() { | ||
| 50 | + return pcUrl; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + public void setPcUrl(String pcUrl) { | ||
| 54 | + this.pcUrl = pcUrl; | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public String getMiniProUrl() { | ||
| 58 | + return miniProUrl; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public void setMiniProUrl(String miniProUrl) { | ||
| 62 | + this.miniProUrl = miniProUrl; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + public String getH5Url() { | ||
| 66 | + return h5Url; | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + public void setH5Url(String h5Url) { | ||
| 70 | + this.h5Url = h5Url; | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + public String getAppUrl() { | ||
| 74 | + return appUrl; | ||
| 75 | + } | ||
| 76 | + | ||
| 77 | + public void setAppUrl(String appUrl) { | ||
| 78 | + this.appUrl = appUrl; | ||
| 79 | + } | ||
| 80 | + } | ||
| 81 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/PaymentStateDTO.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.domain; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.type.OutPaymentType; | ||
| 4 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 5 | + | ||
| 6 | +import java.time.LocalDateTime; | ||
| 7 | + | ||
| 8 | +/** | ||
| 9 | + * 支付订单状态处理模型 | ||
| 10 | + */ | ||
| 11 | +public class PaymentStateDTO { | ||
| 12 | + // 支付ID | ||
| 13 | + private String paymentId; | ||
| 14 | + // 通道流水号 | ||
| 15 | + private String outTradeNo; | ||
| 16 | + // 实际支付方式 | ||
| 17 | + private Integer outPayType; | ||
| 18 | + // 支付方ID - 如:微信的openId | ||
| 19 | + private String payerId; | ||
| 20 | + // 支付时间 | ||
| 21 | + private LocalDateTime finishTime; | ||
| 22 | + // 订单状态 | ||
| 23 | + private Integer state; | ||
| 24 | + // 交易描述 | ||
| 25 | + private String description; | ||
| 26 | + // 数据版本 | ||
| 27 | + private Integer version; | ||
| 28 | + // 修改时间 | ||
| 29 | + private LocalDateTime modifiedTime; | ||
| 30 | + | ||
| 31 | + public String getPaymentId() { | ||
| 32 | + return paymentId; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public void setPaymentId(String paymentId) { | ||
| 36 | + this.paymentId = paymentId; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + public String getOutTradeNo() { | ||
| 40 | + return outTradeNo; | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public void setOutTradeNo(String outTradeNo) { | ||
| 44 | + this.outTradeNo = outTradeNo; | ||
| 45 | + } | ||
| 46 | + | ||
| 47 | + public Integer getOutPayType() { | ||
| 48 | + return outPayType; | ||
| 49 | + } | ||
| 50 | + | ||
| 51 | + public void setOutPayType(Integer outPayType) { | ||
| 52 | + this.outPayType = outPayType; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + public String getPayerId() { | ||
| 56 | + return payerId; | ||
| 57 | + } | ||
| 58 | + | ||
| 59 | + public void setPayerId(String payerId) { | ||
| 60 | + this.payerId = payerId; | ||
| 61 | + } | ||
| 62 | + | ||
| 63 | + public LocalDateTime getFinishTime() { | ||
| 64 | + return finishTime; | ||
| 65 | + } | ||
| 66 | + | ||
| 67 | + public void setFinishTime(LocalDateTime finishTime) { | ||
| 68 | + this.finishTime = finishTime; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + public Integer getState() { | ||
| 72 | + return state; | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + public void setState(Integer state) { | ||
| 76 | + this.state = state; | ||
| 77 | + } | ||
| 78 | + | ||
| 79 | + public String getDescription() { | ||
| 80 | + return description; | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + public void setDescription(String description) { | ||
| 84 | + this.description = description; | ||
| 85 | + } | ||
| 86 | + | ||
| 87 | + public Integer getVersion() { | ||
| 88 | + return version; | ||
| 89 | + } | ||
| 90 | + | ||
| 91 | + public void setVersion(Integer version) { | ||
| 92 | + this.version = version; | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + public LocalDateTime getModifiedTime() { | ||
| 96 | + return modifiedTime; | ||
| 97 | + } | ||
| 98 | + | ||
| 99 | + public void setModifiedTime(LocalDateTime modifiedTime) { | ||
| 100 | + this.modifiedTime = modifiedTime; | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + public static Builder builder() { | ||
| 104 | + return new PaymentStateDTO().new Builder(); | ||
| 105 | + } | ||
| 106 | + | ||
| 107 | + public class Builder { | ||
| 108 | + public Builder paymentId(String paymentId) { | ||
| 109 | + PaymentStateDTO.this.paymentId = paymentId; | ||
| 110 | + return this; | ||
| 111 | + } | ||
| 112 | + | ||
| 113 | + public Builder outTradeNo(String outTradeNo) { | ||
| 114 | + PaymentStateDTO.this.outTradeNo = outTradeNo; | ||
| 115 | + return this; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + public Builder outPayType(OutPaymentType outPayType) { | ||
| 119 | + PaymentStateDTO.this.outPayType = outPayType.getCode(); | ||
| 120 | + return this; | ||
| 121 | + } | ||
| 122 | + | ||
| 123 | + public Builder payerId(String payerId) { | ||
| 124 | + PaymentStateDTO.this.payerId = payerId; | ||
| 125 | + return this; | ||
| 126 | + } | ||
| 127 | + | ||
| 128 | + public Builder finishTime(LocalDateTime finishTime) { | ||
| 129 | + PaymentStateDTO.this.finishTime = finishTime; | ||
| 130 | + return this; | ||
| 131 | + } | ||
| 132 | + | ||
| 133 | + public Builder state(PaymentState state) { | ||
| 134 | + PaymentStateDTO.this.state = state.getCode(); | ||
| 135 | + return this; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + public Builder description(String description) { | ||
| 139 | + PaymentStateDTO.this.description = description; | ||
| 140 | + return this; | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + public Builder version(Integer version) { | ||
| 144 | + PaymentStateDTO.this.version = version; | ||
| 145 | + return this; | ||
| 146 | + } | ||
| 147 | + | ||
| 148 | + public Builder modifiedTime(LocalDateTime modifiedTime) { | ||
| 149 | + PaymentStateDTO.this.modifiedTime = modifiedTime; | ||
| 150 | + return this; | ||
| 151 | + } | ||
| 152 | + | ||
| 153 | + public PaymentStateDTO build() { | ||
| 154 | + return PaymentStateDTO.this; | ||
| 155 | + } | ||
| 156 | + } | ||
| 157 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/TradePaymentResult.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.domain; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.spi.PaymentEvent; | ||
| 4 | + | ||
| 5 | +import java.time.LocalDateTime; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 在线支付结果 - 用于业务系统支付结果通知 | ||
| 9 | + */ | ||
| 10 | +public class TradePaymentResult extends PaymentEvent { | ||
| 11 | + public TradePaymentResult(String tradeId, int state, String outTradeNo, Integer outPayType, String payerId, | ||
| 12 | + LocalDateTime when, String message) { | ||
| 13 | + super(tradeId, state, outTradeNo, outPayType, payerId, when, message); | ||
| 14 | + } | ||
| 15 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/domain/TradeStateDTO.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.domain; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.trade.type.TradeState; | ||
| 4 | + | ||
| 5 | +import java.time.LocalDateTime; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 交易状态数据传输对象 | ||
| 9 | + */ | ||
| 10 | +public class TradeStateDTO { | ||
| 11 | + // 交易ID | ||
| 12 | + private String tradeId; | ||
| 13 | + // 金额 | ||
| 14 | + private Long amount; | ||
| 15 | + // 状态 | ||
| 16 | + private Integer state; | ||
| 17 | + // 数据版本 | ||
| 18 | + private Integer version; | ||
| 19 | + // 修改时间 | ||
| 20 | + private LocalDateTime modifiedTime; | ||
| 21 | + | ||
| 22 | + public String getTradeId() { | ||
| 23 | + return tradeId; | ||
| 24 | + } | ||
| 25 | + | ||
| 26 | + public void setTradeId(String tradeId) { | ||
| 27 | + this.tradeId = tradeId; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + public Long getAmount() { | ||
| 31 | + return amount; | ||
| 32 | + } | ||
| 33 | + | ||
| 34 | + public void setAmount(Long amount) { | ||
| 35 | + this.amount = amount; | ||
| 36 | + } | ||
| 37 | + | ||
| 38 | + public Integer getState() { | ||
| 39 | + return state; | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + public void setState(Integer state) { | ||
| 43 | + this.state = state; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + public Integer getVersion() { | ||
| 47 | + return version; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + public void setVersion(Integer version) { | ||
| 51 | + this.version = version; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public LocalDateTime getModifiedTime() { | ||
| 55 | + return modifiedTime; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public void setModifiedTime(LocalDateTime modifiedTime) { | ||
| 59 | + this.modifiedTime = modifiedTime; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + public static TradeStateDTO of(String tradeId, TradeState state, Integer version, LocalDateTime modifiedTime) { | ||
| 63 | + return of(tradeId, null, state, version, modifiedTime); | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + public static TradeStateDTO of(String tradeId, Long amount, TradeState state, Integer version, LocalDateTime modifiedTime) { | ||
| 67 | + TradeStateDTO tradeStateDTO = new TradeStateDTO(); | ||
| 68 | + tradeStateDTO.tradeId = tradeId; | ||
| 69 | + tradeStateDTO.amount = amount; | ||
| 70 | + tradeStateDTO.state = state.getCode(); | ||
| 71 | + tradeStateDTO.version = version; | ||
| 72 | + tradeStateDTO.modifiedTime = modifiedTime; | ||
| 73 | + return tradeStateDTO; | ||
| 74 | + } | ||
| 75 | +} | ||
| 0 | \ No newline at end of file | 76 | \ No newline at end of file |
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/PaymentResultManager.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.manager; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.service.ServiceEndpointSupport; | ||
| 4 | +import com.diligrp.cashier.shared.service.ThreadPoolService; | ||
| 5 | +import com.diligrp.cashier.shared.spi.IPaymentEventListener; | ||
| 6 | +import com.diligrp.cashier.shared.util.JsonUtils; | ||
| 7 | +import com.diligrp.cashier.shared.util.ObjectUtils; | ||
| 8 | +import com.diligrp.cashier.trade.domain.TradePaymentResult; | ||
| 9 | +import jakarta.annotation.Resource; | ||
| 10 | +import org.slf4j.Logger; | ||
| 11 | +import org.slf4j.LoggerFactory; | ||
| 12 | +import org.springframework.beans.factory.ObjectProvider; | ||
| 13 | +import org.springframework.stereotype.Service; | ||
| 14 | + | ||
| 15 | +import java.util.List; | ||
| 16 | + | ||
| 17 | +@Service("paymentResultManager") | ||
| 18 | +public class PaymentResultManager { | ||
| 19 | + | ||
| 20 | + private static final Logger LOG = LoggerFactory.getLogger(PaymentResultManager.class); | ||
| 21 | + | ||
| 22 | + @Resource | ||
| 23 | + private ObjectProvider<IPaymentEventListener> eventListeners; | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 通知业务系统在线支付通道处理结果 | ||
| 27 | + */ | ||
| 28 | + public void notifyPaymentResult(String uri, TradePaymentResult payload) { | ||
| 29 | + ThreadPoolService.getIoThreadPoll().submit(() -> { | ||
| 30 | + List<IPaymentEventListener> lifeCycles = eventListeners.stream().toList(); | ||
| 31 | + for (IPaymentEventListener listener : lifeCycles) { | ||
| 32 | + try { | ||
| 33 | + listener.onEvent(payload); | ||
| 34 | + } catch (Exception ex) { | ||
| 35 | + LOG.error("Failed to notify trade payment result", ex); | ||
| 36 | + } | ||
| 37 | + } | ||
| 38 | + }); | ||
| 39 | + | ||
| 40 | + if (ObjectUtils.isEmpty(uri)) { | ||
| 41 | + return; | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + ThreadPoolService.getIoThreadPoll().submit(() -> { | ||
| 45 | + try { | ||
| 46 | + String body = JsonUtils.toJsonString(payload); | ||
| 47 | + LOG.info("Notifying online trade payment result: {}", body); | ||
| 48 | + ServiceEndpointSupport.HttpResult httpResult = new NotifyHttpClient(uri).send(body); | ||
| 49 | + if (httpResult.statusCode != 200) { | ||
| 50 | + LOG.error("Failed to notify trade payment result"); | ||
| 51 | + } | ||
| 52 | + } catch (Exception ex) { | ||
| 53 | + LOG.error("Failed to notify trade payment result", ex); | ||
| 54 | + } | ||
| 55 | + }); | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + private static class NotifyHttpClient extends ServiceEndpointSupport { | ||
| 59 | + private final String baseUrl; | ||
| 60 | + | ||
| 61 | + public NotifyHttpClient(String baseUrl) { | ||
| 62 | + this.baseUrl = baseUrl; | ||
| 63 | + } | ||
| 64 | + | ||
| 65 | + public HttpResult send(String body) { | ||
| 66 | + return send(baseUrl, body); | ||
| 67 | + } | ||
| 68 | + } | ||
| 69 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/model/OnlinePayment.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.model; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.type.ChannelType; | ||
| 4 | +import com.diligrp.cashier.pipeline.type.OutPaymentType; | ||
| 5 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 6 | +import com.diligrp.cashier.pipeline.type.PaymentType; | ||
| 7 | +import com.diligrp.cashier.shared.domain.BaseDO; | ||
| 8 | +import com.diligrp.cashier.trade.type.TradeType; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | + | ||
| 12 | +public class OnlinePayment extends BaseDO { | ||
| 13 | + // 外部商户号 | ||
| 14 | + private String outMchId; | ||
| 15 | + // 订单ID | ||
| 16 | + private String tradeId; | ||
| 17 | + // 交易类型 | ||
| 18 | + private Integer type; | ||
| 19 | + // 支付ID | ||
| 20 | + private String paymentId; | ||
| 21 | + // 支付通道 | ||
| 22 | + private Integer channelId; | ||
| 23 | + // 支付方式 | ||
| 24 | + private Integer payType; | ||
| 25 | + // 客户ID | ||
| 26 | + private Long pipelineId; | ||
| 27 | + // 微信商品描述 | ||
| 28 | + private String goods; | ||
| 29 | + // 申请金额-分 | ||
| 30 | + private Long amount; | ||
| 31 | + // 操作对象-比如:prepareId,二维码,或退款时的原单号 | ||
| 32 | + private String objectId; | ||
| 33 | + // 支付方-如微信openId | ||
| 34 | + private String payerId; | ||
| 35 | + // 支付时间 | ||
| 36 | + private LocalDateTime finishTime; | ||
| 37 | + // 通道流水号 | ||
| 38 | + private String outTradeNo; | ||
| 39 | + // 实际支付方式-聚合支付通道使用 | ||
| 40 | + private Integer outPayType; | ||
| 41 | + // 申请状态 | ||
| 42 | + private Integer state; | ||
| 43 | + // 备注 | ||
| 44 | + private String description; | ||
| 45 | + | ||
| 46 | + public String getOutMchId() { | ||
| 47 | + return outMchId; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + public void setOutMchId(String outMchId) { | ||
| 51 | + this.outMchId = outMchId; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public String getTradeId() { | ||
| 55 | + return tradeId; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public void setTradeId(String tradeId) { | ||
| 59 | + this.tradeId = tradeId; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + public Integer getType() { | ||
| 63 | + return type; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + public void setType(Integer type) { | ||
| 67 | + this.type = type; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + public String getPaymentId() { | ||
| 71 | + return paymentId; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + public void setPaymentId(String paymentId) { | ||
| 75 | + this.paymentId = paymentId; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + public Integer getChannelId() { | ||
| 79 | + return channelId; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + public void setChannelId(Integer channelId) { | ||
| 83 | + this.channelId = channelId; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + public Integer getPayType() { | ||
| 87 | + return payType; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + public void setPayType(Integer payType) { | ||
| 91 | + this.payType = payType; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + public Long getPipelineId() { | ||
| 95 | + return pipelineId; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + public void setPipelineId(Long pipelineId) { | ||
| 99 | + this.pipelineId = pipelineId; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + public String getGoods() { | ||
| 103 | + return goods; | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + public void setGoods(String goods) { | ||
| 107 | + this.goods = goods; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + public Long getAmount() { | ||
| 111 | + return amount; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + public void setAmount(Long amount) { | ||
| 115 | + this.amount = amount; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + public String getObjectId() { | ||
| 119 | + return objectId; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + public void setObjectId(String objectId) { | ||
| 123 | + this.objectId = objectId; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + public String getPayerId() { | ||
| 127 | + return payerId; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + public void setPayerId(String payerId) { | ||
| 131 | + this.payerId = payerId; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + public LocalDateTime getFinishTime() { | ||
| 135 | + return finishTime; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + public void setFinishTime(LocalDateTime finishTime) { | ||
| 139 | + this.finishTime = finishTime; | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + public String getOutTradeNo() { | ||
| 143 | + return outTradeNo; | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + public void setOutTradeNo(String outTradeNo) { | ||
| 147 | + this.outTradeNo = outTradeNo; | ||
| 148 | + } | ||
| 149 | + | ||
| 150 | + public Integer getOutPayType() { | ||
| 151 | + return outPayType; | ||
| 152 | + } | ||
| 153 | + | ||
| 154 | + public void setOutPayType(Integer outPayType) { | ||
| 155 | + this.outPayType = outPayType; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + public Integer getState() { | ||
| 159 | + return state; | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + public void setState(Integer state) { | ||
| 163 | + this.state = state; | ||
| 164 | + } | ||
| 165 | + | ||
| 166 | + public String getDescription() { | ||
| 167 | + return description; | ||
| 168 | + } | ||
| 169 | + | ||
| 170 | + public void setDescription(String description) { | ||
| 171 | + this.description = description; | ||
| 172 | + } | ||
| 173 | + | ||
| 174 | + public static Builder builder() { | ||
| 175 | + return new OnlinePayment().new Builder(); | ||
| 176 | + } | ||
| 177 | + | ||
| 178 | + public class Builder { | ||
| 179 | + public Builder outMchId(String outMchId) { | ||
| 180 | + OnlinePayment.this.outMchId = outMchId; | ||
| 181 | + return this; | ||
| 182 | + } | ||
| 183 | + | ||
| 184 | + public Builder tradeId(String tradeId) { | ||
| 185 | + OnlinePayment.this.tradeId = tradeId; | ||
| 186 | + return this; | ||
| 187 | + } | ||
| 188 | + | ||
| 189 | + public Builder type(TradeType type) { | ||
| 190 | + OnlinePayment.this.type = type.getCode(); | ||
| 191 | + return this; | ||
| 192 | + } | ||
| 193 | + | ||
| 194 | + public Builder paymentId(String paymentId) { | ||
| 195 | + OnlinePayment.this.paymentId = paymentId; | ||
| 196 | + return this; | ||
| 197 | + } | ||
| 198 | + | ||
| 199 | + public Builder channelId(ChannelType channelType) { | ||
| 200 | + OnlinePayment.this.channelId = channelType.getCode(); | ||
| 201 | + return this; | ||
| 202 | + } | ||
| 203 | + | ||
| 204 | + public Builder payType(PaymentType payType) { | ||
| 205 | + OnlinePayment.this.payType = payType.getCode(); | ||
| 206 | + return this; | ||
| 207 | + } | ||
| 208 | + | ||
| 209 | + public Builder pipelineId(Long pipelineId) { | ||
| 210 | + OnlinePayment.this.pipelineId = pipelineId; | ||
| 211 | + return this; | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + public Builder goods(String goods) { | ||
| 215 | + OnlinePayment.this.goods = goods; | ||
| 216 | + return this; | ||
| 217 | + } | ||
| 218 | + | ||
| 219 | + public Builder amount(Long amount) { | ||
| 220 | + OnlinePayment.this.amount = amount; | ||
| 221 | + return this; | ||
| 222 | + } | ||
| 223 | + | ||
| 224 | + public Builder objectId(String objectId) { | ||
| 225 | + OnlinePayment.this.objectId = objectId; | ||
| 226 | + return this; | ||
| 227 | + } | ||
| 228 | + | ||
| 229 | + public Builder payerId(String payerId) { | ||
| 230 | + OnlinePayment.this.payerId = payerId; | ||
| 231 | + return this; | ||
| 232 | + } | ||
| 233 | + | ||
| 234 | + public Builder finishTime(LocalDateTime payTime) { | ||
| 235 | + OnlinePayment.this.finishTime = payTime; | ||
| 236 | + return this; | ||
| 237 | + } | ||
| 238 | + | ||
| 239 | + public Builder outTradeNo(String outTradeNo) { | ||
| 240 | + OnlinePayment.this.outTradeNo = outTradeNo; | ||
| 241 | + return this; | ||
| 242 | + } | ||
| 243 | + | ||
| 244 | + public Builder outPayType(OutPaymentType outPayType) { | ||
| 245 | + OnlinePayment.this.outPayType = outPayType.getCode(); | ||
| 246 | + return this; | ||
| 247 | + } | ||
| 248 | + | ||
| 249 | + public Builder state(PaymentState state) { | ||
| 250 | + OnlinePayment.this.state = state.getCode(); | ||
| 251 | + return this; | ||
| 252 | + } | ||
| 253 | + | ||
| 254 | + public Builder description(String description) { | ||
| 255 | + OnlinePayment.this.description = description; | ||
| 256 | + return this; | ||
| 257 | + } | ||
| 258 | + | ||
| 259 | + public Builder version(Integer version) { | ||
| 260 | + OnlinePayment.this.version = version; | ||
| 261 | + return this; | ||
| 262 | + } | ||
| 263 | + | ||
| 264 | + public Builder createdTime(LocalDateTime createdTime) { | ||
| 265 | + OnlinePayment.this.createdTime = createdTime; | ||
| 266 | + return this; | ||
| 267 | + } | ||
| 268 | + | ||
| 269 | + public Builder modifiedTime(LocalDateTime modifiedTime) { | ||
| 270 | + OnlinePayment.this.modifiedTime = modifiedTime; | ||
| 271 | + return this; | ||
| 272 | + } | ||
| 273 | + | ||
| 274 | + public OnlinePayment build() { | ||
| 275 | + return OnlinePayment.this; | ||
| 276 | + } | ||
| 277 | + } | ||
| 278 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/model/TradeOrder.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.model; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.domain.BaseDO; | ||
| 4 | + | ||
| 5 | +import java.time.LocalDateTime; | ||
| 6 | + | ||
| 7 | +/** | ||
| 8 | + * 交易订单数据模型 | ||
| 9 | + */ | ||
| 10 | +public class TradeOrder extends BaseDO { | ||
| 11 | + // 商户ID | ||
| 12 | + private Long mchId; | ||
| 13 | + // 交易ID | ||
| 14 | + private String tradeId; | ||
| 15 | + // 交易类型 | ||
| 16 | + private Integer type; | ||
| 17 | + // 外部流水号 | ||
| 18 | + private String outTradeNo; | ||
| 19 | + // 金额-分 | ||
| 20 | + private Long amount; | ||
| 21 | + // 初始金额-分 | ||
| 22 | + private Long maxAmount; | ||
| 23 | + // 商品描述 | ||
| 24 | + private String goods; | ||
| 25 | + // 订单超时时间-秒 | ||
| 26 | + private Integer timeout; | ||
| 27 | + // 交易状态 | ||
| 28 | + private Integer state; | ||
| 29 | + // 业务回调地址 | ||
| 30 | + private String notifyUrl; | ||
| 31 | + // 交易备注 | ||
| 32 | + private String description; | ||
| 33 | + // 附加数据 | ||
| 34 | + private String attach; | ||
| 35 | + // 收银台来源 | ||
| 36 | + private Integer source; | ||
| 37 | + | ||
| 38 | + public Long getMchId() { | ||
| 39 | + return mchId; | ||
| 40 | + } | ||
| 41 | + | ||
| 42 | + public void setMchId(Long mchId) { | ||
| 43 | + this.mchId = mchId; | ||
| 44 | + } | ||
| 45 | + | ||
| 46 | + public String getTradeId() { | ||
| 47 | + return tradeId; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + public void setTradeId(String tradeId) { | ||
| 51 | + this.tradeId = tradeId; | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + public Integer getType() { | ||
| 55 | + return type; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + public void setType(Integer type) { | ||
| 59 | + this.type = type; | ||
| 60 | + } | ||
| 61 | + | ||
| 62 | + public String getOutTradeNo() { | ||
| 63 | + return outTradeNo; | ||
| 64 | + } | ||
| 65 | + | ||
| 66 | + public void setOutTradeNo(String outTradeNo) { | ||
| 67 | + this.outTradeNo = outTradeNo; | ||
| 68 | + } | ||
| 69 | + | ||
| 70 | + public Long getAmount() { | ||
| 71 | + return amount; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + public void setAmount(Long amount) { | ||
| 75 | + this.amount = amount; | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + public Long getMaxAmount() { | ||
| 79 | + return maxAmount; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + public void setMaxAmount(Long maxAmount) { | ||
| 83 | + this.maxAmount = maxAmount; | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + public String getGoods() { | ||
| 87 | + return goods; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + public void setGoods(String goods) { | ||
| 91 | + this.goods = goods; | ||
| 92 | + } | ||
| 93 | + | ||
| 94 | + public Integer getTimeout() { | ||
| 95 | + return timeout; | ||
| 96 | + } | ||
| 97 | + | ||
| 98 | + public void setTimeout(Integer timeout) { | ||
| 99 | + this.timeout = timeout; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + public Integer getState() { | ||
| 103 | + return state; | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + public void setState(Integer state) { | ||
| 107 | + this.state = state; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + public String getNotifyUrl() { | ||
| 111 | + return notifyUrl; | ||
| 112 | + } | ||
| 113 | + | ||
| 114 | + public void setNotifyUrl(String notifyUrl) { | ||
| 115 | + this.notifyUrl = notifyUrl; | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + public String getDescription() { | ||
| 119 | + return description; | ||
| 120 | + } | ||
| 121 | + | ||
| 122 | + public void setDescription(String description) { | ||
| 123 | + this.description = description; | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + public String getAttach() { | ||
| 127 | + return attach; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + public void setAttach(String attach) { | ||
| 131 | + this.attach = attach; | ||
| 132 | + } | ||
| 133 | + | ||
| 134 | + public Integer getSource() { | ||
| 135 | + return source; | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + public void setSource(Integer source) { | ||
| 139 | + this.source = source; | ||
| 140 | + } | ||
| 141 | + | ||
| 142 | + public static Builder builder() { | ||
| 143 | + return new TradeOrder().new Builder(); | ||
| 144 | + } | ||
| 145 | + | ||
| 146 | + public class Builder { | ||
| 147 | + public Builder mchId(Long mchId) { | ||
| 148 | + TradeOrder.this.mchId = mchId; | ||
| 149 | + return this; | ||
| 150 | + } | ||
| 151 | + | ||
| 152 | + public Builder tradeId(String tradeId) { | ||
| 153 | + TradeOrder.this.tradeId = tradeId; | ||
| 154 | + return this; | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + public Builder type(Integer type) { | ||
| 158 | + TradeOrder.this.type = type; | ||
| 159 | + return this; | ||
| 160 | + } | ||
| 161 | + | ||
| 162 | + public Builder outTradeNo(String outTradeNo) { | ||
| 163 | + TradeOrder.this.outTradeNo = outTradeNo; | ||
| 164 | + return this; | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + public Builder amount(Long amount) { | ||
| 168 | + TradeOrder.this.amount = amount; | ||
| 169 | + return this; | ||
| 170 | + } | ||
| 171 | + | ||
| 172 | + public Builder maxAmount(Long maxAmount) { | ||
| 173 | + TradeOrder.this.maxAmount = maxAmount; | ||
| 174 | + return this; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + public Builder goods(String goods) { | ||
| 178 | + TradeOrder.this.goods = goods; | ||
| 179 | + return this; | ||
| 180 | + } | ||
| 181 | + | ||
| 182 | + public Builder timeout(Integer timeout) { | ||
| 183 | + TradeOrder.this.timeout = timeout; | ||
| 184 | + return this; | ||
| 185 | + } | ||
| 186 | + | ||
| 187 | + public Builder state(Integer state) { | ||
| 188 | + TradeOrder.this.state = state; | ||
| 189 | + return this; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + public Builder notifyUrl(String notifyUrl) { | ||
| 193 | + TradeOrder.this.notifyUrl = notifyUrl; | ||
| 194 | + return this; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + public Builder description(String description) { | ||
| 198 | + TradeOrder.this.description = description; | ||
| 199 | + return this; | ||
| 200 | + } | ||
| 201 | + | ||
| 202 | + public Builder attach(String attach) { | ||
| 203 | + TradeOrder.this.attach = attach; | ||
| 204 | + return this; | ||
| 205 | + } | ||
| 206 | + | ||
| 207 | + public Builder source(Integer source) { | ||
| 208 | + TradeOrder.this.source = source; | ||
| 209 | + return this; | ||
| 210 | + } | ||
| 211 | + | ||
| 212 | + public Builder version(Integer version) { | ||
| 213 | + TradeOrder.this.version = version; | ||
| 214 | + return this; | ||
| 215 | + } | ||
| 216 | + | ||
| 217 | + public Builder createdTime(LocalDateTime createdTime) { | ||
| 218 | + TradeOrder.this.createdTime = createdTime; | ||
| 219 | + return this; | ||
| 220 | + } | ||
| 221 | + | ||
| 222 | + public Builder modifiedTime(LocalDateTime modifiedTime) { | ||
| 223 | + TradeOrder.this.modifiedTime = modifiedTime; | ||
| 224 | + return this; | ||
| 225 | + } | ||
| 226 | + | ||
| 227 | + public TradeOrder build() { | ||
| 228 | + return TradeOrder.this; | ||
| 229 | + } | ||
| 230 | + } | ||
| 231 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/ICashierPaymentService.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.service; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus; | ||
| 4 | +import com.diligrp.cashier.trade.domain.CashierOrder; | ||
| 5 | +import com.diligrp.cashier.trade.domain.CashierPayment; | ||
| 6 | +import com.diligrp.cashier.trade.domain.Merchant; | ||
| 7 | + | ||
| 8 | +public interface ICashierPaymentService { | ||
| 9 | + /** | ||
| 10 | + * 提交收银台订单 | ||
| 11 | + * | ||
| 12 | + * @param merchant - 接入商户 | ||
| 13 | + * @param cashierOrder - 订单申请 | ||
| 14 | + * @return 支付ID | ||
| 15 | + */ | ||
| 16 | + String doSubmit(Merchant merchant, CashierOrder cashierOrder); | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 收银台支付 | ||
| 20 | + * | ||
| 21 | + * @param cashierPayment - 支付信息 | ||
| 22 | + * @return 支付状态 | ||
| 23 | + */ | ||
| 24 | + OnlinePaymentStatus doPayment(CashierPayment cashierPayment); | ||
| 25 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/IPaymentAssistantService.java
0 → 100644
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/ITradeAssistantService.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.service; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.trade.domain.PaymentStateDTO; | ||
| 4 | +import com.diligrp.cashier.trade.domain.TradeStateDTO; | ||
| 5 | +import com.diligrp.cashier.trade.model.OnlinePayment; | ||
| 6 | +import com.diligrp.cashier.trade.model.TradeOrder; | ||
| 7 | + | ||
| 8 | +public interface ITradeAssistantService { | ||
| 9 | + | ||
| 10 | + /** | ||
| 11 | + * 查询交易订单 | ||
| 12 | + */ | ||
| 13 | + TradeOrder findByTradeId(String tradeId); | ||
| 14 | + | ||
| 15 | + /** | ||
| 16 | + * 交易订单状态处理 | ||
| 17 | + */ | ||
| 18 | + void proceedTradeOrder(TradeStateDTO tradeStateDTO); | ||
| 19 | + | ||
| 20 | + /** | ||
| 21 | + * 关闭交易订单下状态为支付中的支付订单 | ||
| 22 | + */ | ||
| 23 | + boolean resetTradeOrder(TradeOrder tradeOrder); | ||
| 24 | + | ||
| 25 | + /** | ||
| 26 | + * 查询支付订单 | ||
| 27 | + */ | ||
| 28 | + OnlinePayment findByPaymentId(String paymentId); | ||
| 29 | + | ||
| 30 | + /** | ||
| 31 | + * 支付订单状态处理 | ||
| 32 | + */ | ||
| 33 | + void proceedOnlinePayment(PaymentStateDTO paymentDTO); | ||
| 34 | + | ||
| 35 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierPaymentServiceImpl.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.service.impl; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.assistant.service.impl.SnowflakeKeyManager; | ||
| 4 | +import com.diligrp.cashier.pipeline.core.DiliCardPipeline; | ||
| 5 | +import com.diligrp.cashier.pipeline.core.OnlinePipeline; | ||
| 6 | +import com.diligrp.cashier.pipeline.core.PaymentPipeline; | ||
| 7 | +import com.diligrp.cashier.pipeline.domain.MiniProPrepayRequest; | ||
| 8 | +import com.diligrp.cashier.pipeline.domain.MiniProPrepayResponse; | ||
| 9 | +import com.diligrp.cashier.pipeline.domain.OnlinePaymentStatus; | ||
| 10 | +import com.diligrp.cashier.pipeline.domain.card.CardPaymentRequest; | ||
| 11 | +import com.diligrp.cashier.pipeline.domain.card.CardPaymentResponse; | ||
| 12 | +import com.diligrp.cashier.pipeline.service.IPaymentPipelineManager; | ||
| 13 | +import com.diligrp.cashier.pipeline.type.CashierType; | ||
| 14 | +import com.diligrp.cashier.pipeline.type.OutPaymentType; | ||
| 15 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 16 | +import com.diligrp.cashier.pipeline.type.PaymentType; | ||
| 17 | +import com.diligrp.cashier.shared.ErrorCode; | ||
| 18 | +import com.diligrp.cashier.trade.Constants; | ||
| 19 | +import com.diligrp.cashier.trade.dao.IOnlinePaymentDao; | ||
| 20 | +import com.diligrp.cashier.trade.dao.ITradeOrderDao; | ||
| 21 | +import com.diligrp.cashier.trade.domain.*; | ||
| 22 | +import com.diligrp.cashier.trade.exception.TradePaymentException; | ||
| 23 | +import com.diligrp.cashier.trade.manager.PaymentResultManager; | ||
| 24 | +import com.diligrp.cashier.trade.model.OnlinePayment; | ||
| 25 | +import com.diligrp.cashier.trade.model.TradeOrder; | ||
| 26 | +import com.diligrp.cashier.trade.service.ICashierPaymentService; | ||
| 27 | +import com.diligrp.cashier.trade.service.ITradeAssistantService; | ||
| 28 | +import com.diligrp.cashier.trade.type.SnowflakeKey; | ||
| 29 | +import com.diligrp.cashier.trade.type.TradeState; | ||
| 30 | +import com.diligrp.cashier.trade.type.TradeType; | ||
| 31 | +import com.diligrp.cashier.trade.util.CardPaymentConverter; | ||
| 32 | +import com.diligrp.cashier.trade.util.MiniProPaymentConverter; | ||
| 33 | +import jakarta.annotation.Resource; | ||
| 34 | +import org.redisson.api.RLock; | ||
| 35 | +import org.redisson.api.RedissonClient; | ||
| 36 | +import org.springframework.stereotype.Service; | ||
| 37 | +import org.springframework.transaction.annotation.Transactional; | ||
| 38 | + | ||
| 39 | +import java.time.LocalDateTime; | ||
| 40 | +import java.util.Objects; | ||
| 41 | +import java.util.concurrent.TimeUnit; | ||
| 42 | + | ||
| 43 | +@Service("cashierPaymentService") | ||
| 44 | +public class CashierPaymentServiceImpl implements ICashierPaymentService { | ||
| 45 | + | ||
| 46 | + @Resource | ||
| 47 | + private ITradeOrderDao tradeOrderDao; | ||
| 48 | + | ||
| 49 | + @Resource | ||
| 50 | + private IOnlinePaymentDao onlinePaymentDao; | ||
| 51 | + | ||
| 52 | + @Resource | ||
| 53 | + private ITradeAssistantService tradeAssistantService; | ||
| 54 | + | ||
| 55 | + @Resource | ||
| 56 | + private IPaymentPipelineManager paymentPipelineManager; | ||
| 57 | + | ||
| 58 | + @Resource | ||
| 59 | + private PaymentResultManager paymentResultManager; | ||
| 60 | + | ||
| 61 | + @Resource | ||
| 62 | + private SnowflakeKeyManager snowflakeKeyManager; | ||
| 63 | + | ||
| 64 | + @Resource | ||
| 65 | + private RedissonClient redissonClient; | ||
| 66 | + | ||
| 67 | + /** | ||
| 68 | + * 提交收银台订单 | ||
| 69 | + * | ||
| 70 | + * @param merchant - 接入商户 | ||
| 71 | + * @param cashierOrder - 订单申请 | ||
| 72 | + * @return 支付ID | ||
| 73 | + */ | ||
| 74 | + @Override | ||
| 75 | + @Transactional(rollbackFor = Exception.class) | ||
| 76 | + public String doSubmit(Merchant merchant, CashierOrder cashierOrder) { | ||
| 77 | + LocalDateTime now = LocalDateTime.now(); | ||
| 78 | + String tradeId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.TRADE_ID).nextId(); | ||
| 79 | + int timeout = Objects.isNull(cashierOrder.getTimeout()) ? Constants.DEFAULT_ORDER_TIMEOUT_SECONDS : cashierOrder.getTimeout(); | ||
| 80 | + timeout = Math.max(timeout, Constants.MIN_ORDER_TIMEOUT_SECONDS); | ||
| 81 | + TradeOrder tradeOrder = TradeOrder.builder().mchId(merchant.getMchId()).tradeId(tradeId) | ||
| 82 | + .type(cashierOrder.getType().getCode()).outTradeNo(cashierOrder.getOutTradeNo()).amount(cashierOrder.getAmount()) | ||
| 83 | + .maxAmount(cashierOrder.getAmount()).goods(cashierOrder.getGoods()).timeout(timeout).state(TradeState.PENDING.getCode()) | ||
| 84 | + .notifyUrl(cashierOrder.getNotifyUrl()).description(cashierOrder.getDescription()).attach(cashierOrder.getAttach()) | ||
| 85 | + .source(0).version(0).createdTime(now).modifiedTime(now).build(); | ||
| 86 | + tradeOrderDao.insertTradeOrder(tradeOrder); | ||
| 87 | + | ||
| 88 | + // TODO: userId是否需要存储 | ||
| 89 | + // TODO: 如果不打开收银台支付,定时关闭订单 | ||
| 90 | + return tradeId; | ||
| 91 | + } | ||
| 92 | + | ||
| 93 | + /** | ||
| 94 | + * 收银台支付 | ||
| 95 | + * | ||
| 96 | + * @param cashierPayment - 支付信息 | ||
| 97 | + * @return 支付状态 | ||
| 98 | + */ | ||
| 99 | + @Override | ||
| 100 | + @Transactional(rollbackFor = Exception.class) | ||
| 101 | + public OnlinePaymentStatus doPayment(CashierPayment cashierPayment) { | ||
| 102 | + // TODO: 防重复提交 | ||
| 103 | + String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, cashierPayment.getTradeId()); | ||
| 104 | + RLock lock = redissonClient.getLock(lockKey); | ||
| 105 | + try { | ||
| 106 | + boolean locked = lock.tryLock(Constants.TRADE_LOCK_TIMEOUT_SECONDS, TimeUnit.SECONDS); | ||
| 107 | + if (locked) { | ||
| 108 | + TradeOrder tradeOrder = tradeAssistantService.findByTradeId(cashierPayment.getTradeId()); | ||
| 109 | + CashierType cashierType = CashierType.getByCode(tradeOrder.getType()); | ||
| 110 | + if (TradeState.isFinished(tradeOrder.getState())) { | ||
| 111 | + throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "该交易订单已经完成,不能进行支付"); | ||
| 112 | + } | ||
| 113 | + // 关闭支付中的支付订单, 避免一个交易订单存在多笔支付订单, 造成重复支付 | ||
| 114 | + if (!tradeAssistantService.resetTradeOrder(tradeOrder)) { | ||
| 115 | + throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "存在支付中的支付申请"); | ||
| 116 | + } | ||
| 117 | + | ||
| 118 | + LocalDateTime now = LocalDateTime.now(); | ||
| 119 | + // 获取支付通道 | ||
| 120 | + PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(cashierPayment.getPipelineId(), PaymentPipeline.class); | ||
| 121 | + String paymentId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID).nextId(); | ||
| 122 | + if (pipeline instanceof DiliCardPipeline cardPipeline) { | ||
| 123 | + // 园区卡支付通道: 所有的收银台类型使用的是同一种园区卡支付流程 | ||
| 124 | + // 检查园区卡支付参数 | ||
| 125 | + CardPaymentRequest request = new CardPaymentConverter(tradeOrder, paymentId, now).convert(cashierPayment); | ||
| 126 | + // 修改支付状态为支付中,防止重复支付 | ||
| 127 | + CardPaymentResponse response = cardPipeline.sendPaymentRequest(request); | ||
| 128 | + if (PaymentState.isFinished(response.getState().getCode())) { | ||
| 129 | + // 园区卡支付通道outMchId为市场ID | ||
| 130 | + String outMchId = cardPipeline.params().getOutMchId(); | ||
| 131 | + OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(tradeOrder.getTradeId()) | ||
| 132 | + .type(TradeType.TRADE).paymentId(paymentId).channelId(pipeline.supportedChannel()) | ||
| 133 | + .payType(PaymentType.DIRECT).pipelineId(pipeline.pipelineId()).goods(tradeOrder.getGoods()) | ||
| 134 | + .amount(tradeOrder.getAmount()).payerId(response.getPayerId()) | ||
| 135 | + .finishTime(response.getWhen()).outTradeNo(response.getOutTradeNo()) | ||
| 136 | + .outPayType(OutPaymentType.DILICARD).state(response.getState()) | ||
| 137 | + .description(response.getMessage()).version(0).createdTime(now).modifiedTime(now).build(); | ||
| 138 | + onlinePaymentDao.insertOnlinePayment(payment); | ||
| 139 | + } | ||
| 140 | + if (response.getState() == PaymentState.SUCCESS) { | ||
| 141 | + TradeStateDTO tradeStateDTO = TradeStateDTO.of(tradeOrder.getTradeId(), TradeState.SUCCESS, | ||
| 142 | + tradeOrder.getVersion(), now); | ||
| 143 | + tradeAssistantService.proceedTradeOrder(tradeStateDTO); | ||
| 144 | + // 通知业务系统支付结果 | ||
| 145 | + TradePaymentResult paymentResult = new TradePaymentResult(tradeOrder.getTradeId(), | ||
| 146 | + response.getState().getCode(), tradeOrder.getOutTradeNo(), OutPaymentType.DILICARD.getCode(), | ||
| 147 | + response.getPayerId(), response.getWhen(), response.getMessage()); | ||
| 148 | + paymentResultManager.notifyPaymentResult(tradeOrder.getNotifyUrl(), paymentResult); | ||
| 149 | + } | ||
| 150 | + return response; | ||
| 151 | + } else if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { | ||
| 152 | + // 在线支付通道: 不同的收银台类型使用的支付方式不同 | ||
| 153 | + if (cashierType == CashierType.MINIPRO) { | ||
| 154 | + // 小程序支付收银台使用小程序支付 | ||
| 155 | + MiniProPrepayRequest request = new MiniProPaymentConverter(tradeOrder, paymentId, now).convert(cashierPayment); | ||
| 156 | + MiniProPrepayResponse response = onlinePipeline.sendMiniProPrepayRequest(request); | ||
| 157 | + // 微信服务商模式下outMchId为签约子商户 | ||
| 158 | + String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID); | ||
| 159 | + OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(tradeOrder.getTradeId()) | ||
| 160 | + .type(TradeType.TRADE).paymentId(paymentId).channelId(pipeline.supportedChannel()) | ||
| 161 | + .payType(PaymentType.MINI_PRO).pipelineId(pipeline.pipelineId()).goods(tradeOrder.getGoods()) | ||
| 162 | + .amount(tradeOrder.getAmount()).payerId(request.getOpenId()).outTradeNo(response.getOutTradeNo()) | ||
| 163 | + .state(response.getState()).version(0).createdTime(now).modifiedTime(now).build(); | ||
| 164 | + onlinePaymentDao.insertOnlinePayment(payment); | ||
| 165 | + | ||
| 166 | + TradeStateDTO tradeStateDTO = TradeStateDTO.of(tradeOrder.getTradeId(), TradeState.PROCESSING, | ||
| 167 | + tradeOrder.getVersion(), now); | ||
| 168 | + tradeAssistantService.proceedTradeOrder(tradeStateDTO); | ||
| 169 | + return response; | ||
| 170 | + } else { | ||
| 171 | + throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不支持的收银台类型"); | ||
| 172 | + } | ||
| 173 | + } else { | ||
| 174 | + // 目前只有两类支付通道: CardPipeline和OnlinePipeline, 程序逻辑不应该到达此代码块 | ||
| 175 | + throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不支持的支付通道类型"); | ||
| 176 | + } | ||
| 177 | + } else { | ||
| 178 | + throw new TradePaymentException(ErrorCode.SYSTEM_BUSY_ERROR, ErrorCode.MESSAGE_SYSTEM_BUSY); | ||
| 179 | + } | ||
| 180 | + } catch (InterruptedException ex) { | ||
| 181 | + // 重新设置中断标识 | ||
| 182 | + Thread.currentThread().interrupt(); | ||
| 183 | + throw new TradePaymentException(ErrorCode.SYSTEM_BUSY_ERROR, ErrorCode.MESSAGE_SYSTEM_BUSY); | ||
| 184 | + } finally { | ||
| 185 | + if (lock.isHeldByCurrentThread()) { | ||
| 186 | + lock.unlock(); | ||
| 187 | + } | ||
| 188 | + } | ||
| 189 | + } | ||
| 190 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/TradeAssistantServiceImpl.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.service.impl; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.Constants; | ||
| 4 | +import com.diligrp.cashier.pipeline.core.OnlinePipeline; | ||
| 5 | +import com.diligrp.cashier.pipeline.core.PaymentPipeline; | ||
| 6 | +import com.diligrp.cashier.pipeline.domain.OnlinePrepayOrder; | ||
| 7 | +import com.diligrp.cashier.pipeline.service.IPaymentPipelineManager; | ||
| 8 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 9 | +import com.diligrp.cashier.shared.ErrorCode; | ||
| 10 | +import com.diligrp.cashier.trade.dao.IOnlinePaymentDao; | ||
| 11 | +import com.diligrp.cashier.trade.dao.ITradeOrderDao; | ||
| 12 | +import com.diligrp.cashier.trade.domain.PaymentStateDTO; | ||
| 13 | +import com.diligrp.cashier.trade.domain.TradeStateDTO; | ||
| 14 | +import com.diligrp.cashier.trade.exception.TradePaymentException; | ||
| 15 | +import com.diligrp.cashier.trade.model.OnlinePayment; | ||
| 16 | +import com.diligrp.cashier.trade.model.TradeOrder; | ||
| 17 | +import com.diligrp.cashier.trade.service.ITradeAssistantService; | ||
| 18 | +import com.diligrp.cashier.trade.type.TradeState; | ||
| 19 | +import jakarta.annotation.Resource; | ||
| 20 | +import org.slf4j.Logger; | ||
| 21 | +import org.slf4j.LoggerFactory; | ||
| 22 | +import org.springframework.stereotype.Service; | ||
| 23 | +import org.springframework.transaction.annotation.Propagation; | ||
| 24 | +import org.springframework.transaction.annotation.Transactional; | ||
| 25 | + | ||
| 26 | +import java.time.LocalDateTime; | ||
| 27 | +import java.util.List; | ||
| 28 | +import java.util.Optional; | ||
| 29 | + | ||
| 30 | +@Service("tradeAssistantService") | ||
| 31 | +public class TradeAssistantServiceImpl implements ITradeAssistantService { | ||
| 32 | + | ||
| 33 | + private static final Logger LOG = LoggerFactory.getLogger(TradeAssistantServiceImpl.class); | ||
| 34 | + | ||
| 35 | + @Resource | ||
| 36 | + private ITradeOrderDao tradeOrderDao; | ||
| 37 | + | ||
| 38 | + @Resource | ||
| 39 | + private IOnlinePaymentDao onlinePaymentDao; | ||
| 40 | + | ||
| 41 | + @Resource | ||
| 42 | + private IPaymentPipelineManager paymentPipelineManager; | ||
| 43 | + | ||
| 44 | + @Override | ||
| 45 | + public TradeOrder findByTradeId(String tradeId) { | ||
| 46 | + Optional<TradeOrder> tradeOpt = tradeOrderDao.findByTradeId(tradeId); | ||
| 47 | + return tradeOpt.orElseThrow(() -> new TradePaymentException(ErrorCode.OBJECT_NOT_FOUND, "支付订单不存在")); | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + @Override | ||
| 51 | + public void proceedTradeOrder(TradeStateDTO tradeStateDTO) { | ||
| 52 | + if (tradeOrderDao.compareAndSetState(tradeStateDTO) == 0) { | ||
| 53 | + throw new TradePaymentException(ErrorCode.SYSTEM_BUSY_ERROR, ErrorCode.MESSAGE_SYSTEM_BUSY); | ||
| 54 | + } | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + /** | ||
| 58 | + * 关闭交易订单下状态为支付中的支付订单, 园区卡支付不存在支付中的订单 | ||
| 59 | + * | ||
| 60 | + * 独立数据库事务, 避免远程支付通道关单后, 支付订单状态仍然为支付中 | ||
| 61 | + * 任何一笔关闭订单失败都应该返回FALSE,且一笔失败不影响其他能正常的关单操作 | ||
| 62 | + */ | ||
| 63 | + @Override | ||
| 64 | + @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) | ||
| 65 | + public boolean resetTradeOrder(TradeOrder tradeOrder) { | ||
| 66 | + // 只有处理中的交易订单存在状态为支付中的支付订单 | ||
| 67 | + if (!TradeState.isProcessing(tradeOrder.getState())) { | ||
| 68 | + return true; | ||
| 69 | + } | ||
| 70 | + | ||
| 71 | + boolean result = true; | ||
| 72 | + // 理论上只会存在一条支付中的支付订单 | ||
| 73 | + List<OnlinePayment> onlinePayments = onlinePaymentDao.findByTradeId(tradeOrder.getTradeId(), PaymentState.PROCESSING.getCode()); | ||
| 74 | + for (OnlinePayment onlinePayment : onlinePayments) { | ||
| 75 | + try { | ||
| 76 | + PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(onlinePayment.getPipelineId(), PaymentPipeline.class); | ||
| 77 | + if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { | ||
| 78 | + LocalDateTime now = LocalDateTime.now(); | ||
| 79 | + PaymentStateDTO paymentStateDTO = PaymentStateDTO.builder().paymentId(onlinePayment.getPaymentId()) | ||
| 80 | + .finishTime(now).state(PaymentState.FAILED).description("主动关闭支付中的订单") | ||
| 81 | + .version(onlinePayment.getVersion()).modifiedTime(now).build(); | ||
| 82 | + proceedOnlinePayment(paymentStateDTO); | ||
| 83 | + OnlinePrepayOrder prepayOrder = new OnlinePrepayOrder(onlinePayment.getPaymentId(), onlinePayment.getOutTradeNo()); | ||
| 84 | + // 微信服务商模式下, outMchId为签约子商户; 园区卡支付时, outMchId为市场ID | ||
| 85 | + prepayOrder.attach(Constants.PARAM_MCH_ID, onlinePayment.getOutMchId()); | ||
| 86 | + onlinePipeline.closePrepayOrder(prepayOrder); | ||
| 87 | + } | ||
| 88 | + // 园区卡支付不存在支付中的订单 | ||
| 89 | + } catch (Exception ex) { | ||
| 90 | + result = false; | ||
| 91 | + LOG.error("关闭支付订单失败: {}", onlinePayment.getPaymentId(), ex); | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + return result; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + @Override | ||
| 98 | + public OnlinePayment findByPaymentId(String paymentId) { | ||
| 99 | + Optional<OnlinePayment> paymentOpt = onlinePaymentDao.findByPaymentId(paymentId); | ||
| 100 | + return paymentOpt.orElseThrow(() -> new TradePaymentException(ErrorCode.OBJECT_NOT_FOUND, "支付订单不存在")); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + @Override | ||
| 104 | + public void proceedOnlinePayment(PaymentStateDTO paymentDTO) { | ||
| 105 | + if (onlinePaymentDao.compareAndSetState(paymentDTO) == 0) { | ||
| 106 | + throw new TradePaymentException(ErrorCode.SYSTEM_BUSY_ERROR, ErrorCode.MESSAGE_SYSTEM_BUSY); | ||
| 107 | + } | ||
| 108 | + } | ||
| 109 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/type/SourceType.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.type; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.shared.type.IEnumType; | ||
| 4 | + | ||
| 5 | +import java.util.Arrays; | ||
| 6 | +import java.util.List; | ||
| 7 | +import java.util.Optional; | ||
| 8 | +import java.util.stream.Stream; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 订单来源 | ||
| 12 | + */ | ||
| 13 | +public enum SourceType implements IEnumType { | ||
| 14 | + | ||
| 15 | + PC("PC端", 1), | ||
| 16 | + | ||
| 17 | + MINIPRO("小程序端", 2), | ||
| 18 | + | ||
| 19 | + APP("APP端", 3), | ||
| 20 | + | ||
| 21 | + ATM("自助机", 4); | ||
| 22 | + | ||
| 23 | + private final String name; | ||
| 24 | + private final int code; | ||
| 25 | + | ||
| 26 | + SourceType(String name, int code) { | ||
| 27 | + this.name = name; | ||
| 28 | + this.code = code; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + public boolean equalTo(int code) { | ||
| 32 | + return this.code == code; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public static Optional<SourceType> getType(int code) { | ||
| 36 | + Stream<SourceType> TYPES = Arrays.stream(SourceType.values()); | ||
| 37 | + return TYPES.filter(type -> type.getCode() == code).findFirst(); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public static String getName(int code) { | ||
| 41 | + return getType(code).map(SourceType::getName).orElse(null); | ||
| 42 | + } | ||
| 43 | + | ||
| 44 | + public static List<SourceType> getTypes() { | ||
| 45 | + return Arrays.asList(SourceType.values()); | ||
| 46 | + } | ||
| 47 | + | ||
| 48 | + @Override | ||
| 49 | + public String getName() { | ||
| 50 | + return name; | ||
| 51 | + } | ||
| 52 | + | ||
| 53 | + @Override | ||
| 54 | + public int getCode() { | ||
| 55 | + return code; | ||
| 56 | + } | ||
| 57 | + | ||
| 58 | + @Override | ||
| 59 | + public String toString() { | ||
| 60 | + return name; | ||
| 61 | + } | ||
| 62 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/type/TradeState.java
| 1 | package com.diligrp.cashier.trade.type; | 1 | package com.diligrp.cashier.trade.type; |
| 2 | 2 | ||
| 3 | +import com.diligrp.cashier.pipeline.type.PaymentState; | ||
| 3 | import com.diligrp.cashier.shared.type.IEnumType; | 4 | import com.diligrp.cashier.shared.type.IEnumType; |
| 4 | 5 | ||
| 5 | import java.util.Arrays; | 6 | import java.util.Arrays; |
| @@ -14,6 +15,8 @@ public enum TradeState implements IEnumType { | @@ -14,6 +15,8 @@ public enum TradeState implements IEnumType { | ||
| 14 | 15 | ||
| 15 | PENDING("待处理", 1), | 16 | PENDING("待处理", 1), |
| 16 | 17 | ||
| 18 | + PROCESSING("处理中", 2), | ||
| 19 | + | ||
| 17 | SUCCESS("交易成功", 4), | 20 | SUCCESS("交易成功", 4), |
| 18 | 21 | ||
| 19 | REFUND("交易退款", 5), | 22 | REFUND("交易退款", 5), |
| @@ -47,6 +50,19 @@ public enum TradeState implements IEnumType { | @@ -47,6 +50,19 @@ public enum TradeState implements IEnumType { | ||
| 47 | return Arrays.asList(TradeState.values()); | 50 | return Arrays.asList(TradeState.values()); |
| 48 | } | 51 | } |
| 49 | 52 | ||
| 53 | + public static boolean isPending(int code) { | ||
| 54 | + return TradeState.PENDING.equalTo(code); | ||
| 55 | + } | ||
| 56 | + | ||
| 57 | + public static boolean isProcessing(int code) { | ||
| 58 | + return TradeState.PROCESSING.equalTo(code); | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | + public static boolean isFinished(int code) { | ||
| 62 | + return TradeState.SUCCESS.equalTo(code) || TradeState.FAILED.equalTo(code) || | ||
| 63 | + TradeState.REFUND.equalTo(code) || TradeState.CLOSED.equalTo(code); | ||
| 64 | + } | ||
| 65 | + | ||
| 50 | /** | 66 | /** |
| 51 | * 交易订单是否允许退款; 允许多次交易退款 | 67 | * 交易订单是否允许退款; 允许多次交易退款 |
| 52 | * | 68 | * |
cashier-trade/src/main/java/com/diligrp/cashier/trade/util/CardPaymentConverter.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.util; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.domain.card.CardPaymentRequest; | ||
| 4 | +import com.diligrp.cashier.shared.codec.IConverter; | ||
| 5 | +import com.diligrp.cashier.trade.domain.CashierPayment; | ||
| 6 | +import com.diligrp.cashier.trade.model.OnlinePayment; | ||
| 7 | +import com.diligrp.cashier.trade.model.TradeOrder; | ||
| 8 | +import org.springframework.util.Assert; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | +public class CardPaymentConverter implements IConverter<CashierPayment, CardPaymentRequest> { | ||
| 14 | + | ||
| 15 | + private static final String PARAM_ACCOUNT_ID = "accountId"; | ||
| 16 | + | ||
| 17 | + private static final String PARAM_CARD_NO = "cardNo"; | ||
| 18 | + | ||
| 19 | + private final TradeOrder tradeOrder; | ||
| 20 | + | ||
| 21 | + private final String paymentId; | ||
| 22 | + | ||
| 23 | + private final LocalDateTime when; | ||
| 24 | + | ||
| 25 | + public CardPaymentConverter(TradeOrder tradeOrder, String paymentId, LocalDateTime when) { | ||
| 26 | + this.tradeOrder = tradeOrder; | ||
| 27 | + this.paymentId = paymentId; | ||
| 28 | + this.when = when; | ||
| 29 | + } | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public CardPaymentRequest convert(CashierPayment payment) { | ||
| 33 | + Map<String, Object> params = payment.getParams(); | ||
| 34 | + Assert.notNull(params, "params missed"); | ||
| 35 | + Long accountId = (Long) payment.getParams().get(PARAM_ACCOUNT_ID); | ||
| 36 | + String cardNo = (String) params.get(PARAM_CARD_NO); | ||
| 37 | + Assert.notNull(accountId, "params.accountId missed"); | ||
| 38 | + Assert.notNull(cardNo, "params.cardNo missed"); | ||
| 39 | + | ||
| 40 | + return new CardPaymentRequest(paymentId, tradeOrder.getMaxAmount(), | ||
| 41 | + tradeOrder.getGoods(), tradeOrder.getDescription(), when, accountId, cardNo); | ||
| 42 | + } | ||
| 43 | +} |
cashier-trade/src/main/java/com/diligrp/cashier/trade/util/MiniProPaymentConverter.java
0 → 100644
| 1 | +package com.diligrp.cashier.trade.util; | ||
| 2 | + | ||
| 3 | +import com.diligrp.cashier.pipeline.Constants; | ||
| 4 | +import com.diligrp.cashier.pipeline.domain.MiniProPrepayRequest; | ||
| 5 | +import com.diligrp.cashier.shared.codec.IConverter; | ||
| 6 | +import com.diligrp.cashier.trade.domain.CashierPayment; | ||
| 7 | +import com.diligrp.cashier.trade.model.TradeOrder; | ||
| 8 | +import org.springframework.util.Assert; | ||
| 9 | + | ||
| 10 | +import java.time.LocalDateTime; | ||
| 11 | +import java.util.Map; | ||
| 12 | + | ||
| 13 | +public class MiniProPaymentConverter implements IConverter<CashierPayment, MiniProPrepayRequest> { | ||
| 14 | + | ||
| 15 | + private final TradeOrder tradeOrder; | ||
| 16 | + | ||
| 17 | + private final String paymentId; | ||
| 18 | + | ||
| 19 | + private final LocalDateTime when; | ||
| 20 | + | ||
| 21 | + public MiniProPaymentConverter(TradeOrder tradeOrder, String paymentId, LocalDateTime when) { | ||
| 22 | + this.tradeOrder = tradeOrder; | ||
| 23 | + this.paymentId = paymentId; | ||
| 24 | + this.when = when; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public MiniProPrepayRequest convert(CashierPayment payment) { | ||
| 29 | + Map<String, Object> params = payment.getParams(); | ||
| 30 | + Assert.notNull(params, "params missed"); | ||
| 31 | + String openId = (String) params.get(Constants.PARAM_OPEN_ID); | ||
| 32 | + Assert.notNull(openId, "params.openId missed"); | ||
| 33 | + | ||
| 34 | + MiniProPrepayRequest prepayRequest = new MiniProPrepayRequest(paymentId, tradeOrder.getMaxAmount(), | ||
| 35 | + tradeOrder.getGoods(), tradeOrder.getDescription(), when, openId); | ||
| 36 | + prepayRequest.putParams(params); | ||
| 37 | + return prepayRequest; | ||
| 38 | + } | ||
| 39 | +} |
cashier-trade/src/main/resources/com/diligrp/cashier/dao/mapper/IOnlinePaymentDao.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
| 3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 4 | + | ||
| 5 | +<mapper namespace="com.diligrp.cashier.trade.dao.IOnlinePaymentDao"> | ||
| 6 | + <resultMap id="OnlinePaymentMap" type="com.diligrp.cashier.trade.model.OnlinePayment"> | ||
| 7 | + <id column="id" property="id"/> | ||
| 8 | + <result column="out_mch_id" property="outMchId"/> | ||
| 9 | + <result column="trade_id" property="tradeId"/> | ||
| 10 | + <result column="type" property="type"/> | ||
| 11 | + <result column="payment_id" property="paymentId"/> | ||
| 12 | + <result column="channel_id" property="channelId"/> | ||
| 13 | + <result column="pay_type" property="payType"/> | ||
| 14 | + <result column="pipeline_id" property="pipelineId"/> | ||
| 15 | + <result column="goods" property="goods"/> | ||
| 16 | + <result column="amount" property="amount"/> | ||
| 17 | + <result column="object_id" property="objectId"/> | ||
| 18 | + <result column="payer_id" property="payerId"/> | ||
| 19 | + <result column="finish_time" property="finishTime"/> | ||
| 20 | + <result column="out_trade_no" property="outTradeNo"/> | ||
| 21 | + <result column="out_pay_type" property="outPayType"/> | ||
| 22 | + <result column="state" property="state"/> | ||
| 23 | + <result column="description" property="description"/> | ||
| 24 | + <result column="version" property="version"/> | ||
| 25 | + <result column="created_time" property="createdTime"/> | ||
| 26 | + <result column="modified_time" property="modifiedTime"/> | ||
| 27 | + </resultMap> | ||
| 28 | + | ||
| 29 | + <insert id="insertOnlinePayment" parameterType="com.diligrp.cashier.trade.model.OnlinePayment"> | ||
| 30 | + INSERT INTO upay_online_payment(out_mch_id, trade_id, type, payment_id, channel_id, pay_type, pipeline_id, | ||
| 31 | + goods, amount, object_id, payer_id, finish_time, out_trade_no, out_pay_type, | ||
| 32 | + state, description, version, created_time, modified_time) | ||
| 33 | + VALUES | ||
| 34 | + (#{outMchId}, #{tradeId}, #{type}, #{paymentId}, #{channelId}, #{payType}, #{pipelineId}, | ||
| 35 | + #{goods}, #{amount}, #{objectId}, #{payerId}, #{finishTime}, #{outTradeNo}, #{outPayType} | ||
| 36 | + #{state}, #{description}, #{version}, #{createdTime}, #{modifiedTime}) | ||
| 37 | + </insert> | ||
| 38 | + | ||
| 39 | + <select id="findByPaymentId" parameterType="string" resultMap="OnlinePaymentMap"> | ||
| 40 | + SELECT * FROM upay_online_payment WHERE payment_id = #{paymentId} | ||
| 41 | + </select> | ||
| 42 | + | ||
| 43 | + <update id="compareAndSetState" parameterType="com.diligrp.cashier.trade.domain.PaymentStateDTO"> | ||
| 44 | + UPDATE upay_online_payment SET version = version + 1 | ||
| 45 | + <if test="outTradeNo != null"> | ||
| 46 | + , out_trade_no = #{outTradeNo} | ||
| 47 | + </if> | ||
| 48 | + <if test="outPayType != null"> | ||
| 49 | + , out_pay_type = #{outPayType} | ||
| 50 | + </if> | ||
| 51 | + <if test="payerId != null"> | ||
| 52 | + , payer_id = #{payerId} | ||
| 53 | + </if> | ||
| 54 | + <if test="finishTime != null"> | ||
| 55 | + , finish_time = #{finishTime} | ||
| 56 | + </if> | ||
| 57 | + <if test="state != null"> | ||
| 58 | + , state = #{state} | ||
| 59 | + </if> | ||
| 60 | + <if test="description != null"> | ||
| 61 | + , description = #{description} | ||
| 62 | + </if> | ||
| 63 | + <if test="modifiedTime != null"> | ||
| 64 | + , modified_time = #{modifiedTime} | ||
| 65 | + </if> | ||
| 66 | + WHERE | ||
| 67 | + payment_id = #{paymentId} AND version = #{version} | ||
| 68 | + </update> | ||
| 69 | + | ||
| 70 | + <select id="findByTradeId" resultMap="OnlinePaymentMap"> | ||
| 71 | + SELECT * FROM upay_online_payment WHERE trade_id = #{tradeId} | ||
| 72 | + <if test="state != null"> | ||
| 73 | + AND state = #{state} | ||
| 74 | + </if> | ||
| 75 | + ORDER BY id | ||
| 76 | + </select> | ||
| 77 | +</mapper> |
cashier-trade/src/main/resources/com/diligrp/cashier/dao/mapper/ITradeOrderDao.xml
0 → 100644
| 1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
| 2 | +<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" | ||
| 3 | + "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> | ||
| 4 | + | ||
| 5 | +<mapper namespace="com.diligrp.cashier.trade.dao.ITradeOrderDao"> | ||
| 6 | + <resultMap id="TradeOrderMap" type="com.diligrp.cashier.trade.model.TradeOrder"> | ||
| 7 | + <id column="id" property="id"/> | ||
| 8 | + <result column="mch_id" property="mchId"/> | ||
| 9 | + <result column="trade_id" property="tradeId"/> | ||
| 10 | + <result column="type" property="type"/> | ||
| 11 | + <result column="out_trade_no" property="outTradeNo"/> | ||
| 12 | + <result column="amount" property="amount"/> | ||
| 13 | + <result column="max_amount" property="maxAmount"/> | ||
| 14 | + <result column="goods" property="goods"/> | ||
| 15 | + <result column="timeout" property="timeout"/> | ||
| 16 | + <result column="state" property="state"/> | ||
| 17 | + <result column="notify_url" property="notifyUrl"/> | ||
| 18 | + <result column="description" property="description"/> | ||
| 19 | + <result column="attach" property="attach"/> | ||
| 20 | + <result column="source" property="source"/> | ||
| 21 | + <result column="version" property="version"/> | ||
| 22 | + <result column="created_time" property="createdTime"/> | ||
| 23 | + <result column="modified_time" property="modifiedTime"/> | ||
| 24 | + </resultMap> | ||
| 25 | + | ||
| 26 | + <insert id="insertTradeOrder" parameterType="com.diligrp.cashier.trade.model.TradeOrder"> | ||
| 27 | + INSERT INTO upay_trade_order(mch_id, trade_id, type, out_trade_no, amount, max_amount, goods, timeout, | ||
| 28 | + state, notify_url, description, attach, source, version, created_time, modified_time) | ||
| 29 | + VALUES (#{mchId}, #{tradeId}, #{type}, #{outTradeNo}, #{amount}, #{maxAmount}, #{goods}, #{timeout}, | ||
| 30 | + #{state}, #{notifyUrl}, #{description}, #{attach}, #{source}, #{version}, #{createdTime}, #{modifiedTime}) | ||
| 31 | + </insert> | ||
| 32 | + | ||
| 33 | + <select id="findByTradeId" resultMap="TradeOrderMap"> | ||
| 34 | + SELECT * FROM upay_trade_order WHERE trade_id = #{tradeId} | ||
| 35 | + </select> | ||
| 36 | + | ||
| 37 | + <select id="findByOutTradeNo" resultMap="TradeOrderMap"> | ||
| 38 | + SELECT * FROM upay_trade_order WHERE mch_id = #{mchId} AND out_trade_no = #{outTradeNo} | ||
| 39 | + </select> | ||
| 40 | + | ||
| 41 | + <update id="compareAndSetState"> | ||
| 42 | + UPDATE upay_trade_order SET version = version + 1 | ||
| 43 | + <if test="amount != null"> | ||
| 44 | + , amount = #{amount} | ||
| 45 | + </if> | ||
| 46 | + <if test="state != null"> | ||
| 47 | + , state = #{state} | ||
| 48 | + </if> | ||
| 49 | + <if test="modifiedTime != null"> | ||
| 50 | + , modified_time = #{modifiedTime} | ||
| 51 | + </if> | ||
| 52 | + WHERE | ||
| 53 | + trade_id = #{tradeId} AND version = #{version} | ||
| 54 | + </update> | ||
| 55 | +</mapper> |
scripts/dili-cashier.sql
| @@ -7,7 +7,6 @@ CREATE TABLE `upay_merchant` ( | @@ -7,7 +7,6 @@ CREATE TABLE `upay_merchant` ( | ||
| 7 | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', | 7 | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', |
| 8 | `mch_id` BIGINT NOT NULL COMMENT '商户ID', | 8 | `mch_id` BIGINT NOT NULL COMMENT '商户ID', |
| 9 | `name` VARCHAR(60) NOT NULL COMMENT '商户名称', | 9 | `name` VARCHAR(60) NOT NULL COMMENT '商户名称', |
| 10 | - `access_token` VARCHAR(40) NOT NULL COMMENT '访问令牌', | ||
| 11 | `param` JSON COMMENT '参数配置', | 10 | `param` JSON COMMENT '参数配置', |
| 12 | `address` VARCHAR(128) COMMENT '商户地址', | 11 | `address` VARCHAR(128) COMMENT '商户地址', |
| 13 | `linkman` VARCHAR(40) COMMENT '联系人', | 12 | `linkman` VARCHAR(40) COMMENT '联系人', |
| @@ -27,17 +26,17 @@ CREATE TABLE `upay_trade_order` ( | @@ -27,17 +26,17 @@ CREATE TABLE `upay_trade_order` ( | ||
| 27 | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', | 26 | `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '主键ID', |
| 28 | `mch_id` BIGINT NOT NULL COMMENT '商户ID', | 27 | `mch_id` BIGINT NOT NULL COMMENT '商户ID', |
| 29 | `trade_id` VARCHAR(40) NOT NULL COMMENT '交易ID', | 28 | `trade_id` VARCHAR(40) NOT NULL COMMENT '交易ID', |
| 30 | - `type` TINYINT UNSIGNED NOT NULL COMMENT '交易类型', -- 购买会员 | ||
| 31 | --- `channel_id` TINYINT UNSIGNED NOT NULL COMMENT '支付渠道', | 29 | + `type` TINYINT UNSIGNED NOT NULL COMMENT '业务类型', -- 购买会员 |
| 32 | `out_trade_no` VARCHAR(40) COMMENT '外部流水号', -- 商户流水号 | 30 | `out_trade_no` VARCHAR(40) COMMENT '外部流水号', -- 商户流水号 |
| 33 | `amount` BIGINT NOT NULL COMMENT '金额-分', | 31 | `amount` BIGINT NOT NULL COMMENT '金额-分', |
| 34 | `max_amount` BIGINT NOT NULL COMMENT '初始金额-分', | 32 | `max_amount` BIGINT NOT NULL COMMENT '初始金额-分', |
| 35 | - `goods` VARCHAR(128) COMMENT '商品描述', | ||
| 36 | - `order_timeout` INTEGER UNSIGNED NOT NULL COMMENT '超时间隔时间-秒', | 33 | + `goods` VARCHAR(128) NOT NULL COMMENT '商品描述', |
| 34 | + `timeout` INTEGER UNSIGNED NOT NULL COMMENT '超时间隔时间-秒', | ||
| 37 | `state` TINYINT UNSIGNED NOT NULL COMMENT '交易状态', | 35 | `state` TINYINT UNSIGNED NOT NULL COMMENT '交易状态', |
| 36 | + `notify_url` VARCHAR(128) COMMENT '业务回调链接', | ||
| 38 | `description` VARCHAR(128) COMMENT '交易备注', | 37 | `description` VARCHAR(128) COMMENT '交易备注', |
| 39 | `attach` VARCHAR(255) COMMENT '附加数据', | 38 | `attach` VARCHAR(255) COMMENT '附加数据', |
| 40 | - `cashier_desk` TINYINT UNSIGNED NOT NULL COMMENT '收银台类型', | 39 | + `source` TINYINT UNSIGNED COMMENT '订单来源', |
| 41 | `version` INTEGER UNSIGNED NOT NULL COMMENT '数据版本号', | 40 | `version` INTEGER UNSIGNED NOT NULL COMMENT '数据版本号', |
| 42 | `created_time` DATETIME COMMENT '创建时间', | 41 | `created_time` DATETIME COMMENT '创建时间', |
| 43 | `modified_time` DATETIME COMMENT '修改时间', | 42 | `modified_time` DATETIME COMMENT '修改时间', |
| @@ -68,7 +67,6 @@ CREATE TABLE `upay_online_payment` ( | @@ -68,7 +67,6 @@ CREATE TABLE `upay_online_payment` ( | ||
| 68 | `out_trade_no` VARCHAR(40) COMMENT '通道流水号', | 67 | `out_trade_no` VARCHAR(40) COMMENT '通道流水号', |
| 69 | `out_pay_type` TINYINT UNSIGNED NOT NULL COMMENT '实际支付方式', -- 银行聚合支付时使用 | 68 | `out_pay_type` TINYINT UNSIGNED NOT NULL COMMENT '实际支付方式', -- 银行聚合支付时使用 |
| 70 | `state` TINYINT UNSIGNED NOT NULL COMMENT '申请状态', | 69 | `state` TINYINT UNSIGNED NOT NULL COMMENT '申请状态', |
| 71 | - `notify_uri` VARCHAR(128) COMMENT '业务回调链接', | ||
| 72 | `description` VARCHAR(256) COMMENT '交易备注', | 70 | `description` VARCHAR(256) COMMENT '交易备注', |
| 73 | `version` INTEGER UNSIGNED NOT NULL COMMENT '数据版本号', | 71 | `version` INTEGER UNSIGNED NOT NULL COMMENT '数据版本号', |
| 74 | `created_time` DATETIME COMMENT '创建时间', | 72 | `created_time` DATETIME COMMENT '创建时间', |