Эх сурвалжийг харах

Merge branch 'sit' into uat-20260202

dujian 5 цаг өмнө
parent
commit
8ad7c51d2e

+ 4 - 0
alien-entity/src/main/java/shop/alien/entity/store/CommonRating.java

@@ -110,5 +110,9 @@ public class CommonRating implements Serializable {
     @ApiModelProperty(value = "审核失败原因")
     @TableField(value = "audit_reason")
     private String auditReason;
+
+    @ApiModelProperty(value = "审核拒绝次数")
+    @TableField(value = "reject_num")
+    private Integer rejectNum;
 }
 

+ 2 - 0
alien-entity/src/main/java/shop/alien/entity/store/vo/CommonRatingVo.java

@@ -42,4 +42,6 @@ public class CommonRatingVo extends CommonRating {
     private Integer appealStatus;
     @ApiModelProperty(name = "appealFlag", value = "是否已申诉:0-未申诉, 1-已申诉")
     private Integer appealFlag;
+    @ApiModelProperty(value = "审核拒绝次数")
+    private Integer rejectNum;
 }

+ 4 - 3
alien-job/src/main/java/shop/alien/job/store/AlipayJob.java

@@ -18,6 +18,7 @@ import org.springframework.stereotype.Component;
 import shop.alien.entity.store.AlipayZftCreateRecord;
 import shop.alien.entity.store.StoreInfo;
 import shop.alien.mapper.AlipayZftCreateRecordMapper;
+import shop.alien.mapper.StoreInfoMapper;
 import shop.alien.store.service.StoreInfoService;
 
 import java.util.List;
@@ -29,7 +30,7 @@ public class AlipayJob {
 
     private final AlipayZftCreateRecordMapper alipayZftCreateRecordMapper;
 
-    private final StoreInfoService storeInfoService;
+    private final StoreInfoMapper storeInfoMapper;
 
     /**
      * 查询支付宝二级商户进件结果,并从响应中回写门店 smid。
@@ -78,7 +79,7 @@ public class AlipayJob {
                 continue;
             }
 
-            StoreInfo storeInfo = storeInfoService.getById(storeId);
+            StoreInfo storeInfo = storeInfoMapper.selectById(storeId);
             if (storeInfo == null) {
                 log.warn("门店不存在 storeId={} orderId={}", storeId, orderId);
                 continue;
@@ -89,7 +90,7 @@ public class AlipayJob {
             }
 
             storeInfo.setAlipaySmid(smid);
-            storeInfoService.updateById(storeInfo);
+            storeInfoMapper.updateById(storeInfo);
             log.info("已回写门店 alipay_smid storeId={} orderId={}", storeId, orderId);
         }
     }

+ 20 - 4
alien-store/src/main/java/shop/alien/store/service/StoreCommentAppealSupplementJobService.java

@@ -159,6 +159,10 @@ public class StoreCommentAppealSupplementJobService {
                     updateAppeal.setAppealStatus(1);
                     updateAppeal.setFinalResult("已驳回");
                     log.info("【用户补充申诉】用户赢,申诉驳回,申诉ID: {}", appeal.getId());
+                    Integer ratingId = appeal.getCommentId();
+                    if (ratingId != null) {
+                        incrementRatingRejectNum(ratingId);
+                    }
                 }
 
                 storeCommentAppealMapper.updateByRecordIdNew(appeal.getId(),
@@ -390,11 +394,23 @@ public class StoreCommentAppealSupplementJobService {
         return baseUrl + "/" + recordId + "/completed";
     }
 
+    private void incrementRatingRejectNum(Integer ratingId) {
+        try {
+            LambdaUpdateWrapper<CommonRating> wrapper = new LambdaUpdateWrapper<>();
+            wrapper.eq(CommonRating::getId, ratingId)
+                    .setSql("reject_num = IFNULL(reject_num, 0) + 1");
+            int rows = commonRatingMapper.update(null, wrapper);
+            log.info("【用户补充申诉】申诉失败,评价拒绝次数+1,ratingId={},影响行数={}", ratingId, rows);
+        } catch (Exception e) {
+            log.error("【用户补充申诉】更新评价拒绝次数失败,ratingId={}", ratingId, e);
+        }
+    }
+
     private void deleteRatingAndComments(Integer ratingId) {
         try {
             CommonRating rating = commonRatingMapper.selectById(ratingId);
             if (rating != null) {
-//                int rows = commonRatingMapper.logicDeleteById(ratingId);
+                int rows = commonRatingMapper.logicDeleteById(ratingId);
                 commonRatingService.updateStoreScoreAfterDelete(rating.getBusinessId());
                 log.info("【用户补充申诉】删除评价,ratingId={}", ratingId);
             }
@@ -430,9 +446,9 @@ public class StoreCommentAppealSupplementJobService {
                 }
             }
 
-            if (rating != null && rating.getBusinessType() == 1) {
-                updateStoreScore(rating.getBusinessId());
-            }
+//            if (rating != null && rating.getBusinessType() == 1) {
+//                updateStoreScore(rating.getBusinessId());
+//            }
         } catch (Exception e) {
             log.error("【用户补充申诉】删除评价和评论异常,ratingId={}", ratingId, e);
         }

+ 32 - 37
alien-store/src/main/java/shop/alien/store/service/impl/CommonRatingServiceImpl.java

@@ -1235,57 +1235,52 @@ public class CommonRatingServiceImpl extends ServiceImpl<CommonRatingMapper, Com
             Integer commentCount = storeInfoScoreNew.size();
 
 
-            if (commentCount == 10) {
-                // 没有评价,设置默认评分为0
-                StoreInfo storeInfo = new StoreInfo();
-                storeInfo.setId(businessId);
-                storeInfo.setScoreAvg(4.0);
+            if (commentCount < 10) {
+                if (storeInfoNew.getScoreAvg()!=0.0){
+                    // 没有评价,设置默认评分为0
+                    StoreInfo storeInfo = new StoreInfo();
+                    storeInfo.setId(businessId);
+                    storeInfo.setScoreAvg(3.5);
 //                storeInfo.setScoreOne(3.0);
 //                storeInfo.setScoreTwo(3.0);
 //                storeInfo.setScoreThree(3.0);
-                storeInfoMapper.updateById(storeInfo);
-                log.info("店铺有效评价被删除=10条,重置评分为4.0,businessId={}", businessId);
-                return;
-            }
+                    storeInfoMapper.updateById(storeInfo);
+                    log.info("店铺有效评价被删除<10条,重置评分为3.5,businessId={}", businessId);
+                }
+            }else if(commentCount > 10){
+                // 计算平均评分
+                double scoreSum = ratings.stream().mapToDouble(r -> r.getScore() != null ? r.getScore() : 0.0).sum();
+                double scoreOneSum = ratings.stream().mapToDouble(r -> r.getScoreOne() != null ? r.getScoreOne() : 0.0).sum();
+                double scoreTwoSum = ratings.stream().mapToDouble(r -> r.getScoreTwo() != null ? r.getScoreTwo() : 0.0).sum();
+                double scoreThreeSum = ratings.stream().mapToDouble(r -> r.getScoreThree() != null ? r.getScoreThree() : 0.0).sum();
+
+                double scoreAvg = Math.round((scoreSum / total) * 100.0) / 100.0;
+                double scoreOne = Math.round((scoreOneSum / total) * 100.0) / 100.0;
+                double scoreTwo = Math.round((scoreTwoSum / total) * 100.0) / 100.0;
+                double scoreThree = Math.round((scoreThreeSum / total) * 100.0) / 100.0;
 
-            if (commentCount < 10) {
+                StoreInfo storeInfo = new StoreInfo();
+                storeInfo.setId(businessId);
+                storeInfo.setScoreAvg(scoreAvg);
+                storeInfo.setScoreOne(scoreOne);
+                storeInfo.setScoreTwo(scoreTwo);
+                storeInfo.setScoreThree(scoreThree);
+                storeInfoMapper.updateById(storeInfo);
 
-                if (storeInfoNew.getScoreAvg()==0.0){
-                    return;
-                }
+                log.info("更新店铺评分成功,businessId={},评价数={},scoreAvg={}", businessId, total, scoreAvg);
+            }else{
                 // 没有评价,设置默认评分为0
                 StoreInfo storeInfo = new StoreInfo();
                 storeInfo.setId(businessId);
-                storeInfo.setScoreAvg(3.5);
+                storeInfo.setScoreAvg(4.0);
 //                storeInfo.setScoreOne(3.0);
 //                storeInfo.setScoreTwo(3.0);
 //                storeInfo.setScoreThree(3.0);
                 storeInfoMapper.updateById(storeInfo);
-                log.info("店铺有效评价被删除<10条,重置评分为3.5,businessId={}", businessId);
-                return;
-            }
+                log.info("店铺有效评价被删除=10条,重置评分为4.0,businessId={}", businessId);
 
+            }
 
-            // 计算平均评分
-            double scoreSum = ratings.stream().mapToDouble(r -> r.getScore() != null ? r.getScore() : 0.0).sum();
-            double scoreOneSum = ratings.stream().mapToDouble(r -> r.getScoreOne() != null ? r.getScoreOne() : 0.0).sum();
-            double scoreTwoSum = ratings.stream().mapToDouble(r -> r.getScoreTwo() != null ? r.getScoreTwo() : 0.0).sum();
-            double scoreThreeSum = ratings.stream().mapToDouble(r -> r.getScoreThree() != null ? r.getScoreThree() : 0.0).sum();
-            
-            double scoreAvg = Math.round((scoreSum / total) * 100.0) / 100.0;
-            double scoreOne = Math.round((scoreOneSum / total) * 100.0) / 100.0;
-            double scoreTwo = Math.round((scoreTwoSum / total) * 100.0) / 100.0;
-            double scoreThree = Math.round((scoreThreeSum / total) * 100.0) / 100.0;
-            
-            StoreInfo storeInfo = new StoreInfo();
-            storeInfo.setId(businessId);
-            storeInfo.setScoreAvg(scoreAvg);
-            storeInfo.setScoreOne(scoreOne);
-            storeInfo.setScoreTwo(scoreTwo);
-            storeInfo.setScoreThree(scoreThree);
-            storeInfoMapper.updateById(storeInfo);
-            
-            log.info("更新店铺评分成功,businessId={},评价数={},scoreAvg={}", businessId, total, scoreAvg);
         } catch (Exception e) {
             log.error("更新店铺评分失败,businessId={},error={}", businessId, e.getMessage());
         }

+ 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;
 
 
 
@@ -192,13 +208,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,"","查询失败");
         }
     }
 
@@ -255,7 +272,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.01");
+//        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