diff --git a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java index a0b5dbfc..a4feff01 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/PaymentInfo.java @@ -22,6 +22,8 @@ public class PaymentInfo extends BaseEntity{ * paid and liquidated means the refund request has been executed. * expired means the request has been rejected. * wait means the request is still under processing. + * ------------------------------------------------- + * 退款:Partial refund 部分退款; Refunded 全部退款 */ private String tradeState;//交易状态 diff --git a/src/main/java/com/ai/da/mapper/primary/entity/RefundInfo.java b/src/main/java/com/ai/da/mapper/primary/entity/RefundInfo.java index 5349fd89..b239baaa 100644 --- a/src/main/java/com/ai/da/mapper/primary/entity/RefundInfo.java +++ b/src/main/java/com/ai/da/mapper/primary/entity/RefundInfo.java @@ -13,11 +13,14 @@ public class RefundInfo extends BaseEntity{ private String refundId;//支付系统退款单号(微信) + // 退款必定对应一次具体的收费款项 + private String chargeId; + // private Integer totalFee;//原订单金额(分) private Float totalFee;//原订单金额(分) // private Integer refund;//退款金额(分) - private Float refund;//退款金额(分) + private Float refund;//退款金额(元) private String reason;//退款原因 diff --git a/src/main/java/com/ai/da/service/PaymentInfoService.java b/src/main/java/com/ai/da/service/PaymentInfoService.java index c0434e94..a9ef0453 100644 --- a/src/main/java/com/ai/da/service/PaymentInfoService.java +++ b/src/main/java/com/ai/da/service/PaymentInfoService.java @@ -34,4 +34,6 @@ public interface PaymentInfoService extends IService { PageBaseResponse getPaymentInfo(QueryPageByTimeDTO queryPageByTimeDTO); List getPaymentInfoByPromCode(Long accountId, String promCode); + + PaymentInfo updatePaymentRefundStatus(Charge charge); } diff --git a/src/main/java/com/ai/da/service/RefundInfoService.java b/src/main/java/com/ai/da/service/RefundInfoService.java index 5cfeca4c..d1cb0fe7 100644 --- a/src/main/java/com/ai/da/service/RefundInfoService.java +++ b/src/main/java/com/ai/da/service/RefundInfoService.java @@ -3,6 +3,8 @@ package com.ai.da.service; import com.ai.da.mapper.primary.entity.RefundInfo; import com.baomidou.mybatisplus.extension.service.IService; +import com.stripe.model.Charge; +import com.stripe.model.Refund; import java.util.List; @@ -19,4 +21,13 @@ public interface RefundInfoService extends IService { void updateRefundForAliPay(String refundNo, String content, String refundStatus); void updateRefundForPayPal(Long id, String refundId, String content, String refundStatus); + + List getByChargeId(String chargeId); + + RefundInfo createRefundForStripe(Refund refund); + + RefundInfo updateRefundStatusForStripe(Refund refund); + + RefundInfo updateRefundForStripe(Charge charge); + } diff --git a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java index d85d3725..355e29ac 100644 --- a/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/PaymentInfoServiceImpl.java @@ -435,4 +435,28 @@ public class PaymentInfoServiceImpl extends ServiceImpl getPaymentInfoByPromCode(Long accountId, String promCode){ return baseMapper.selectPaidPaymentsByAccountAndPromotion(accountId, promCode); } + + public PaymentInfo updatePaymentRefundStatus(Charge charge){ + // 判断当前退款是部分退款还是全部退款 + QueryWrapper qw = new QueryWrapper<>(); + qw.eq("transaction_id", charge.getInvoice()); + PaymentInfo paymentInfo = baseMapper.selectOne(qw); + if (Objects.nonNull(paymentInfo)){ + String status ; + if (Objects.equals(charge.getAmount(), charge.getAmountRefunded())){ + status = "Refunded"; + }else if (charge.getAmount() > charge.getAmountRefunded()){ + status = "Partial refund"; + }else { + status = "Refund Exception"; + log.warn("{}, 退款金额高于付款金额, ChargeId为:{}", status, charge.getId()); + } + if (!paymentInfo.getTradeState().equals(status)){ + paymentInfo.setTradeState(status); + paymentInfo.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(paymentInfo); + } + } + return null; + } } diff --git a/src/main/java/com/ai/da/service/impl/RefundInfoServiceImpl.java b/src/main/java/com/ai/da/service/impl/RefundInfoServiceImpl.java index ff1db544..cfc82fef 100644 --- a/src/main/java/com/ai/da/service/impl/RefundInfoServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/RefundInfoServiceImpl.java @@ -10,14 +10,16 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.google.gson.Gson; +import com.stripe.model.Charge; +import com.stripe.model.Refund; +import io.netty.util.internal.StringUtil; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.time.Duration; import java.time.Instant; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.time.LocalDateTime; +import java.util.*; @Service public class RefundInfoServiceImpl extends ServiceImpl implements RefundInfoService { @@ -170,4 +172,63 @@ public class RefundInfoServiceImpl extends ServiceImpl getByChargeId(String chargeId){ + List refundInfoList = baseMapper.selectList(new QueryWrapper().eq("charge_id", chargeId)); + // 判断当前已退款的金额是否全部退完(针对多次部分退款的情况) + if (refundInfoList.isEmpty()){ + return new ArrayList<>(); + }else { + return refundInfoList; + } + } + + public RefundInfo getByRefundId(String refundId){ + return baseMapper.selectOne(new QueryWrapper().eq("refund_id", refundId)); + } + + public RefundInfo createRefundForStripe(Refund refund){ + // 先确认这个回调是否已经被记录 + RefundInfo refundInfo = getByRefundId(refund.getId()); + if (Objects.isNull(refundInfo)){ + refundInfo = new RefundInfo(); + refundInfo.setRefundId(refund.getId()); + refundInfo.setChargeId(refund.getCharge()); + refundInfo.setRefund(refund.getAmount() / 100f); + refundInfo.setReason(refund.getReason()); + refundInfo.setRefundStatus(refund.getStatus()); + refundInfo.setCreateTime(LocalDateTime.now()); + baseMapper.insert(refundInfo); + } + return refundInfo; + } + + public RefundInfo updateRefundStatusForStripe(Refund refund){ + RefundInfo refundInfo = getByRefundId(refund.getId()); + if (Objects.isNull(refundInfo)){ + return null; + } + if (!refundInfo.getRefundStatus().equals(refund.getStatus())){ + refundInfo.setRefundStatus(refund.getStatus()); + refundInfo.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(refundInfo); + } + return refundInfo; + } + + public RefundInfo updateRefundForStripe(Charge charge){ + List refundInfoList = getByChargeId(charge.getId()); + if (!refundInfoList.isEmpty()){ + RefundInfo refundInfo = refundInfoList.get(refundInfoList.size() - 1); + if (StringUtil.isNullOrEmpty(refundInfo.getOrderNo())){ + String orderNo = charge.getDescription().replace("AiDA - ", ""); + refundInfo.setOrderNo(orderNo); + refundInfo.setTotalFee(charge.getAmount() / 100f); + refundInfo.setUpdateTime(LocalDateTime.now()); + baseMapper.updateById(refundInfo); + return refundInfo; + } + } + return null; + } } diff --git a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java index c83907f0..e7bf9780 100644 --- a/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java +++ b/src/main/java/com/ai/da/service/impl/StripeServiceImpl.java @@ -430,6 +430,26 @@ public class StripeServiceImpl implements StripeService { orderInfo.setOrderStatus(OrderStatusEnum.SUCCESS.getType()); orderInfo.setNote(""); orderInfoService.updateById(orderInfo); + }else if (event.getType().equals("charge.refunded")){ + // 更新退款信息 + RefundInfo refundInfo = refundInfoService.updateRefundForStripe(charge); + // 更新 t_payment_info的支付状态 + if (Objects.nonNull(refundInfo)){ + paymentInfoService.updatePaymentRefundStatus(charge); + } + } + }else if (stripeObject instanceof Refund){ + Refund refund = (Refund) stripeObject; + if (event.getType().equals("refund.created")){ + // 新增退款信息 + refundInfoService.createRefundForStripe(refund); + }else if (event.getType().equals("refund.updated")){ + // 根据***id更新退款记录信息 + RefundInfo refundInfo = refundInfoService.updateRefundStatusForStripe(refund); + if (Objects.isNull(refundInfo)){ + // 等事件先创建,再更新。回调事件的顺序随机 + response = false; + } } } log.info("回调事件 {} 处理完成", event.getType());