From c4791fd6e9526f580f72a380aa2f15c777358954 Mon Sep 17 00:00:00 2001 From: Jack <46790855@qq.com> Date: Tue, 17 Jun 2025 11:38:00 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=80=E6=AC=BE=E8=B0=83=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mall/pay/service/LakalaPayService.java | 14 +++ .../service/impl/LakalaPayServiceImpl.java | 90 +++++++++++++++++++ .../impl/PayConsumeTradeServiceImpl.java | 65 ++++++++++---- .../src/main/resources/bootstrap-prod.yml | 1 + .../service/impl/ShopMchEntryServiceImpl.java | 4 +- 5 files changed, 153 insertions(+), 21 deletions(-) diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java index 855a6fc3..ec6a07f7 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/LakalaPayService.java @@ -10,6 +10,7 @@ package com.suisung.mall.pay.service; import cn.hutool.json.JSONObject; import com.suisung.mall.common.api.CommonResult; +import org.springframework.data.util.Pair; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -62,6 +63,19 @@ public interface LakalaPayService { */ JSONObject refund(Integer storeId, String out_trade_no, String origin_trade_no, String refund_amount, String refund_reason, String requestIP); + /** + * 执行内部拉卡拉交易退款 + * 参考地址:https://o.lakala.com/#/home/document/detail?id=113 + * + * @param storeId 店铺ID + * @param outTradeNo 外部交易订单号 + * @param originTradeNo 原拉卡拉交易流水号 + * @param refundAmount 退款金额(单位:分) + * @param refundReason 退款原因 + * @return Pair,包含退款是否成功以及消息 + */ + Pair innerLklRefund(Integer storeId, String outTradeNo, String originTradeNo, String refundAmount, String refundReason); + /** * 账户余额查询 * 参考:https://o.lakala.com/#/home/document/detail?id=364 diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java index 31823930..770f4bc7 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/LakalaPayServiceImpl.java @@ -37,7 +37,10 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -50,6 +53,8 @@ import java.util.List; @Service public class LakalaPayServiceImpl implements LakalaPayService { private static final boolean init = false; + + //### 可选的两个参数,不同的店铺商家,可以数据库里配置不同的商户号和终端号 @Value("${lakala.merchant_no}") public String merchantNo; // 拉卡拉分配的商户号 @@ -331,6 +336,91 @@ public class LakalaPayServiceImpl implements LakalaPayService { } } + + /** + * 执行内部拉卡拉交易退款 + * 参考地址:https://o.lakala.com/#/home/document/detail?id=113 + * + * @param storeId 店铺ID + * @param outTradeNo 退货订单号 + * @param originTradeNo 原拉卡拉交易流水号 + * @param refundAmount 退款金额(单位:分) + * @param refundReason 退款原因 + * @return Pair,包含退款是否成功以及消息 + */ + @Override + public Pair innerLklRefund(Integer storeId, String outTradeNo, String originTradeNo, String refundAmount, String refundReason) { + try { + log.info("开始执行拉卡拉内部退款,参数: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, refundReason={}", + storeId, outTradeNo, originTradeNo, refundAmount, refundReason); + + // 1. 获取请求IP + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes == null) { + log.error("无法获取HttpServletRequest,退款失败"); + return Pair.of(false, I18nUtil._("系统异常,无法获取请求信息!")); + } + HttpServletRequest request = attributes.getRequest(); + String requestIp = IpKit.getRealIp(request); + // 2. 校验参数 + if (ObjectUtil.isEmpty(storeId) || org.apache.commons.lang3.StringUtils.isAnyBlank(outTradeNo, refundAmount, originTradeNo)) { + log.warn("退款请求参数不完整: storeId={}, outTradeNo={}, originTradeNo={}, refundAmount={}, requestIp={}", storeId, outTradeNo, originTradeNo, refundAmount, requestIp); + return Pair.of(false, I18nUtil._("缺少必要参数,退款失败!")); + } + if (!refundAmount.matches("\\d+") || Integer.parseInt(refundAmount) <= 0) { + log.warn("退款金额不合法: refundAmount={}", refundAmount); + return Pair.of(false, I18nUtil._("退款金额不合法!")); + } + // 3. 初始化拉卡拉SDK + initLKLSDK(); + // 4. 获取店铺的拉卡拉商户号和终端号 + ShopStoreBase shopStoreBase = shopService.getLklMerchantNoAndTermNo(storeId); + if (shopStoreBase == null || org.apache.commons.lang3.StringUtils.isAnyBlank(shopStoreBase.getLkl_merchant_no(), shopStoreBase.getLkl_term_no())) { + log.error("无法获取店铺的拉卡拉商户号或终端号: storeId={}", storeId); + return Pair.of(false, I18nUtil._("缺少商户号参数,退款失败!")); + } + // 5. 构造退款请求并发送 + V3LabsRelationRefundRequest refundRequest = new V3LabsRelationRefundRequest(); + refundRequest.setOutTradeNo(outTradeNo); + refundRequest.setMerchantNo(shopStoreBase.getLkl_merchant_no()); + refundRequest.setTermNo(shopStoreBase.getLkl_term_no()); + refundRequest.setRefundAmount(refundAmount); + refundRequest.setRefundReason(refundReason); + refundRequest.setOriginTradeNo(originTradeNo); + refundRequest.setLocationInfo(new V3LabsTradeLocationInfo(requestIp, null, "")); + + log.info("拉卡拉退款请求参数: {}", JSONUtil.toJsonStr(refundRequest)); + + String responseString = LKLSDK.httpPost(refundRequest); + // 6. 处理响应 + if (StrUtil.isBlank(responseString)) { + log.error("拉卡拉退款接口无响应"); + return Pair.of(false, I18nUtil._("服务端无返回值,退款失败!")); + } + + log.info("拉卡拉退款接口响应: {}", responseString); + + JSONObject lakalaResponseJson = JSONUtil.parseObj(responseString); + if (lakalaResponseJson == null) { + log.error("拉卡拉退款接口返回值解析失败: responseString={}", responseString); + return Pair.of(false, I18nUtil._("返回值解析失败,退款失败!")); + } + if (!"BBS00000".equals(lakalaResponseJson.getStr("code"))) { + String errorMessage = lakalaResponseJson.getStr("msg", "未知错误"); + log.error("拉卡拉退款失败, 错误信息: {}", errorMessage); + return Pair.of(false, I18nUtil._(errorMessage)); + } + log.info("拉卡拉退款成功: outTradeNo={}", outTradeNo); + return Pair.of(true, I18nUtil._("退款成功!")); + } catch (SDKException e) { + log.error("拉卡拉退款SDK异常: ", e); + return Pair.of(false, I18nUtil._("拉卡拉退款SDK异常,退款失败!") + e.getMessage()); + } catch (Exception e) { + log.error("拉卡拉退款发生未知异常: ", e); + return Pair.of(false, I18nUtil._("拉卡拉退款发生未知异常,退款失败!") + e.getMessage()); + } + } + /** * 账户余额查询 * 参考:https://o.lakala.com/#/home/document/detail?id=364 diff --git a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java index ef1f511f..1625f487 100644 --- a/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java +++ b/mall-pay/src/main/java/com/suisung/mall/pay/service/impl/PayConsumeTradeServiceImpl.java @@ -25,6 +25,8 @@ import com.suisung.mall.pay.mapper.PayConsumeTradeMapper; import com.suisung.mall.pay.service.*; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Lazy; +import org.springframework.data.util.Pair; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -71,6 +73,10 @@ public class PayConsumeTradeServiceImpl extends BaseServiceImpl fixConsumeTrade(List rows, String field_key) { if (ObjectUtil.isNull(rows)) return new ArrayList<>(); @@ -175,7 +181,7 @@ public class PayConsumeTradeServiceImpl extends BaseServiceImpl returnRows) { - log.info("执行退款操作开始"); + log.info("执行退款操作开始..."); if (CollUtil.isEmpty(returnRows)) { log.warn("退款订单列表为空,停止退款操作"); return false; } +// log.info("退款订单列表大小: {}", returnRows.size()); + // 存储已支付的退货单ID列表 List paidReturnIdList = new ArrayList<>(); // 获取是否原路退回配置,默认为 false boolean refundToOriginal = accountBaseConfigService.getConfig("order_refund_flag", false); + log.info("是否原路退回:{}", refundToOriginal); // 提取所有订单ID,并去重 List orderIdList = returnRows.stream().map(ShopOrderReturn::getOrder_id).distinct().collect(Collectors.toList()); @@ -1079,6 +1088,8 @@ public class PayConsumeTradeServiceImpl extends BaseServiceImpl 0) { - // 获取买家用户资源 - PayUserResource payUserResource = payUserResourceService.getById(buyerUserId); - // 设置买家用户余额(原余额 + 余额差额) - payUserResource.setUser_money(NumberUtil.add(payUserResource.getUser_money(), moneyDifference)); - // 修改买家用户资源 - if (!payUserResourceService.edit(payUserResource)) { - throw new ApiException(I18nUtil._("用户退款失败!")); +// log.info("买家余额差额大于 0,调用退款接口"); + // TODO 支付宝微信金额原路返回(调用 拉卡拉的退款接口) + Pair refundResult = lakalaPayService.innerLklRefund( + storeId, + returnRow.getReturn_id(), // 退货单ID + depositTradeNo, + String.valueOf(moneyDifference.multiply(BigDecimal.valueOf(100)).intValue()), // 单位:分 + returnRow.getReturn_buyer_message() + ); + if (!refundResult.getFirst()) { + // 如果原路退款失败,直接退回余额 + + // 获取买家用户资源 + PayUserResource payUserResource = payUserResourceService.getById(buyerUserId); + // 设置买家用户余额(原余额 + 余额差额) + payUserResource.setUser_money(NumberUtil.add(payUserResource.getUser_money(), moneyDifference)); + // 修改买家用户资源 + if (!payUserResourceService.edit(payUserResource)) { + throw new ApiException(I18nUtil._("用户退款失败!")); + } + //throw new ApiException(I18nUtil._("退款原路返回失败!")); } } @@ -1367,9 +1396,6 @@ public class PayConsumeTradeServiceImpl extends BaseServiceImpl 0) { // 获取买家用户资源 PayUserResource payUserResource = payUserResourceService.getById(buyerUserId); diff --git a/mall-pay/src/main/resources/bootstrap-prod.yml b/mall-pay/src/main/resources/bootstrap-prod.yml index e0f6e1fb..c43fe6d3 100644 --- a/mall-pay/src/main/resources/bootstrap-prod.yml +++ b/mall-pay/src/main/resources/bootstrap-prod.yml @@ -105,6 +105,7 @@ logging: naming: error config: error netflix: error + lkl: error org: error io: error reactor: error diff --git a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java index e1dae6b2..499cb214 100644 --- a/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java +++ b/mall-shop/src/main/java/com/suisung/mall/shop/store/service/impl/ShopMchEntryServiceImpl.java @@ -473,7 +473,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl recordList = list(queryWrapper); if (CollectionUtil.isEmpty(recordList)) { - return CommonResult.success(null, "暂无申请记录!"); + return CommonResult.success(new JSONObject().set("approval_status", CommonConstant.MCH_APPR_STA_NONE), "请求成功!"); } ShopMchEntry record = recordList.get(0); @@ -1041,7 +1041,7 @@ public class ShopMchEntryServiceImpl extends BaseServiceImpl