Przeglądaj źródła

bugfix:支付小修改(查询返回+退款)

刘云鑫 3 godzin temu
rodzic
commit
23bf798eea

+ 277 - 4
alien-store/src/main/java/shop/alien/store/strategy/payment/impl/AlipayPartnerPaymentStrategyImpl.java

@@ -1,5 +1,8 @@
 package shop.alien.store.strategy.payment.impl;
 
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.alipay.api.AlipayApiException;
 import com.alipay.api.AlipayClient;
 import com.alipay.api.AlipayConfig;
@@ -7,19 +10,30 @@ import com.alipay.api.DefaultAlipayClient;
 import com.alipay.api.domain.*;
 import com.alipay.api.request.AlipayTradeAppPayRequest;
 import com.alipay.api.request.AlipayTradeQueryRequest;
+import com.alipay.api.request.AlipayTradeRefundRequest;
 import com.alipay.api.response.AlipayTradeAppPayResponse;
 import com.alipay.api.response.AlipayTradeQueryResponse;
+import com.alipay.api.response.AlipayTradeRefundResponse;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.collections4.map.HashedMap;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Component;
 import shop.alien.entity.result.R;
+import shop.alien.entity.store.RefundRecord;
+import shop.alien.entity.store.StoreAliPayRefundLog;
 import shop.alien.mapper.AlipayZftCreateRecordMapper;
+import shop.alien.store.service.RefundRecordService;
+import shop.alien.store.service.StoreAliPayRefundLogService;
 import shop.alien.store.strategy.payment.PaymentStrategy;
+import shop.alien.util.common.UniqueRandomNumGenerator;
 import shop.alien.util.common.constant.PaymentEnum;
 
 import java.math.BigDecimal;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Date;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -31,6 +45,8 @@ import java.util.Random;
 public class AlipayPartnerPaymentStrategyImpl implements PaymentStrategy {
 
     private final AlipayZftCreateRecordMapper alipayZftCreateRecordMapper;
+    private final StoreAliPayRefundLogService storeAliPayRefundLogService;
+    private final RefundRecordService refundRecordService;
 
 
 
@@ -200,13 +216,14 @@ public class AlipayPartnerPaymentStrategyImpl implements PaymentStrategy {
 
             Map<String, Object> data = buildAlipayTradeQueryData(response);
             if (response.isSuccess()) {
-                return R.success("订单状态:" + data.get("tradeStatus"));
+//                data.get("tradeStatus")
+                return R.data(200,"","支付成功" );
             }
             String sub = response.getSubMsg() != null ? response.getSubMsg() : "";
-            return R.fail("订单查询失败:" + response.getMsg() + "(" + sub + ")");
+            return R.data(200,"","支付失败");
         } catch (AlipayApiException e) {
             log.error("支付宝订单查询异常, transactionId={}", transactionId, e);
-            return R.fail("查询异常:" + e.getMessage());
+            return R.data(200,"","查询失败");
         }
     }
 
@@ -263,7 +280,263 @@ public class AlipayPartnerPaymentStrategyImpl implements PaymentStrategy {
 
     @Override
     public String handleRefund(Map<String, String> params) throws Exception {
-        return "";
+        log.info("[支付宝服务商退款] 处理退款请求,参数:{}", params);
+        try {
+            // 调用 alipay.trade.refund 接口发起退款
+            AlipayTradeRefundRequest refundRequest = buildRefundRequest(params);
+            AlipayTradeRefundResponse response = refundRun(refundRequest);
+            String refundResult = "";
+            JSONObject responseBody = JSONObject.parseObject(response.getBody());
+            JSONObject refundResponse = responseBody.getJSONObject("alipay_trade_refund_response");
+
+            if (response.isSuccess()) {
+                refundResult = "调用成功";
+                log.info("[支付宝服务商退款] 退款成功 outTradeNo={}, tradeNo={}, refundFee={}",
+                        refundResponse.getString("out_trade_no"),
+                        refundResponse.getString("trade_no"),
+                        refundResponse.getString("refund_fee"));
+
+                // 保存退款信息到支付宝退款记录表
+                StoreAliPayRefundLog refundLog = new StoreAliPayRefundLog();
+                refundLog.setResponseCode(refundResponse.getString("code"));
+                refundLog.setResponseMsg(refundResponse.getString("msg"));
+                refundLog.setBuyerLogonId(refundResponse.getString("buyer_logon_id"));
+                refundLog.setBuyerOpenId(refundResponse.getString("buyer_open_id"));
+                refundLog.setFundChange(refundResponse.getString("fund_change"));
+                refundLog.setOutTradeNo(refundResponse.getString("out_trade_no"));
+                refundLog.setTradeNo(refundResponse.getString("trade_no"));
+                refundLog.setRefundFee(refundResponse.getString("refund_fee"));
+                refundLog.setSendBackFee(refundResponse.getString("send_back_fee"));
+                if (refundResponse.containsKey("refund_detail_item_list")) {
+                    JSONArray refundDetailList = refundResponse.getJSONArray("refund_detail_item_list");
+                    if (refundDetailList != null) {
+                        refundLog.setRefundDetailItemList(JSON.toJSONString(refundDetailList));
+                    }
+                }
+                String gmtRefundPayStr = refundResponse.getString("gmt_refund_pay");
+                if (StringUtils.isNotBlank(gmtRefundPayStr)) {
+                    try {
+                        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                        refundLog.setGmtRefundPay(sdf.parse(gmtRefundPayStr));
+                    } catch (ParseException e) {
+                        log.warn("[支付宝服务商退款] 解析退款时间失败: {}", gmtRefundPayStr, e);
+                    }
+                }
+                refundLog.setRefundReason(params.get("refundReason"));
+                refundLog.setOutRequestNo(params.get("partialRefundCode"));
+                refundLog.setAlipayCertSn(responseBody.getString("alipay_cert_sn"));
+                refundLog.setSign(responseBody.getString("sign"));
+                refundLog.setDeleteFlag(0);
+                refundLog.setCreatedTime(new Date());
+                storeAliPayRefundLogService.save(refundLog);
+
+                // 保存到通用退款记录表
+                try {
+                    RefundRecord refundRecord = buildRefundRecordFromAlipayResponse(refundResponse, responseBody, params);
+                    if (refundRecord != null) {
+                        long count = refundRecordService.lambdaQuery()
+                                .eq(RefundRecord::getOutRefundNo, refundRecord.getOutRefundNo())
+                                .count();
+                        if (count == 0) {
+                            refundRecordService.save(refundRecord);
+                            log.info("[支付宝服务商退款] 退款记录已保存,商户退款单号:{}", refundRecord.getOutRefundNo());
+                        } else {
+                            log.info("[支付宝服务商退款] 退款记录已存在,跳过插入,商户退款单号:{}", refundRecord.getOutRefundNo());
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("[支付宝服务商退款] 保存 RefundRecord 失败", e);
+                }
+            } else {
+                log.warn("[支付宝服务商退款] 退款失败 body={}", response.getBody());
+                refundResult = refundResponse.getString("sub_msg");
+
+                try {
+                    RefundRecord refundRecord = buildRefundRecordFromAlipayError(refundResponse, responseBody, params);
+                    if (refundRecord != null) {
+                        long count = refundRecordService.lambdaQuery()
+                                .eq(RefundRecord::getOutRefundNo, refundRecord.getOutRefundNo())
+                                .count();
+                        if (count == 0) {
+                            refundRecordService.save(refundRecord);
+                            log.info("[支付宝服务商退款] 退款失败记录已保存,商户退款单号:{}", refundRecord.getOutRefundNo());
+                        } else {
+                            log.info("[支付宝服务商退款] 退款失败记录已存在,跳过插入,商户退款单号:{}", refundRecord.getOutRefundNo());
+                        }
+                    }
+                } catch (Exception e) {
+                    log.error("[支付宝服务商退款] 保存退款失败 RefundRecord 失败", e);
+                }
+            }
+            return refundResult;
+        } catch (AlipayApiException e) {
+            log.error("[支付宝服务商退款] 调用 alipay.trade.refund 异常 outTradeNo={}", params.get("outTradeNo"), e);
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 构建 alipay.trade.refund 退款请求。
+     */
+    private AlipayTradeRefundRequest buildRefundRequest(Map<String, String> params) {
+        AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
+        AlipayTradeRefundModel model = new AlipayTradeRefundModel();
+        model.setOutTradeNo(params.get("outTradeNo"));
+        model.setRefundAmount(params.get("refundAmount"));
+        model.setRefundReason(params.get("refundReason"));
+        if (StringUtils.isNotBlank(params.get("partialRefundCode"))) {
+            model.setOutRequestNo(params.get("partialRefundCode"));
+        }
+        // 设置退分账明细信息
+        List<OpenApiRoyaltyDetailInfoPojo> refundRoyaltyParameters = new ArrayList<OpenApiRoyaltyDetailInfoPojo>();
+        OpenApiRoyaltyDetailInfoPojo refundRoyaltyParameters0 = new OpenApiRoyaltyDetailInfoPojo();
+        refundRoyaltyParameters0.setAmount("0.1");
+        refundRoyaltyParameters0.setTransIn("2088101126708402");
+        refundRoyaltyParameters0.setRoyaltyType("transfer");
+        refundRoyaltyParameters0.setTransOut("2088101126765726");
+        refundRoyaltyParameters0.setTransOutType("userId");
+        refundRoyaltyParameters0.setRoyaltyScene("达人佣金");
+        refundRoyaltyParameters0.setTransInType("userId");
+        refundRoyaltyParameters0.setTransInName("张三");
+        refundRoyaltyParameters0.setDesc("分账给2088101126708402");
+        refundRoyaltyParameters.add(refundRoyaltyParameters0);
+
+        model.setRefundRoyaltyParameters(refundRoyaltyParameters);
+        request.setBizModel(model);
+        return request;
+    }
+
+    /**
+     * 执行退款请求(直付通使用公钥模式,调用 execute)。
+     */
+    private AlipayTradeRefundResponse refundRun(AlipayTradeRefundRequest request) throws AlipayApiException {
+        AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
+        return alipayClient.execute(request);
+    }
+
+    /**
+     * 从支付宝退款成功响应构建 RefundRecord。
+     */
+    private RefundRecord buildRefundRecordFromAlipayResponse(JSONObject refundResponse, JSONObject responseBody, Map<String, String> params) {
+        try {
+            RefundRecord record = new RefundRecord();
+            record.setPayType(PaymentEnum.ALIPAY_PARTNER.getType());
+            record.setOutTradeNo(refundResponse.getString("out_trade_no"));
+            record.setTransactionId(refundResponse.getString("trade_no"));
+            String outRefundNo = params.get("partialRefundCode");
+            if (StringUtils.isBlank(outRefundNo)) {
+                outRefundNo = UniqueRandomNumGenerator.generateUniqueCode(19);
+            }
+            record.setOutRefundNo(outRefundNo);
+            record.setRefundStatus("SUCCESS");
+
+            String refundFeeStr = refundResponse.getString("refund_fee");
+            String sendBackFeeStr = refundResponse.getString("send_back_fee");
+            if (StringUtils.isNotBlank(refundFeeStr)) {
+                record.setRefundAmount(new BigDecimal(refundFeeStr).multiply(new BigDecimal(100)).longValue());
+            }
+            if (StringUtils.isNotBlank(sendBackFeeStr)) {
+                record.setActualRefundAmount(new BigDecimal(sendBackFeeStr).multiply(new BigDecimal(100)).longValue());
+            }
+            String totalAmountStr = params.get("totalAmount");
+            if (StringUtils.isNotBlank(totalAmountStr)) {
+                record.setTotalAmount(new BigDecimal(totalAmountStr).multiply(new BigDecimal(100)).longValue());
+            }
+            record.setCurrency("CNY");
+            record.setRefundReason(params.get("refundReason"));
+
+            if (refundResponse.containsKey("refund_detail_item_list")) {
+                JSONArray refundDetailList = refundResponse.getJSONArray("refund_detail_item_list");
+                if (refundDetailList != null) {
+                    record.setRefundDetail(JSON.toJSONString(refundDetailList));
+                }
+            }
+            record.setUserReceivedAccount(refundResponse.getString("buyer_logon_id"));
+
+            String gmtRefundPayStr = refundResponse.getString("gmt_refund_pay");
+            if (StringUtils.isNotBlank(gmtRefundPayStr)) {
+                try {
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                    Date refundTime = sdf.parse(gmtRefundPayStr);
+                    record.setRefundSuccessTime(refundTime);
+                    record.setRefundCreateTime(refundTime);
+                } catch (ParseException e) {
+                    log.warn("[支付宝服务商退款] 解析退款时间失败: {}", gmtRefundPayStr, e);
+                }
+            }
+
+            fillRefundRecordBusinessFields(record, params);
+            record.setResponseData(responseBody.toJSONString());
+            record.setDeleteFlag(0);
+            record.setCreatedTime(new Date());
+            return record;
+        } catch (Exception e) {
+            log.error("[支付宝服务商退款] 构建 RefundRecord 失败", e);
+            return null;
+        }
+    }
+
+    /**
+     * 从支付宝退款失败响应构建 RefundRecord。
+     */
+    private RefundRecord buildRefundRecordFromAlipayError(JSONObject refundResponse, JSONObject responseBody, Map<String, String> params) {
+        try {
+            RefundRecord record = new RefundRecord();
+            record.setPayType(PaymentEnum.ALIPAY_PARTNER.getType());
+            record.setOutTradeNo(params.get("outTradeNo"));
+            String outRefundNo = params.get("partialRefundCode");
+            if (StringUtils.isBlank(outRefundNo)) {
+                outRefundNo = UniqueRandomNumGenerator.generateUniqueCode(19);
+            }
+            record.setOutRefundNo(outRefundNo);
+            record.setRefundStatus("ABNORMAL");
+
+            String refundAmountStr = params.get("refundAmount");
+            if (StringUtils.isNotBlank(refundAmountStr)) {
+                record.setRefundAmount(new BigDecimal(refundAmountStr).multiply(new BigDecimal(100)).longValue());
+            }
+            String totalAmountStr = params.get("totalAmount");
+            if (StringUtils.isNotBlank(totalAmountStr)) {
+                record.setTotalAmount(new BigDecimal(totalAmountStr).multiply(new BigDecimal(100)).longValue());
+            }
+            record.setCurrency("CNY");
+            record.setRefundReason(params.get("refundReason"));
+            record.setErrorCode(refundResponse.getString("code"));
+            record.setErrorMsg(refundResponse.getString("sub_msg"));
+
+            fillRefundRecordBusinessFields(record, params);
+            record.setResponseData(responseBody.toJSONString());
+            record.setDeleteFlag(0);
+            record.setCreatedTime(new Date());
+            record.setRefundCreateTime(new Date());
+            return record;
+        } catch (Exception e) {
+            log.error("[支付宝服务商退款] 构建退款失败 RefundRecord 失败", e);
+            return null;
+        }
+    }
+
+    /**
+     * 填充退款记录中的业务字段(userId、orderId、storeId)。
+     */
+    private void fillRefundRecordBusinessFields(RefundRecord record, Map<String, String> params) {
+        if (params.containsKey("userId")) {
+            try {
+                record.setUserId(Integer.parseInt(params.get("userId")));
+            } catch (NumberFormatException e) {
+                log.warn("[支付宝服务商退款] 解析 userId 失败: {}", params.get("userId"));
+            }
+        }
+        if (params.containsKey("orderId")) {
+            record.setOrderId(params.get("orderId"));
+        }
+        if (params.containsKey("storeId")) {
+            try {
+                record.setStoreId(Integer.parseInt(params.get("storeId")));
+            } catch (NumberFormatException e) {
+                log.warn("[支付宝服务商退款] 解析 storeId 失败: {}", params.get("storeId"));
+            }
+        }
     }
 
     @Override