Commit eb7b1af06ed4b483f64670c48835e117bb130b85

Authored by huanggang
1 parent e2a07d8f

upgrade after testing

cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/CardPaymentHttpClient.java
... ... @@ -68,7 +68,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport {
68 68 LocalDateTime now = LocalDateTime.now();
69 69 HttpResult result = send(uri, payload);
70 70 if (result.statusCode == 200) {
71   - LOG.debug("Received from card payment pipeline: {}\n{}", request.getPaymentId(), result.responseText);
  71 + LOG.debug("Card payment response received: {}\n{}", request.getPaymentId(), result.responseText);
72 72 Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
73 73 if ("200".equals(response.get("code"))) {
74 74 Map<String, Object> data = (Map<String, Object>) response.get("data");
... ... @@ -99,7 +99,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport {
99 99 LocalDateTime now = LocalDateTime.now();
100 100 HttpResult result = send(uri, payload);
101 101 if (result.statusCode == 200) {
102   - LOG.debug("Received from card payment pipeline: {}\n", request.getRefundId(), result.responseText);
  102 + LOG.debug("Card refund response received: {}\n{}", request.getRefundId(), result.responseText);
103 103 Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
104 104 if ("200".equals(response.get("code"))) {
105 105 return new OnlineRefundResponse(request.getRefundId(), null, now,
... ... @@ -121,7 +121,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport {
121 121 LOG.debug("Sending list user card request: {}\n{}", userId, payload);
122 122 HttpResult result = send(uri, payload);
123 123 if (result.statusCode == 200) {
124   - LOG.debug("Received from card payment pipeline: {}\n{}", userId, result.responseText);
  124 + LOG.debug("List user card response received: {}\n{}", userId, result.responseText);
125 125 Map<String, Object> response = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
126 126 if ("200".equals(response.get("code"))) {
127 127 List<UserCardDTO> userCards = new ArrayList<>();
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/RcbOnlineHttpClient.java
... ... @@ -11,7 +11,6 @@
11 11 import com.diligrp.cashier.shared.service.ServiceEndpointSupport;
12 12 import com.diligrp.cashier.shared.util.*;
13 13 import com.fasterxml.jackson.core.type.TypeReference;
14   - import jakarta.annotation.Resource;
15 14 import org.slf4j.Logger;
16 15 import org.slf4j.LoggerFactory;
17 16 import org.springframework.dao.DataAccessException;
... ... @@ -38,11 +37,6 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
38 37  
39 38 private static final Logger LOG = LoggerFactory.getLogger(RcbOnlineHttpClient.class);
40 39  
41   - // 微信API BASE URL
42   - private static final String WECHAT_BASE_URL = "https://api.weixin.qq.com";
43   - // code2session接口: 根据登录凭证code获取登录信息
44   - private static final String CODE_TO_SESSION = "/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code";
45   -
46 40 private static final int STATUS_OK = 200;
47 41  
48 42 private final String uri;
... ... @@ -89,7 +83,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
89 83 LOG.error("Failed to send rcb MiniPro prepay request: {}", result.statusCode);
90 84 throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "调用小程序预支付接口失败: " + result.statusCode);
91 85 }
92   - LOG.debug("Received from rcb MiniPro pipeline: {}\n{}", request.getPaymentId(), result.responseText);
  86 + LOG.debug("Rcb MiniPro prepay received: {}\n{}", request.getPaymentId(), result.responseText);
93 87  
94 88 Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
95 89 String resultCode = data.get("resultCode");
... ... @@ -117,13 +111,13 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
117 111  
118 112 params.put("sign", RcbSignatureUtils.sign(params, key));
119 113 String payload = JsonUtils.toJsonString(params);
120   - LOG.info("Sending rcb query prepay order state request: {}", request.getPaymentId());
  114 + LOG.info("Sending query rcb prepay order request: {}", request.getPaymentId());
121 115 HttpResult result = send(uri + "/cposp/pay/orderQuery", payload);
122 116 if (result.statusCode != STATUS_OK) {
123   - LOG.error("Failed to query rcb prepay order state: {}", result.statusCode);
  117 + LOG.error("Failed to query rcb prepay order: {}", result.statusCode);
124 118 throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "查询支付状态失败: " + result.statusCode);
125 119 }
126   - LOG.debug("Received from rcb online pipeline: {}\n{}", request.getPaymentId(), result.responseText);
  120 + LOG.debug("Query rcb prepay order response received: {}\n{}", request.getPaymentId(), result.responseText);
127 121  
128 122 Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
129 123 String signature = data.remove("sign");
... ... @@ -175,7 +169,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
175 169 LOG.error("Failed to close rcb prepay order: {}", request.getPaymentId());
176 170 throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "关闭支付订单失败: " + result.statusCode);
177 171 }
178   - LOG.debug("Received from rcb online pipeline: {}\n{}", request.getPaymentId(), result.responseText);
  172 + LOG.debug("Close rcb prepay order response received: {}\n{}", request.getPaymentId(), result.responseText);
179 173  
180 174 Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
181 175 String resultCode = data.get("resultCode");
... ... @@ -212,7 +206,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
212 206 LOG.error("Failed to send rcb refund request: {}", request.getRefundId());
213 207 throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "发送退款请求失败: " + result.statusCode);
214 208 }
215   - LOG.debug("Received from rcb online pipeline: {}\n{}", request.getRefundId(), result.responseText);
  209 + LOG.debug("Rcb payment refund response received: {}\n{}", request.getRefundId(), result.responseText);
216 210  
217 211 Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
218 212 String resultCode = data.get("resultCode");
... ... @@ -252,7 +246,7 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
252 246 LOG.error("Failed to get rcb batch no, statusCode: {}", result.statusCode);
253 247 throw new PaymentPipelineException(ErrorCode.SYSTEM_UNKNOWN_ERROR, "获取签到批次号: " + result.statusCode);
254 248 }
255   - LOG.debug("Received from rcb online pipeline: {}", result.responseText);
  249 + LOG.debug("Rcb signIn response received: {}", result.responseText);
256 250  
257 251 Map<String, String> data = JsonUtils.fromJsonString(result.responseText, new TypeReference<>() {});
258 252 String resultCode = data.get("resultCode");
... ... @@ -262,13 +256,13 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
262 256 stringRedisTemplate.opsForValue().set(key, batchNo, 36 * 60 * 60, TimeUnit.SECONDS);
263 257 return batchNo;
264 258 } else {
265   - LOG.error("Failed to rcb sign in, errorCode: {}, resultMessage: {}", resultCode, resultMessage);
266   - throw new PaymentPipelineException(ErrorCode.SERVICE_ACCESS_ERROR, "签到接口调用失败");
  259 + LOG.error("Failed to rcb signIn: {}", result.responseText);
  260 + throw new PaymentPipelineException(ErrorCode.SERVICE_ACCESS_ERROR, "签到接口调用失败: " + resultMessage);
267 261 }
268 262 } catch (ServiceAccessException | PaymentPipelineException rex) {
269 263 throw rex;
270 264 } catch (Exception ex) {
271   - LOG.error("Failed to get rcb sign in batchNo", ex);
  265 + LOG.error("Failed to rcb signIn", ex);
272 266 throw new PaymentPipelineException(ErrorCode.SERVICE_ACCESS_ERROR, "获取签到批次号失败");
273 267 }
274 268 }
... ... @@ -326,57 +320,4 @@ public class RcbOnlineHttpClient extends ServiceEndpointSupport {
326 320 }
327 321 return Optional.ofNullable(sslContext);
328 322 }
329   -
330   - private static class AuthorizationSession {
331   - // 用户唯一标识
332   - private String openid;
333   - // 会话密钥
334   - private String session_key;
335   - // 用户在开放平台的唯一标识
336   - private String unionid;
337   - // 错误码
338   - private Integer errcode;
339   - // 错误信息
340   - private String errmsg;
341   -
342   - public String getOpenid() {
343   - return openid;
344   - }
345   -
346   - public void setOpenid(String openid) {
347   - this.openid = openid;
348   - }
349   -
350   - public String getSession_key() {
351   - return session_key;
352   - }
353   -
354   - public void setSession_key(String session_key) {
355   - this.session_key = session_key;
356   - }
357   -
358   - public String getUnionid() {
359   - return unionid;
360   - }
361   -
362   - public void setUnionid(String unionid) {
363   - this.unionid = unionid;
364   - }
365   -
366   - public Integer getErrcode() {
367   - return errcode;
368   - }
369   -
370   - public void setErrcode(Integer errcode) {
371   - this.errcode = errcode;
372   - }
373   -
374   - public String getErrmsg() {
375   - return errmsg;
376   - }
377   -
378   - public void setErrmsg(String errmsg) {
379   - this.errmsg = errmsg;
380   - }
381   - }
382 323 }
... ...
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/core/DefaultTimeStrategy.java
... ... @@ -7,10 +7,10 @@ public class DefaultTimeStrategy implements ScanTimeStrategy {
7 7 private final long[] prepayTimeArray = { 10 * ONE_MINUTE };
8 8  
9 9 // 直接支付订单扫描时间策略
10   - private final long[] paymentTimeArray = {5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 10 * ONE_SECOND, 15 * ONE_SECOND};
  10 + private final long[] paymentTimeArray = { 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 5 * ONE_SECOND, 10 * ONE_SECOND, 15 * ONE_SECOND };
11 11  
12 12 // 退款订单扫描时间策略
13   - private final long[] refundTimeArray = { 10 * ONE_MINUTE };
  13 + private final long[] refundTimeArray = { ONE_MINUTE, 2 * ONE_MINUTE, 2 * ONE_MINUTE, 5 * ONE_MINUTE };
14 14  
15 15 @Override
16 16 public long nextPrepayScanTime(int times) {
... ...
cashier-shared/src/main/java/com/diligrp/cashier/shared/service/ThreadPoolService.java
1 1 package com.diligrp.cashier.shared.service;
2 2  
3   -import java.util.concurrent.ExecutorService;
4   -import java.util.concurrent.LinkedBlockingQueue;
5   -import java.util.concurrent.ThreadPoolExecutor;
6   -import java.util.concurrent.TimeUnit;
  3 +import java.util.concurrent.*;
7 4  
8 5 /**
9 6 * 请谨慎使用此线程池工具类,通常建议根据特定的使用场景设置线程池参数,不建议使用统一的线程池配置
10   - * JDK的线程池类并不能很好区分"计算密集型"和"IO密集型"任务类型,根据不同的任务类型去配置不同的参数
  7 + * JDK的线程池类并不能很好区分"计算密集型"和"IO密集型"任务类型,应该根据不同的任务类型去配置不同的参数
11 8 */
12 9 public final class ThreadPoolService {
13 10  
... ... @@ -15,7 +12,7 @@ public final class ThreadPoolService {
15 12  
16 13 private static final int CPU_MAX_POOL_SIZE = 100;
17 14  
18   - private static final int IO_MAX_POOL_SIZE = 1000;
  15 +// private static final int IO_MAX_POOL_SIZE = 1000;
19 16  
20 17 // CPU运算密集型任务的线程池实例
21 18 private static volatile ExecutorService cpuThreadPoll;
... ... @@ -32,11 +29,11 @@ public final class ThreadPoolService {
32 29 */
33 30 public static ExecutorService getCpuThreadPoll() {
34 31 if (cpuThreadPoll == null) {
  32 +
35 33 synchronized (ThreadPoolService.class) {
36 34 if (cpuThreadPoll == null) {
37   - cpuThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, CPU_MAX_POOL_SIZE,
38   - 20, TimeUnit.SECONDS, new LinkedBlockingQueue<>(100),
39   - new ThreadPoolExecutor.AbortPolicy());
  35 + cpuThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, CPU_MAX_POOL_SIZE, 20,
  36 + TimeUnit.SECONDS, new LinkedBlockingQueue<>(100), new LazyRejectedExecutionHandler());
40 37 }
41 38 }
42 39 }
... ... @@ -51,12 +48,29 @@ public final class ThreadPoolService {
51 48 if (ioThreadPoll == null) {
52 49 synchronized (ThreadPoolService.class) {
53 50 if (ioThreadPoll == null) {
54   - ioThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, IO_MAX_POOL_SIZE,
55   - 20, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000),
56   - new ThreadPoolExecutor.AbortPolicy());
  51 + ioThreadPoll = Executors.newVirtualThreadPerTaskExecutor();
  52 +
  53 +// ioThreadPoll = new ThreadPoolExecutor(CPU_CORE_NUM + 1, IO_MAX_POOL_SIZE, 20,
  54 +// TimeUnit.SECONDS, new LinkedBlockingQueue<>(1000), new LazyRejectedExecutionHandler());
57 55 }
58 56 }
59 57 }
60 58 return ioThreadPoll;
61 59 }
  60 +
  61 + private static class LazyRejectedExecutionHandler implements RejectedExecutionHandler {
  62 + @Override
  63 + public void rejectedExecution(Runnable task, ThreadPoolExecutor executor) {
  64 + boolean success = false;
  65 + try {
  66 + success = executor.getQueue().offer(task, 15, TimeUnit.SECONDS);
  67 + } catch (InterruptedException ex) {
  68 + Thread.currentThread().interrupt();
  69 + }
  70 +
  71 + if (!success) {
  72 + throw new RejectedExecutionException("task queue is full");
  73 + }
  74 + }
  75 + }
62 76 }
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/PaymentResultManager.java
... ... @@ -86,7 +86,7 @@ public class PaymentResultManager {
86 86 try {
87 87 listener.onEvent(refundEvent);
88 88 } catch (Exception ex) {
89   - LOG.error("Failed to notify trade refund result", ex);
  89 + LOG.error("Failed to notify payment refund result", ex);
90 90 }
91 91 }
92 92 }
... ... @@ -95,13 +95,13 @@ public class PaymentResultManager {
95 95 ThreadPoolService.getIoThreadPoll().submit(() -> {
96 96 try {
97 97 String payload = JsonUtils.toJsonString(refundResult);
98   - LOG.info("Notifying online trade refund result: {}", payload);
  98 + LOG.info("Notifying online payment refund result: {}", payload);
99 99 ServiceEndpointSupport.HttpResult httpResult = new NotifyHttpClient(uri).send(payload);
100 100 if (httpResult.statusCode != 200) {
101   - LOG.error("Failed to notify trade refund result");
  101 + LOG.error("Failed to notify payment refund result");
102 102 }
103 103 } catch (Exception ex) {
104   - LOG.error("Failed to notify trade refund result", ex);
  104 + LOG.error("Failed to notify payment refund result", ex);
105 105 }
106 106 });
107 107 }
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/TaskMessageConsumer.java
... ... @@ -35,7 +35,7 @@ public class TaskMessageConsumer {
35 35 ? properties.getContentEncoding() : StandardCharsets.UTF_8.name();
36 36 try {
37 37 String body = new String(packet, charSet);
38   - LOG.info("Receiving async delay task message: {}", body);
  38 + LOG.debug("Receiving async delay task message: {}", body);
39 39 TaskMessage task = TaskMessage.fromJson(body);
40 40 int times = NumberUtils.str2Int(task.getParams(), Integer.MAX_VALUE);
41 41 if (task.getType() == TaskMessage.TYPE_CASHIER_ORDER_SCAN) {
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/manager/TaskMessageSender.java
... ... @@ -19,11 +19,6 @@ public class TaskMessageSender {
19 19  
20 20 private static final Logger LOG = LoggerFactory.getLogger(TaskMessageSender.class);
21 21  
22   - private static final long ONE_MINUTE = 60 * 1000;
23   -
24   - private static final long TEN_MINUTES = 10 * ONE_MINUTE;
25   -
26   - private static final long ONE_SECOND = 1000;
27 22  
28 23 @Resource
29 24 private RabbitTemplate rabbitTemplate;
... ... @@ -33,7 +28,7 @@ public class TaskMessageSender {
33 28 */
34 29 public void sendDelayTaskMessage(TaskMessage task, long delayInMillis) {
35 30 if (delayInMillis < 0) {
36   - LOG.info("No need send scan order message: {}", task);
  31 + LOG.debug("No need send scan order message: {}", task);
37 32 return;
38 33 }
39 34  
... ... @@ -47,7 +42,7 @@ public class TaskMessageSender {
47 42 properties.setHeader("x-delay", String.valueOf(delayInMillis));
48 43 String payload = JsonUtils.toJsonString(task);
49 44 Message message = new Message(payload.getBytes(StandardCharsets.UTF_8), properties);
50   - LOG.info("Sending async delay task message: {}", task.getPayload());
  45 + LOG.debug("Sending async delay task message: {}", task.getPayload());
51 46 rabbitTemplate.send(Constants.PAYMENT_DELAY_EXCHANGE, Constants.PAYMENT_DELAY_KEY, message);
52 47 } catch (Exception ex) {
53 48 LOG.error("Failed to send async delay task message: {}", task.getPayload(), ex);
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierAssistantServiceImpl.java
... ... @@ -10,7 +10,9 @@ import com.diligrp.cashier.pipeline.service.IPaymentPipelineManager;
10 10 import com.diligrp.cashier.pipeline.type.PaymentState;
11 11 import com.diligrp.cashier.trade.Constants;
12 12 import com.diligrp.cashier.trade.dao.IOnlinePaymentDao;
  13 +import com.diligrp.cashier.trade.domain.TaskMessage;
13 14 import com.diligrp.cashier.trade.domain.TradeStateDTO;
  15 +import com.diligrp.cashier.trade.manager.TaskMessageSender;
14 16 import com.diligrp.cashier.trade.model.OnlinePayment;
15 17 import com.diligrp.cashier.trade.model.TradeOrder;
16 18 import com.diligrp.cashier.trade.service.ICashierAssistantService;
... ... @@ -45,11 +47,14 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
45 47 private TradeAssistantServiceImpl tradeAssistantService;
46 48  
47 49 @Resource
  50 + private TaskMessageSender taskMessageSender;
  51 +
  52 + @Resource
48 53 private RedissonClient redissonClient;
49 54  
50 55 @Override
51 56 public void scanCashierTradeOrder(String tradeId, int times) {
52   - LOG.debug("scanCashierTradeOrder{}: processing cashier trade order {}", times, tradeId);
  57 + LOG.info("scanCashierTradeOrder{}: processing cashier order {}", times, tradeId);
53 58 String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, tradeId);
54 59 RLock lock = redissonClient.getLock(lockKey);
55 60 try {
... ... @@ -64,12 +69,11 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
64 69 // 在线支付通道才能关闭订单, 园区卡支付不支持
65 70 if (pipeline instanceof OnlinePipeline<?> onlinePipeline) {
66 71 OnlinePrepayOrder order = new OnlinePrepayOrder(payment.getPaymentId(), payment.getOutTradeNo());
67   - // 微信服务商模式,还需子商户
68 72 OnlinePaymentResponse response = onlinePipeline.queryPrepayResponse(order);
69 73 if (!PaymentState.isFinished(response.getState().getCode())) {
70 74 try {
71 75 onlinePipeline.closePrepayOrder(order);
72   - LOG.info("scanCashierTradeOrder: close online prepay order {}", payment.getPaymentId());
  76 + LOG.debug("scanCashierTradeOrder: close online prepay order {}", payment.getPaymentId());
73 77 response = new OnlinePaymentResponse(response.getPaymentId(), response.getOutTradeNo(),
74 78 response.getOutPayType(), response.getPayerId(), response.getWhen(),
75 79 PaymentState.FAILED, "自动关闭超时的支付订单");
... ... @@ -85,7 +89,9 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
85 89 if (!TradeState.isFinished(trade.getState())) {
86 90 TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.CLOSED, trade.getVersion(), now);
87 91 tradeAssistantService.proceedTradeOrder(tradeStateDTO);
88   - LOG.info("scanCashierTradeOrder: close cashier trade order {}", tradeId);
  92 + LOG.debug("scanCashierTradeOrder: close cashier order {}", tradeId);
  93 + } else {
  94 + LOG.debug("scanCashierTradeOrder: cashier order {} already accomplished", trade.getTradeId());
89 95 }
90 96 } finally {
91 97 if (lock.isHeldByCurrentThread()) {
... ... @@ -96,10 +102,10 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
96 102  
97 103 @Override
98 104 public void scanCashierRefundOrder(String refundId, int times) {
99   - LOG.debug("scanCashierRefundOrder{}: processing online refund order {}", times, refundId);
  105 + LOG.info("scanCashierRefundOrder{}: processing cashier refund order {}", times, refundId);
100 106 OnlinePayment refund = tradeAssistantService.findByRefundId(refundId);
101 107 if (PaymentState.isFinished(refund.getState())) {
102   - LOG.debug("scanCashierRefundOrder{}: online refund order {} already accomplished", times, refundId);
  108 + LOG.debug("scanCashierRefundOrder{}: cashier refund order {} already accomplished", times, refundId);
103 109 return;
104 110 }
105 111  
... ... @@ -107,5 +113,10 @@ public class CashierAssistantServiceImpl implements ICashierAssistantService {
107 113 OnlineRefundOrder order = new OnlineRefundOrder(refundId, refund.getOutTradeNo());
108 114 OnlineRefundResponse response = pipeline.queryRefundResponse(order);
109 115 cashierPaymentService.notifyRefundResult(response);
  116 + if (!PaymentState.isFinished(response.getState().getCode())) {
  117 + long delay = pipeline.getTimeStrategy().nextRefundScanTime(times + 1);
  118 + TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, String.valueOf(times + 1));
  119 + taskMessageSender.sendDelayTaskMessage(message, delay);
  120 + }
110 121 }
111 122 }
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierPaymentServiceImpl.java
... ... @@ -5,6 +5,7 @@ import com.diligrp.cashier.assistant.service.impl.SnowflakeKeyManager;
5 5 import com.diligrp.cashier.pipeline.core.DiliCardPipeline;
6 6 import com.diligrp.cashier.pipeline.core.OnlinePipeline;
7 7 import com.diligrp.cashier.pipeline.core.PaymentPipeline;
  8 +import com.diligrp.cashier.pipeline.core.ScanTimeStrategy;
8 9 import com.diligrp.cashier.pipeline.domain.*;
9 10 import com.diligrp.cashier.pipeline.domain.card.CardPaymentRequest;
10 11 import com.diligrp.cashier.pipeline.domain.card.CardPaymentResponse;
... ... @@ -104,19 +105,19 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
104 105 /**
105 106 * 收银台支付
106 107 *
107   - * @param cashierPayment - 支付信息
  108 + * @param payment - 支付信息
108 109 * @return 支付状态
109 110 */
110 111 @Override
111 112 @Transactional(rollbackFor = Exception.class)
112   - public OnlinePaymentStatus doPayment(CashierPayment cashierPayment) {
  113 + public OnlinePaymentStatus doPayment(CashierPayment payment) {
113 114 // TODO: 接口防重复提交
114   - String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, cashierPayment.getTradeId());
  115 + String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, payment.getTradeId());
115 116 RLock lock = redissonClient.getLock(lockKey);
116 117 try {
117 118 boolean locked = lock.tryLock(Constants.TRADE_LOCK_TIMEOUT, TimeUnit.SECONDS);
118 119 if (locked) {
119   - TradeOrder trade = tradeAssistantService.findByTradeId(cashierPayment.getTradeId());
  120 + TradeOrder trade = tradeAssistantService.findByTradeId(payment.getTradeId());
120 121 CashierType cashierType = CashierType.getByCode(trade.getType());
121 122 if (TradeState.isFinished(trade.getState())) {
122 123 throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行支付, 交易订单已经完成");
... ... @@ -125,6 +126,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
125 126 if (cashierType != CashierType.MINIPRO) {
126 127 throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "系统当前不支持的此收银台类型");
127 128 }
  129 + LOG.info("Requesting cashier order payment: {}", payment.getTradeId());
128 130 // 关闭支付中的支付订单, 避免一个交易订单存在多笔支付订单, 造成重复支付
129 131 if (!tradeAssistantService.resetTradeOrder(trade)) {
130 132 throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行支付, 交易订单正在支付中");
... ... @@ -132,26 +134,26 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
132 134  
133 135 LocalDateTime now = LocalDateTime.now();
134 136 // 获取支付通道
135   - PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(
136   - cashierPayment.getPipelineId(), PaymentPipeline.class);
  137 + PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(payment.getPipelineId(), PaymentPipeline.class);
137 138 String paymentId = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID).nextId();
138 139 if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { // 在线支付通道
139 140 // 在线支付通道: 不同的收银台类型使用不同的支付方式(目前只支持小程序收银台)
140 141 // 小程序收银台将使用在线支付通道的小程序支付
141   - MiniProPrepayRequest request = new MiniProPaymentConverter(trade, paymentId, now).convert(cashierPayment);
  142 + MiniProPrepayRequest request = new MiniProPaymentConverter(trade, paymentId, now).convert(payment);
142 143 MiniProPrepayResponse response = onlinePipeline.sendMiniProPrepayRequest(request);
143 144 String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID);
144   - OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId())
  145 + OnlinePayment onlinePayment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId())
145 146 .type(TradeType.TRADE).paymentId(paymentId).channelId(onlinePipeline.supportedChannel())
146 147 .payType(PaymentType.MINI_PRO).pipelineId(onlinePipeline.pipelineId()).goods(trade.getGoods())
147 148 .amount(trade.getAmount()).payerId(request.getOpenId()).outTradeNo(response.getOutTradeNo())
148 149 .outPayType(OutPaymentType.NOP).finishTime(null).state(response.getState())
149 150 .notifyUrl(trade.getNotifyUrl()).description(null).version(0).createdTime(now).modifiedTime(now).build();
150   - onlinePaymentDao.insertOnlinePayment(payment);
  151 + onlinePaymentDao.insertOnlinePayment(onlinePayment);
  152 + LOG.debug("Cashier order payment result: {}:{}", response.getPaymentId(), response.getState().name());
151 153 return response;
152 154 } else if (pipeline instanceof DiliCardPipeline cardPipeline) { // 园区卡支付通道
153 155 // 园区卡支付通道: 所有的收银台类型使用的是同一种园区卡支付流程
154   - CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(cashierPayment);
  156 + CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(payment);
155 157 // 园区卡支付需要订单来源
156 158 request.attach("source", SourceType.getIfNonNull(trade.getSource()));
157 159 // 修改支付状态为支付中,防止重复支付
... ... @@ -160,14 +162,14 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
160 162 if (response.getState() == PaymentState.SUCCESS) {
161 163 // 园区卡支付通道outMchId为市场ID
162 164 String outMchId = request.getString(com.diligrp.cashier.pipeline.Constants.PARAM_MCH_ID);
163   - OnlinePayment payment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId())
  165 + OnlinePayment onlinePayment = OnlinePayment.builder().outMchId(outMchId).tradeId(trade.getTradeId())
164 166 .type(TradeType.TRADE).paymentId(paymentId).channelId(cardPipeline.supportedChannel())
165 167 .payType(PaymentType.DIRECT).pipelineId(cardPipeline.pipelineId()).goods(trade.getGoods())
166 168 .amount(trade.getAmount()).payerId(response.getPayerId()).outTradeNo(response.getOutTradeNo())
167 169 .outPayType(response.getOutPayType()).finishTime(response.getWhen()).state(response.getState())
168 170 .notifyUrl(trade.getNotifyUrl()).description(response.getMessage()).version(0)
169 171 .createdTime(now).modifiedTime(now).build();
170   - onlinePaymentDao.insertOnlinePayment(payment);
  172 + onlinePaymentDao.insertOnlinePayment(onlinePayment);
171 173  
172 174 TradeStateDTO tradeStateDTO = TradeStateDTO.of(trade.getTradeId(), TradeState.SUCCESS,
173 175 trade.getVersion(), now);
... ... @@ -178,6 +180,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
178 180 response.getPayerId(), response.getWhen(), response.getMessage());
179 181 paymentResultManager.notifyPaymentResult(trade.getNotifyUrl(), paymentResult, 500);
180 182 }
  183 + LOG.debug("Cashier order payment result: {}:{}", response.getPaymentId(), response.getState().name());
181 184 return response;
182 185 } else {
183 186 // 目前只有两类支付通道: CardPipeline和OnlinePipeline, 程序逻辑不应该到达此代码块
... ... @@ -205,10 +208,10 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
205 208 public void notifyPaymentResponse(OnlinePaymentResponse response) {
206 209 OnlinePayment payment = tradeAssistantService.findByPaymentId(response.getPaymentId());
207 210 if (PaymentState.isFinished(payment.getState())) {
208   - LOG.warn("Duplicate process payment response: [{}:{}]", payment.getPaymentId(), response.getState());
  211 + LOG.warn("Duplicate process cashier payment response: [{}:{}]", payment.getPaymentId(), response.getState().name());
209 212 return;
210 213 }
211   - LOG.info("Processing payment response: [{},{}]", payment.getPaymentId(), response.getState());
  214 + LOG.info("Processing cashier payment response: [{},{}]", payment.getPaymentId(), response.getState().name());
212 215  
213 216 if (PaymentState.isFinished(response.getState().getCode())) {
214 217 LocalDateTime now = LocalDateTime.now();
... ... @@ -261,6 +264,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
261 264 throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "关闭交易订单失败: 无效的订单状态");
262 265 }
263 266  
  267 + LOG.info("Requesting close cashier trade order: {}", tradeId);
264 268 LocalDateTime now = LocalDateTime.now();
265 269 // 获取所有支付记录
266 270 List<OnlinePayment> onlinePayments = onlinePaymentDao.listOnlinePayments(trade.getTradeId(),
... ... @@ -326,6 +330,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
326 330 TradeType.TRADE.getCode(), PaymentState.SUCCESS.getCode()).stream().findFirst()
327 331 .orElseThrow(() -> new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行交易退款: 无支付信息"));
328 332  
  333 + LOG.info("Requesting cashier payment refund: {}", request.getTradeId());
329 334 LocalDateTime now = LocalDateTime.now().withNano(0);
330 335 KeyGenerator refundIdKey = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID);
331 336 String refundId = refundIdKey.nextId();
... ... @@ -341,6 +346,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
341 346 throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不支持的支付通道");
342 347 }
343 348  
  349 + LOG.debug("Cashier payment refund result: [{}:{}]", trade.getTradeId(), response.getState().name());
344 350 OnlinePayment refund = OnlinePayment.builder().outMchId(payment.getOutMchId()).tradeId(payment.getTradeId())
345 351 .type(TradeType.REFUND).paymentId(refundId).channelId(payment.getChannelId())
346 352 .payType(payment.getPayType()).pipelineId(payment.getPipelineId()).goods(payment.getGoods() + "-退款")
... ... @@ -356,8 +362,11 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
356 362 tradeAssistantService.proceedTradeOrder(tradeState);
357 363 } else if (!PaymentState.isFinished(response.getState().getCode())) {
358 364 // 固定周期后,查询退款状态,根据状态完成退款订单
359   - TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, "1");
360   - taskMessageSender.sendDelayTaskMessage(message, trade.getTimeout() * 1000);
  365 + if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { // 只有在线支付通道允许查询退款状态
  366 + long delay = onlinePipeline.getTimeStrategy().nextRefundScanTime(1);
  367 + TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, "1");
  368 + taskMessageSender.sendDelayTaskMessage(message, delay);
  369 + }
361 370 }
362 371  
363 372 return new OnlineRefundResult(refundId, payment.getPaymentId(), response.getState().getCode(),
... ... @@ -369,14 +378,14 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService {
369 378 public void notifyRefundResult(OnlineRefundResponse response) {
370 379 OnlinePayment refund = tradeAssistantService.findByRefundId(response.getRefundId());
371 380 if (PaymentState.isFinished(refund.getState())) {
372   - LOG.warn("Duplicate process online refund order[{}:{}]", response.getRefundId(), response.getState());
  381 + LOG.warn("Duplicate process cashier refund response: [{}:{}]", response.getRefundId(), response.getState().name());
373 382 return;
374 383 }
375 384 if (!PaymentState.isFinished(response.getState().getCode())) {
376   - LOG.warn("Ignore online refund order[{}:{}]", response.getRefundId(), response.getState());
  385 + LOG.warn("Ignore cashier refund response: [{}:{}]", response.getRefundId(), response.getState().name());
377 386 return;
378 387 }
379   - LOG.info("Processing online refund order[{}:{}]", response.getRefundId(), response.getState());
  388 + LOG.info("Processing cashier refund response: [{}:{}]", response.getRefundId(), response.getState().name());
380 389  
381 390 LocalDateTime now = LocalDateTime.now();
382 391 TradeOrder trade = tradeAssistantService.findByTradeId(refund.getTradeId());
... ...
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/TradeAssistantServiceImpl.java
... ... @@ -65,7 +65,7 @@ public class TradeAssistantServiceImpl implements ITradeAssistantService {
65 65 List<OnlinePayment> onlinePayments = onlinePaymentDao.listOnlinePayments(trade.getTradeId(), TradeType.TRADE.getCode(), null);
66 66 for (OnlinePayment payment : onlinePayments) {
67 67 if (!PaymentState.isFinished(payment.getState())) {
68   - LOG.info("Trying to close payment order in process: {}", payment.getPaymentId());
  68 + LOG.debug("Trying to close payment order in process: {}", payment.getPaymentId());
69 69 PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(payment.getPipelineId(), PaymentPipeline.class);
70 70 if (pipeline instanceof OnlinePipeline<?> onlinePipeline) {
71 71 // 理论上只存在一条支付中的支付记录,否则后面的支付通道关闭失败时,会回滚前面支付记录的状态修改
... ...