| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136 |
- package com.ruoyi.app.task;
- import com.ruoyi.app.pay.LinePayRefundService;
- import com.ruoyi.app.pay.LinePayCancellationCompensationService;
- import com.ruoyi.app.pay.LinePayService;
- import com.ruoyi.app.pay.LinePayOfflineService;
- import com.ruoyi.system.domain.PosOrderLinePayment;
- import com.ruoyi.system.domain.PosOrderLineRefund;
- import com.ruoyi.system.service.IPosOrderLinePaymentService;
- import com.ruoyi.system.service.IPosOrderLineRefundService;
- import org.redisson.api.RLock;
- import org.redisson.api.RedissonClient;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.scheduling.annotation.Scheduled;
- import org.springframework.stereotype.Component;
- import org.springframework.beans.factory.annotation.Value;
- import java.util.Date;
- import java.util.List;
- import java.util.UUID;
- /** Periodically retrieves LINE payment/refund facts and resumes recoverable state. */
- @Component
- public class LinePayReconcileTask {
- private static final Logger log = LoggerFactory.getLogger(LinePayReconcileTask.class);
- private static final String LOCK_KEY = "lock:line-pay:reconcile";
- @Value("${line-pay.reconcile.batch-size:20}")
- private int batchSize = 20;
- @Value("${line-pay.reconcile.row-lease-seconds:120}")
- private long rowLeaseSeconds = 120L;
- @Value("${line-pay.reconcile.round-budget-seconds:45}")
- private long roundBudgetSeconds = 45L;
- private final IPosOrderLinePaymentService paymentService;
- private final IPosOrderLineRefundService refundService;
- private final LinePayService linePayService;
- private final LinePayOfflineService linePayOfflineService;
- private final LinePayRefundService linePayRefundService;
- private final RedissonClient redissonClient;
- private final LinePayCancellationCompensationService cancellationCompensationService;
- public LinePayReconcileTask(IPosOrderLinePaymentService paymentService,
- IPosOrderLineRefundService refundService,
- LinePayService linePayService,
- LinePayRefundService linePayRefundService,
- RedissonClient redissonClient,
- LinePayCancellationCompensationService cancellationCompensationService) {
- this(paymentService, refundService, linePayService, null, linePayRefundService,
- redissonClient, cancellationCompensationService);
- }
- @org.springframework.beans.factory.annotation.Autowired
- public LinePayReconcileTask(IPosOrderLinePaymentService paymentService,
- IPosOrderLineRefundService refundService,
- LinePayService linePayService,
- LinePayOfflineService linePayOfflineService,
- LinePayRefundService linePayRefundService,
- RedissonClient redissonClient,
- LinePayCancellationCompensationService cancellationCompensationService) {
- this.paymentService = paymentService;
- this.refundService = refundService;
- this.linePayService = linePayService;
- this.linePayOfflineService = linePayOfflineService;
- this.linePayRefundService = linePayRefundService;
- this.redissonClient = redissonClient;
- this.cancellationCompensationService = cancellationCompensationService;
- }
- @Scheduled(fixedDelayString = "${line-pay.reconcile.fixed-delay-ms:60000}",
- initialDelayString = "${line-pay.reconcile.initial-delay-ms:60000}")
- public void reconcile() {
- RLock lock = redissonClient.getLock(LOCK_KEY);
- if (!lock.tryLock()) {
- return;
- }
- try {
- reconcileRound();
- } catch (Exception exception) {
- log.error("LINE Pay scheduled reconcile failed", exception);
- } finally {
- if (lock.isHeldByCurrentThread()) {
- lock.unlock();
- }
- }
- }
- private void reconcileRound() {
- long started = System.currentTimeMillis();
- Date now = new Date(started);
- List<PosOrderLinePayment> payments = paymentService.scanDue(now, batchSize);
- for (PosOrderLinePayment payment : payments) {
- if (roundBudgetExceeded(started)) {
- break;
- }
- String owner = "TASK-" + UUID.randomUUID();
- if (paymentService.claimReconcileLease(payment.getId(), payment.getVersion(), owner,
- new Date(System.currentTimeMillis() + rowLeaseSeconds * 1000L), new Date()) != 1) {
- continue;
- }
- try {
- if ("OFFLINE".equals(payment.getPaymentMode()) && linePayOfflineService != null) {
- linePayOfflineService.reconcilePayment(payment.getId(), "TASK");
- } else {
- linePayService.reconcilePayment(payment.getId(), "TASK", owner);
- }
- } catch (Exception exception) {
- log.warn("LINE Pay payment reconcile failed, paymentId={}", payment.getId());
- }
- }
- repairCancelledPayments();
- List<PosOrderLineRefund> refunds = refundService.scanDue(new Date(), batchSize);
- long refundStarted = System.currentTimeMillis();
- boolean processedRefund = false;
- for (PosOrderLineRefund refund : refunds) {
- if (processedRefund && roundBudgetExceeded(refundStarted)) {
- break;
- }
- try {
- linePayRefundService.requestFullRefund(refund.getPaymentId(), "TASK");
- } catch (Exception exception) {
- log.warn("LINE Pay refund reconcile failed, paymentId={}", refund.getPaymentId());
- }
- processedRefund = true;
- }
- }
- private void repairCancelledPayments() {
- cancellationCompensationService.createMissingRefundIntents(
- paymentService.getCancelledPaidWithoutRefund(batchSize));
- }
- private boolean roundBudgetExceeded(long started) {
- return System.currentTimeMillis() - started >= roundBudgetSeconds * 1000L;
- }
- }
|