Commit 05f0cda49f2cc6064025a4c98a567ef560b660ff
1 parent
9ea129ba
issue fixed after prod testing
Showing
2 changed files
with
65 additions
and
54 deletions
cashier-pipeline/src/main/java/com/diligrp/cashier/pipeline/client/CardPaymentHttpClient.java
| @@ -17,10 +17,7 @@ import org.slf4j.Logger; | @@ -17,10 +17,7 @@ import org.slf4j.Logger; | ||
| 17 | import org.slf4j.LoggerFactory; | 17 | import org.slf4j.LoggerFactory; |
| 18 | 18 | ||
| 19 | import java.time.LocalDateTime; | 19 | import java.time.LocalDateTime; |
| 20 | -import java.util.ArrayList; | ||
| 21 | -import java.util.LinkedHashMap; | ||
| 22 | -import java.util.List; | ||
| 23 | -import java.util.Map; | 20 | +import java.util.*; |
| 24 | 21 | ||
| 25 | public class CardPaymentHttpClient extends ServiceEndpointSupport { | 22 | public class CardPaymentHttpClient extends ServiceEndpointSupport { |
| 26 | 23 | ||
| @@ -47,6 +44,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { | @@ -47,6 +44,7 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { | ||
| 47 | public CardPaymentResponse sendPaymentRequest(CardPaymentRequest request) { | 44 | public CardPaymentResponse sendPaymentRequest(CardPaymentRequest request) { |
| 48 | String uri = String.format("%s%s", baseUri, PAYMENT_URL); | 45 | String uri = String.format("%s%s", baseUri, PAYMENT_URL); |
| 49 | SourceType sourceType = request.getObject("source", SourceType.class); | 46 | SourceType sourceType = request.getObject("source", SourceType.class); |
| 47 | + String attach = request.getString("attach"); | ||
| 50 | Map<String, Object> params = new LinkedHashMap<>(); | 48 | Map<String, Object> params = new LinkedHashMap<>(); |
| 51 | params.put("mchId", outMchId); // 市场ID | 49 | params.put("mchId", outMchId); // 市场ID |
| 52 | params.put("accountId", accountId); // 市场ID | 50 | params.put("accountId", accountId); // 市场ID |
| @@ -58,10 +56,13 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { | @@ -58,10 +56,13 @@ public class CardPaymentHttpClient extends ServiceEndpointSupport { | ||
| 58 | params.put("outTradeNo", request.getPaymentId()); | 56 | params.put("outTradeNo", request.getPaymentId()); |
| 59 | params.put("goodsDesc", request.getGoods()); | 57 | params.put("goodsDesc", request.getGoods()); |
| 60 | params.put("description", request.getDescription()); | 58 | params.put("description", request.getDescription()); |
| 61 | - if (sourceType != null) { | 59 | + if (Objects.nonNull(sourceType)) { |
| 62 | params.put("sourceId", sourceType.getCode()); | 60 | params.put("sourceId", sourceType.getCode()); |
| 63 | params.put("sourceName", sourceType.getName()); | 61 | params.put("sourceName", sourceType.getName()); |
| 64 | } | 62 | } |
| 63 | + if (Objects.nonNull(attach)) { | ||
| 64 | + params.put("attach", attach); | ||
| 65 | + } | ||
| 65 | String payload = JsonUtils.toJsonString(params); | 66 | String payload = JsonUtils.toJsonString(params); |
| 66 | 67 | ||
| 67 | LOG.info("Sending card payment request: {}\n{}", request.getPaymentId(), payload); | 68 | LOG.info("Sending card payment request: {}\n{}", request.getPaymentId(), payload); |
cashier-trade/src/main/java/com/diligrp/cashier/trade/service/impl/CashierPaymentServiceImpl.java
| @@ -178,6 +178,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { | @@ -178,6 +178,7 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { | ||
| 178 | CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(payment); | 178 | CardPaymentRequest request = new CardPaymentConverter(trade, paymentId, now).convert(payment); |
| 179 | // 园区卡支付需要订单来源 | 179 | // 园区卡支付需要订单来源 |
| 180 | request.attach("source", SourceType.getIfNonNull(trade.getSource())); | 180 | request.attach("source", SourceType.getIfNonNull(trade.getSource())); |
| 181 | + request.attach("attach", trade.getAttach()); | ||
| 181 | // 修改支付状态为支付中,防止重复支付 | 182 | // 修改支付状态为支付中,防止重复支付 |
| 182 | CardPaymentResponse response = cardPipeline.sendPaymentRequest(request); | 183 | CardPaymentResponse response = cardPipeline.sendPaymentRequest(request); |
| 183 | // 支付成功插入支付记录并修改交易订单状态,失败可以继续支付 | 184 | // 支付成功插入支付记录并修改交易订单状态,失败可以继续支付 |
| @@ -339,59 +340,68 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { | @@ -339,59 +340,68 @@ public class CashierPaymentServiceImpl implements ICashierPaymentService { | ||
| 339 | @Override | 340 | @Override |
| 340 | @Transactional(rollbackFor = Exception.class) | 341 | @Transactional(rollbackFor = Exception.class) |
| 341 | public OnlineRefundResult sendRefundRequest(OnlineRefundDTO request) { | 342 | public OnlineRefundResult sendRefundRequest(OnlineRefundDTO request) { |
| 342 | - TradeOrder trade = tradeAssistantService.findByTradeId(request.getTradeId()); | ||
| 343 | - if (!TradeState.forRefund(trade.getState())) { | ||
| 344 | - throw new TradePaymentException(ErrorCode.INVALID_OBJECT_STATE, "不能进行交易退款: 无效的交易状态"); | ||
| 345 | - } | ||
| 346 | - if (trade.getAmount() < request.getAmount()) { | ||
| 347 | - throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "申请退费金额超过原支付金额"); | ||
| 348 | - } | ||
| 349 | - // 理论上只会存在一条支付完成的支付订单 | ||
| 350 | - OnlinePayment payment = onlinePaymentDao.listOnlinePayments(trade.getTradeId(), | ||
| 351 | - TradeType.TRADE.getCode(), PaymentState.SUCCESS.getCode()).stream().findFirst() | ||
| 352 | - .orElseThrow(() -> new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行交易退款: 无支付信息")); | ||
| 353 | - | ||
| 354 | - LOG.info("Requesting cashier payment refund: {}", request.getTradeId()); | ||
| 355 | - LocalDateTime now = LocalDateTime.now().withNano(0); | ||
| 356 | - KeyGenerator refundIdKey = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID); | ||
| 357 | - String refundId = refundIdKey.nextId(); | ||
| 358 | - PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(payment.getPipelineId(), PaymentPipeline.class); | ||
| 359 | - OnlineRefundRequest refundRequest = OnlineRefundRequest.of(refundId, payment.getPaymentId(), payment.getOutTradeNo(), | ||
| 360 | - trade.getMaxAmount(), request.getAmount(), request.getDescription(), now); | ||
| 361 | - OnlineRefundResponse response; | ||
| 362 | - if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { | ||
| 363 | - response = onlinePipeline.sendRefundRequest(refundRequest); | ||
| 364 | - } else if (pipeline instanceof DiliCardPipeline cardPipeline) { | ||
| 365 | - response = cardPipeline.sendRefundRequest(refundRequest); | ||
| 366 | - } else { | ||
| 367 | - throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不支持的支付通道"); | ||
| 368 | - } | 343 | + String lockKey = String.format(Constants.TRADE_LOCK_REDIS_KEY, request.getTradeId()); |
| 344 | + RLock lock = redissonClient.getLock(lockKey); | ||
| 345 | + try { | ||
| 346 | + lock.lock(); | ||
| 347 | + TradeOrder trade = tradeAssistantService.findByTradeId(request.getTradeId()); | ||
| 348 | + if (!TradeState.forRefund(trade.getState())) { | ||
| 349 | + throw new TradePaymentException(ErrorCode.INVALID_OBJECT_STATE, "不能进行交易退款: 无效的交易状态"); | ||
| 350 | + } | ||
| 351 | + if (trade.getAmount() < request.getAmount()) { | ||
| 352 | + throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "申请退费金额超过原支付金额"); | ||
| 353 | + } | ||
| 354 | + // 理论上只会存在一条支付完成的支付订单 | ||
| 355 | + OnlinePayment payment = onlinePaymentDao.listOnlinePayments(trade.getTradeId(), | ||
| 356 | + TradeType.TRADE.getCode(), PaymentState.SUCCESS.getCode()).stream().findFirst() | ||
| 357 | + .orElseThrow(() -> new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不能进行交易退款: 无支付信息")); | ||
| 358 | + | ||
| 359 | + LOG.info("Requesting cashier payment refund: {}", request.getTradeId()); | ||
| 360 | + LocalDateTime now = LocalDateTime.now().withNano(0); | ||
| 361 | + KeyGenerator refundIdKey = snowflakeKeyManager.getKeyGenerator(SnowflakeKey.PAYMENT_ID); | ||
| 362 | + String refundId = refundIdKey.nextId(); | ||
| 363 | + PaymentPipeline<?> pipeline = paymentPipelineManager.findPipelineById(payment.getPipelineId(), PaymentPipeline.class); | ||
| 364 | + OnlineRefundRequest refundRequest = OnlineRefundRequest.of(refundId, payment.getPaymentId(), payment.getOutTradeNo(), | ||
| 365 | + trade.getMaxAmount(), request.getAmount(), request.getDescription(), now); | ||
| 366 | + OnlineRefundResponse response; | ||
| 367 | + if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { | ||
| 368 | + response = onlinePipeline.sendRefundRequest(refundRequest); | ||
| 369 | + } else if (pipeline instanceof DiliCardPipeline cardPipeline) { | ||
| 370 | + response = cardPipeline.sendRefundRequest(refundRequest); | ||
| 371 | + } else { | ||
| 372 | + throw new TradePaymentException(ErrorCode.OPERATION_NOT_ALLOWED, "不支持的支付通道"); | ||
| 373 | + } | ||
| 369 | 374 | ||
| 370 | - LOG.debug("Cashier payment refund result: [{}:{}]", trade.getTradeId(), response.getState().name()); | ||
| 371 | - OnlinePayment refund = OnlinePayment.builder().outMchId(payment.getOutMchId()).tradeId(payment.getTradeId()) | ||
| 372 | - .type(TradeType.REFUND).paymentId(refundId).channelId(payment.getChannelId()) | ||
| 373 | - .payType(payment.getPayType()).pipelineId(payment.getPipelineId()).goods(payment.getGoods() + "-退款") | ||
| 374 | - .amount(request.getAmount()).objectId(payment.getPaymentId()).payerId(payment.getPayerId()) | ||
| 375 | - .outTradeNo(response.getOutTradeNo()).outPayType(payment.getOutPayType()).finishTime(response.getWhen()) | ||
| 376 | - .state(response.getState()).notifyUrl(request.getNotifyUrl()).description(request.getDescription()) | ||
| 377 | - .version(0).createdTime(now).modifiedTime(now).build(); | ||
| 378 | - onlinePaymentDao.insertOnlinePayment(refund); | 375 | + LOG.debug("Cashier payment refund result: [{}:{}]", trade.getTradeId(), response.getState().name()); |
| 376 | + OnlinePayment refund = OnlinePayment.builder().outMchId(payment.getOutMchId()).tradeId(payment.getTradeId()) | ||
| 377 | + .type(TradeType.REFUND).paymentId(refundId).channelId(payment.getChannelId()) | ||
| 378 | + .payType(payment.getPayType()).pipelineId(payment.getPipelineId()).goods(payment.getGoods() + "-退款") | ||
| 379 | + .amount(request.getAmount()).objectId(payment.getPaymentId()).payerId(payment.getPayerId()) | ||
| 380 | + .outTradeNo(response.getOutTradeNo()).outPayType(payment.getOutPayType()).finishTime(response.getWhen()) | ||
| 381 | + .state(response.getState()).notifyUrl(request.getNotifyUrl()).description(request.getDescription()) | ||
| 382 | + .version(0).createdTime(now).modifiedTime(now).build(); | ||
| 383 | + onlinePaymentDao.insertOnlinePayment(refund); | ||
| 384 | + | ||
| 385 | + if (response.getState() == PaymentState.SUCCESS) { | ||
| 386 | + Long newAmount = trade.getAmount() - refund.getAmount(); | ||
| 387 | + TradeStateDTO tradeState = TradeStateDTO.of(trade.getTradeId(), newAmount, TradeState.REFUND, trade.getVersion(), now); | ||
| 388 | + tradeAssistantService.proceedTradeOrder(tradeState); | ||
| 389 | + } else if (!PaymentState.isFinished(response.getState().getCode())) { | ||
| 390 | + // 固定周期后,查询退款状态,根据状态完成退款订单 | ||
| 391 | + if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { // 只有在线支付通道允许查询退款状态 | ||
| 392 | + Duration duration = onlinePipeline.getTimeStrategy().nextRefundScanTime(1); | ||
| 393 | + TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, "1"); | ||
| 394 | + taskMessageSender.sendDelayTaskMessage(message, duration); | ||
| 395 | + } | ||
| 396 | + } | ||
| 379 | 397 | ||
| 380 | - if (response.getState() == PaymentState.SUCCESS) { | ||
| 381 | - Long newAmount = trade.getAmount() - refund.getAmount(); | ||
| 382 | - TradeStateDTO tradeState = TradeStateDTO.of(trade.getTradeId(), newAmount, TradeState.REFUND, trade.getVersion(), now); | ||
| 383 | - tradeAssistantService.proceedTradeOrder(tradeState); | ||
| 384 | - } else if (!PaymentState.isFinished(response.getState().getCode())) { | ||
| 385 | - // 固定周期后,查询退款状态,根据状态完成退款订单 | ||
| 386 | - if (pipeline instanceof OnlinePipeline<?> onlinePipeline) { // 只有在线支付通道允许查询退款状态 | ||
| 387 | - Duration duration = onlinePipeline.getTimeStrategy().nextRefundScanTime(1); | ||
| 388 | - TaskMessage message = new TaskMessage(TaskMessage.TYPE_CASHIER_REFUND_SCAN, refundId, "1"); | ||
| 389 | - taskMessageSender.sendDelayTaskMessage(message, duration); | 398 | + return new OnlineRefundResult(refundId, payment.getPaymentId(), response.getState().getCode(), |
| 399 | + response.getWhen(), response.getMessage()); | ||
| 400 | + } finally { | ||
| 401 | + if (lock.isHeldByCurrentThread()) { | ||
| 402 | + lock.unlock(); | ||
| 390 | } | 403 | } |
| 391 | } | 404 | } |
| 392 | - | ||
| 393 | - return new OnlineRefundResult(refundId, payment.getPaymentId(), response.getState().getCode(), | ||
| 394 | - response.getWhen(), response.getMessage()); | ||
| 395 | } | 405 | } |
| 396 | 406 | ||
| 397 | @Override | 407 | @Override |