|
|
@@ -0,0 +1,215 @@
|
|
|
+package com.cyksj.service.order.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.alipay.api.AlipayClient;
|
|
|
+import com.alipay.api.domain.AlipayTradeRefundModel;
|
|
|
+import com.alipay.api.request.AlipayTradeRefundRequest;
|
|
|
+import com.alipay.api.response.AlipayTradeRefundResponse;
|
|
|
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
+import com.cyksj.common.exception.BusinessRuntimeException;
|
|
|
+import com.cyksj.common.util.Codec;
|
|
|
+import com.cyksj.config.WeChatConfig;
|
|
|
+import com.cyksj.config.zfb.AliPayClientFactory;
|
|
|
+import com.cyksj.mapper.OrderDonMapper;
|
|
|
+import com.cyksj.mapper.PaypalPayConfigMapper;
|
|
|
+import com.cyksj.mapper.RefundOrderDonMapper;
|
|
|
+import com.cyksj.mapper.StripePayConfigMapper;
|
|
|
+import com.cyksj.mapper.channel.ShopConfigMapper;
|
|
|
+import com.cyksj.model.entity.*;
|
|
|
+import com.cyksj.model.request.OrderRefundReq;
|
|
|
+import com.cyksj.service.order.OrderRefundService;
|
|
|
+import com.cyksj.service.wechat.WeChatService;
|
|
|
+import com.paypal.api.payments.Amount;
|
|
|
+import com.paypal.api.payments.Refund;
|
|
|
+import com.paypal.api.payments.Sale;
|
|
|
+import com.paypal.base.rest.APIContext;
|
|
|
+import com.paypal.base.rest.OAuthTokenCredential;
|
|
|
+import com.paypal.base.rest.PayPalRESTException;
|
|
|
+import com.stripe.Stripe;
|
|
|
+import com.stripe.exception.StripeException;
|
|
|
+import com.stripe.param.RefundCreateParams;
|
|
|
+import lombok.RequiredArgsConstructor;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import java.math.BigDecimal;
|
|
|
+import java.math.RoundingMode;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+import java.util.Map;
|
|
|
+import java.util.Optional;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 项目名: yhlxj
|
|
|
+ * 文件名: OrderRefundServiceImpl
|
|
|
+ * 创建者: JavaZou
|
|
|
+ * 创建时间:2023/12/4 14:36
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+@RequiredArgsConstructor
|
|
|
+public class OrderRefundServiceImpl implements OrderRefundService {
|
|
|
+
|
|
|
+ private final OrderDonMapper orderDonMapper;
|
|
|
+
|
|
|
+ private final PaypalPayConfigMapper paypalPayConfigMapper;
|
|
|
+
|
|
|
+ private final WeChatService weChatService;
|
|
|
+
|
|
|
+ private final WeChatConfig weChatConfig;
|
|
|
+
|
|
|
+ private final StripePayConfigMapper stripePayConfigMapper;
|
|
|
+
|
|
|
+ private final ShopConfigMapper shopConfigMapper;
|
|
|
+
|
|
|
+ private final RefundOrderDonMapper refundOrderDonMapper;
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public String centerRefund(OrderRefundReq refundReq, OrderDon orderDon) throws Exception {
|
|
|
+ OrderDon.Type type = orderDon.getType();
|
|
|
+ String refundType = refundReq.getRefundType();
|
|
|
+ if (type == OrderDon.Type.WeChat && !refundType.equals(OrderDon.Type.BALANCE.getType())) {
|
|
|
+ return wxRefund(refundReq, orderDon);
|
|
|
+ }
|
|
|
+ if (type == OrderDon.Type.ALI_PAY && !refundType.equals(OrderDon.Type.BALANCE.getType())) {
|
|
|
+ return zfbRefund(refundReq, orderDon);
|
|
|
+ }
|
|
|
+ if (type == OrderDon.Type.PAYPAL && !refundType.equals(OrderDon.Type.BALANCE.getType())) {
|
|
|
+ paypalRefund(refundReq, orderDon);
|
|
|
+ }
|
|
|
+ if (type == OrderDon.Type.STRIPE && !refundType.equals(OrderDon.Type.BALANCE.getType())) {
|
|
|
+ stripeRefund(refundReq, orderDon);
|
|
|
+ }
|
|
|
+ return StrUtil.EMPTY;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void refundRecord(OrderDon orderDon, BigDecimal refundMoney, GoodsDon goodsDon, GoodsDonSku sku, String outRefundNo, String refundType) {
|
|
|
+ RefundOrderDon refund = new RefundOrderDon();
|
|
|
+ refund.setOrderId(orderDon.getId());
|
|
|
+ refund.setOutRefundNo(outRefundNo);
|
|
|
+ refund.setTotalFee(orderDon.getMoney());
|
|
|
+ refund.setRefundDesc(orderDon.getRefundDesc());
|
|
|
+ //退款金额
|
|
|
+ refund.setRefundFee(refundMoney);
|
|
|
+ refund.setUserId(orderDon.getUserId());
|
|
|
+ refund.setGoodsId(orderDon.getGoodsId());
|
|
|
+ refund.setGoodsTitle(goodsDon == null ? null : goodsDon.getTitle());
|
|
|
+ refund.setSkuId(orderDon.getSkuId());
|
|
|
+ refund.setSpecVal(sku == null ? null : String.format("%s%s", sku.getSpecVal(), sku.getPrice().divide(BigDecimal.valueOf(100))));
|
|
|
+ refund.setRefundMethod(orderDon.getType().name());
|
|
|
+ refund.setGoodsType(goodsDon == null ? 0 : goodsDon.getType());
|
|
|
+ //退款方式
|
|
|
+ if (StrUtil.isNotBlank(refundType) && refundType.equals(OrderDon.Type.BALANCE.getType())) {
|
|
|
+ refund.setRefundMethod(refundType);
|
|
|
+ refund.setRefundFee(orderDon.getRefundBalance());
|
|
|
+ }
|
|
|
+ refundOrderDonMapper.insert(refund);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public String wxRefund(OrderRefundReq refundReq, OrderDon orderDon) throws Exception {
|
|
|
+ if (orderDon.getMoney().compareTo(BigDecimal.ZERO) <=0){
|
|
|
+ return StrUtil.EMPTY;
|
|
|
+ }
|
|
|
+ long time = System.currentTimeMillis();
|
|
|
+ //退款订单号
|
|
|
+ String outRefundNo = Codec.DoDigest.custom()
|
|
|
+ .setAlgorithm(Codec.DoDigest.Algorithm.MD5)
|
|
|
+ .setStringData(time + String.valueOf(orderDon.getId()))
|
|
|
+ .toHexString();
|
|
|
+ weChatService.refundWxOrder(weChatConfig.getAppid(),
|
|
|
+ Optional.ofNullable(orderDon.getShopId()).orElse(ShopConfig.WX_DEFAULT_APP_ID),
|
|
|
+ orderDon.getTransactionId(),
|
|
|
+ outRefundNo,
|
|
|
+ orderDon.getMoney(),
|
|
|
+ refundReq.getRefundMoney(),
|
|
|
+ weChatConfig.getDomain() + "manage/order/wx/refund/notify");
|
|
|
+ //记录退款信息
|
|
|
+ return outRefundNo;
|
|
|
+ }
|
|
|
+
|
|
|
+ public String zfbRefund(OrderRefundReq refundReq, OrderDon orderDon) throws Exception {
|
|
|
+ if (orderDon.getMoney().compareTo(BigDecimal.ZERO) <=0){
|
|
|
+ return StrUtil.EMPTY;
|
|
|
+ }
|
|
|
+ AlipayTradeRefundResponse response;
|
|
|
+ //支付宝退款
|
|
|
+ AlipayClient alipayClient = AliPayClientFactory.getAlipayClient(Optional.ofNullable(orderDon.getShopId()).orElse(ShopConfig.ZFB_DEFAULT_APP_ID));
|
|
|
+ AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
|
|
|
+ AlipayTradeRefundModel model = new AlipayTradeRefundModel();
|
|
|
+ //支付宝交易号
|
|
|
+ model.setTradeNo(orderDon.getTransactionId());
|
|
|
+ model.setRefundAmount(refundReq.getRefundMoney().divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_EVEN).toString());
|
|
|
+ model.setQueryOptions(List.of("gmt_refund_pay"));
|
|
|
+ long time = System.currentTimeMillis();
|
|
|
+ //退款订单号
|
|
|
+ String outRefundNo = Codec.DoDigest.custom()
|
|
|
+ .setAlgorithm(Codec.DoDigest.Algorithm.MD5)
|
|
|
+ .setStringData(time + String.valueOf(orderDon.getId()))
|
|
|
+ .toHexString();
|
|
|
+ //退款请求号
|
|
|
+ model.setOutRequestNo(outRefundNo);
|
|
|
+ request.setBizModel(model);
|
|
|
+ String shopId = orderDon.getShopId();
|
|
|
+ ShopConfig shopConfig = shopConfigMapper.selectOne(Wrappers.lambdaQuery(ShopConfig.class).eq(ShopConfig::getAppId, orderDon.getShopId()));
|
|
|
+ if (shopId != null && shopConfig != null && shopConfig.getIsCert()) {
|
|
|
+ response = alipayClient.certificateExecute(request);
|
|
|
+ } else {
|
|
|
+ response = alipayClient.execute(request);
|
|
|
+ }
|
|
|
+ if (!response.isSuccess()) throw BusinessRuntimeException.getInstance("退款失败,e:{0}", response.getSubMsg());
|
|
|
+// AliPayRefundRep aliPayRefundRep = Jsons.parseObject(response.getBody(), AliPayRefundRep.class);
|
|
|
+// AliPayRefundRep.AlipayTradeRefundResponse res = aliPayRefundRep.getResponse();
|
|
|
+// orderDon.setRefundMoney(res.getRefundFee().multiply(BigDecimal.valueOf(100)));
|
|
|
+ return outRefundNo;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public Boolean paypalRefund(OrderRefundReq refundReq, OrderDon orderDon) throws PayPalRESTException {
|
|
|
+ BigDecimal net = refundReq.getRefundMoney().divide(new BigDecimal(7),2,RoundingMode.HALF_DOWN).subtract(orderDon.getAbroadTransactionFee());;
|
|
|
+ log.info("paypal return order:{},money:{}",orderDon.getId(),net);
|
|
|
+ PaypalPayConfig paypalPayConfig = paypalPayConfigMapper.selectById(1);
|
|
|
+ APIContext apiContext = getAPIContext(paypalPayConfig.getClientId(), paypalPayConfig.getClientSecret(),paypalPayConfig.getMode());
|
|
|
+ Sale sale = Sale.get(apiContext, orderDon.getTransactionId());
|
|
|
+ Refund refund = new Refund();
|
|
|
+ refund.setAmount(new Amount("USD", net.divide(new BigDecimal(100),2,RoundingMode.HALF_DOWN).toString()));
|
|
|
+ refund = sale.refund(apiContext, refund);
|
|
|
+ log.info("paypal return refund:{}",refund);
|
|
|
+ if ("completed".equals(refund.getState())){
|
|
|
+ orderDon.setStatus(OrderDon.Status.refund);
|
|
|
+ orderDonMapper.updateById(orderDon);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Boolean stripeRefund(OrderRefundReq refundReq, OrderDon orderDon) throws StripeException {
|
|
|
+ BigDecimal net = refundReq.getRefundMoney().divide(new BigDecimal(7),2, RoundingMode.HALF_DOWN).subtract(orderDon.getAbroadTransactionFee());
|
|
|
+ log.info("stripe return order:{},money:{}",orderDon.getId(),net);
|
|
|
+ StripePayConfig stripePayConfig = stripePayConfigMapper.selectById(1);
|
|
|
+ Stripe.apiKey = stripePayConfig.getApiKey();
|
|
|
+ RefundCreateParams params =
|
|
|
+ RefundCreateParams.builder()
|
|
|
+ .setCharge(orderDon.getTransactionId())
|
|
|
+ .setAmount(net.longValue())
|
|
|
+ .build();
|
|
|
+ com.stripe.model.Refund refund = com.stripe.model.Refund.create(params);
|
|
|
+ log.info("stripe return refund:{}",refund);
|
|
|
+ if ("succeeded".equals(refund.getStatus())){
|
|
|
+ orderDon.setStatus(OrderDon.Status.refund);
|
|
|
+ orderDonMapper.updateById(orderDon);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private APIContext getAPIContext(String clientId,String clientSecret,String mode) throws PayPalRESTException {
|
|
|
+ Map<String, String> sdkConfig = new HashMap<>();
|
|
|
+ sdkConfig.put("mode", mode);
|
|
|
+ OAuthTokenCredential authTokenCredential = new OAuthTokenCredential(clientId,clientSecret,sdkConfig);
|
|
|
+ APIContext apiContext = new APIContext(authTokenCredential.getAccessToken());
|
|
|
+ apiContext.setConfigurationMap(sdkConfig);
|
|
|
+ return apiContext;
|
|
|
+ }
|
|
|
+}
|