|
|
@@ -3,18 +3,12 @@ package com.zsElectric.boot.business.service;
|
|
|
import cn.hutool.core.collection.CollUtil;
|
|
|
import cn.hutool.core.util.ObjectUtil;
|
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
|
-import com.google.gson.Gson;
|
|
|
-import com.google.gson.JsonObject;
|
|
|
import com.zsElectric.boot.business.mapper.*;
|
|
|
import com.zsElectric.boot.business.model.entity.*;
|
|
|
import com.zsElectric.boot.business.model.form.applet.AppLevelOrderForm;
|
|
|
import com.zsElectric.boot.business.model.form.applet.AppUserPayForm;
|
|
|
-import com.zsElectric.boot.business.model.vo.applet.WFTOrderVO;
|
|
|
-import com.zsElectric.boot.business.model.vo.applet.WechatPayParamsVO;
|
|
|
import com.zsElectric.boot.common.constant.SystemConstants;
|
|
|
import com.zsElectric.boot.core.exception.BusinessException;
|
|
|
-import com.zsElectric.boot.core.pay.WFT.WFTConstants;
|
|
|
-import com.zsElectric.boot.core.pay.WechatUrlConstants;
|
|
|
import com.zsElectric.boot.core.pay.swiftpass.config.SwiftpassConfig;
|
|
|
import com.zsElectric.boot.core.pay.swiftpass.util.PayUtill;
|
|
|
import com.zsElectric.boot.core.pay.swiftpass.util.SignUtil;
|
|
|
@@ -22,14 +16,12 @@ import com.zsElectric.boot.core.pay.swiftpass.util.SignUtils;
|
|
|
import com.zsElectric.boot.core.pay.swiftpass.util.XmlUtils;
|
|
|
import com.zsElectric.boot.security.util.SecurityUtils;
|
|
|
import jakarta.annotation.Resource;
|
|
|
-import jakarta.servlet.ServletException;
|
|
|
import jakarta.servlet.http.HttpServletRequest;
|
|
|
import jakarta.validation.Valid;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
-import java.io.IOException;
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.RoundingMode;
|
|
|
import java.text.SimpleDateFormat;
|
|
|
@@ -774,11 +766,11 @@ public class WFTOrderService {
|
|
|
* @return
|
|
|
*/
|
|
|
@Transactional(rollbackFor = Exception.class)
|
|
|
- public String refundOrder() throws Exception {
|
|
|
+ public String refundOrder(Long userId) throws Exception {
|
|
|
|
|
|
//查询账户余额
|
|
|
UserAccount userAccount =
|
|
|
- userAccountService.getOne(Wrappers.<UserAccount>lambdaQuery().eq(UserAccount::getUserId, SecurityUtils.getUserId()).last("limit 1"));
|
|
|
+ userAccountService.getOne(Wrappers.<UserAccount>lambdaQuery().eq(UserAccount::getUserId, userId).last("limit 1"));
|
|
|
if (userAccount.getBalance().compareTo(BigDecimal.ZERO) == 0) {
|
|
|
return "账户余额为 0";
|
|
|
}
|
|
|
@@ -817,12 +809,12 @@ public class WFTOrderService {
|
|
|
}
|
|
|
if ((userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney())).compareTo(refundMoney) < 0) {
|
|
|
//退款金额小于订单金额,则先退订单金额
|
|
|
- refundOrder(userOrderInfo,userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()), "账户退款", SystemConstants.STATUS_ONE);
|
|
|
+ refundOrder(userOrderInfo,userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()), "账户退款", SystemConstants.STATUS_TWO);
|
|
|
//账户变动及日志记录
|
|
|
userAccountService.updateAccountBalanceAndLog(
|
|
|
SecurityUtils.getUserId(),
|
|
|
userOrderInfo.getOrderMoney().subtract(userOrderInfo.getRefundMoney()),
|
|
|
- SystemConstants.CHANGE_TYPE_REDUCE,
|
|
|
+ SystemConstants.ACCOUNT_REFUND,
|
|
|
SystemConstants.ACCOUNT_LOG_REFUND_NOTE,
|
|
|
userOrderInfo.getId()
|
|
|
);
|
|
|
@@ -832,7 +824,7 @@ public class WFTOrderService {
|
|
|
refundMoney = refundMoney.subtract(userOrderInfo.getOrderMoney());
|
|
|
}
|
|
|
}
|
|
|
- return "账户退款,预计3个工作日内分一笔或多笔退还!如未收到,请联系客服!";
|
|
|
+ return "账户退款,预计3个工作日内分一笔或多笔退还!到期如未收到,请联系客服处理!";
|
|
|
}
|
|
|
|
|
|
public void refundOrder(UserOrderInfo userOrderInfo, BigDecimal refundAmount, String reason, Integer type) throws Exception {
|
|
|
@@ -890,4 +882,152 @@ public class WFTOrderService {
|
|
|
}
|
|
|
|
|
|
}
|
|
|
+ /**
|
|
|
+ * 退款查询
|
|
|
+ *
|
|
|
+ * 应用场景:
|
|
|
+ * 1. 提交退款申请后,通过调用该接口查询退款状态
|
|
|
+ * 2. 退款有一定延时,请在3个工作日后重新查询退款状态
|
|
|
+ *
|
|
|
+ * 参数优先级:
|
|
|
+ * refund_id > out_refund_no > transaction_id > out_trade_no
|
|
|
+ *
|
|
|
+ * 退款状态:
|
|
|
+ * - SUCCESS:退款成功
|
|
|
+ * - FAIL:退款失败
|
|
|
+ * - PROCESSING:退款处理中
|
|
|
+ * - CHANGE:转入代发,退款到银行发现用户的卡作废或者冻结了,
|
|
|
+ * 导致原路退款银行卡失败,资金回流到商户的现金帐号,
|
|
|
+ * 需要商户人工干预,通过线下或者平台转账的方式进行退款
|
|
|
+ *
|
|
|
+ * @param outTradeNo 商户订单号(四选一)
|
|
|
+ * @param transactionId 平台订单号(四选一)
|
|
|
+ * @param outRefundNo 商户退款单号(四选一)
|
|
|
+ * @param refundId 平台退款单号(四选一,优先级最高)
|
|
|
+ * @return 退款查询结果
|
|
|
+ */
|
|
|
+ public Map<String, Object> queryRefund(String outTradeNo, String transactionId,
|
|
|
+ String outRefundNo, String refundId) {
|
|
|
+ log.info("========== 开始查询退款状态 ==========");
|
|
|
+ log.info("查询参数: outTradeNo={}, transactionId={}, outRefundNo={}, refundId={}",
|
|
|
+ outTradeNo, transactionId, outRefundNo, refundId);
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 1. 参数校验 - 四个参数至少需要一个
|
|
|
+ if (outTradeNo == null && transactionId == null &&
|
|
|
+ outRefundNo == null && refundId == null) {
|
|
|
+ log.error("退款查询参数不能全为空");
|
|
|
+ Map<String, Object> errorResult = new HashMap<>();
|
|
|
+ errorResult.put("status", "500");
|
|
|
+ errorResult.put("msg", "查询参数不能全为空,请提供 outTradeNo/transactionId/outRefundNo/refundId 中的任意一个");
|
|
|
+ return errorResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 2. 构建查询请求参数
|
|
|
+ SortedMap<String, String> queryParams = new TreeMap<>();
|
|
|
+
|
|
|
+ // 按优先级添加参数:refund_id > out_refund_no > transaction_id > out_trade_no
|
|
|
+ if (refundId != null && !refundId.trim().isEmpty()) {
|
|
|
+ queryParams.put("refund_id", refundId);
|
|
|
+ } else if (outRefundNo != null && !outRefundNo.trim().isEmpty()) {
|
|
|
+ queryParams.put("out_refund_no", outRefundNo);
|
|
|
+ } else if (transactionId != null && !transactionId.trim().isEmpty()) {
|
|
|
+ queryParams.put("transaction_id", transactionId);
|
|
|
+ } else if (outTradeNo != null && !outTradeNo.trim().isEmpty()) {
|
|
|
+ queryParams.put("out_trade_no", outTradeNo);
|
|
|
+ }
|
|
|
+
|
|
|
+ queryParams.put("sign_type", "RSA_1_256"); // 签名方式
|
|
|
+
|
|
|
+ // 3. 调用威富通退款查询API
|
|
|
+ PayUtill payUtill = new PayUtill();
|
|
|
+ Map<String, Object> queryResult = payUtill.refundQuery(queryParams, swiftpassConfig);
|
|
|
+
|
|
|
+ log.info("威富通退款查询返回结果: {}", queryResult);
|
|
|
+
|
|
|
+ // 4. 解析查询结果
|
|
|
+ if ("200".equals(queryResult.get("status"))) {
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, String> dataMap = (Map<String, String>) queryResult.get("data");
|
|
|
+
|
|
|
+ if (dataMap == null) {
|
|
|
+ log.error("退款查询结果数据为空");
|
|
|
+ queryResult.put("status", "500");
|
|
|
+ queryResult.put("msg", "查询结果数据为空");
|
|
|
+ return queryResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 5. 检查业务结果
|
|
|
+ String status = dataMap.get("status");
|
|
|
+ String resultCode = dataMap.get("result_code");
|
|
|
+
|
|
|
+ if (!"0".equals(status) || !"0".equals(resultCode)) {
|
|
|
+ log.error("退款查询失败: status={}, result_code={}, err_code={}, err_msg={}",
|
|
|
+ status, resultCode, dataMap.get("err_code"), dataMap.get("err_msg"));
|
|
|
+ queryResult.put("status", "500");
|
|
|
+ queryResult.put("msg", dataMap.get("err_msg"));
|
|
|
+ return queryResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 6. 解析退款记录信息
|
|
|
+ Integer refundCount = Integer.parseInt(dataMap.getOrDefault("refund_count", "0"));
|
|
|
+ log.info("退款笔数: {}", refundCount);
|
|
|
+
|
|
|
+ // 7. 构造返回结果
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
+ result.put("status", "200");
|
|
|
+ result.put("mch_id", dataMap.get("mch_id"));
|
|
|
+ result.put("trade_type", dataMap.get("trade_type"));
|
|
|
+ result.put("out_transaction_id", dataMap.get("out_transaction_id"));
|
|
|
+ result.put("transaction_id", dataMap.get("transaction_id"));
|
|
|
+ result.put("out_trade_no", dataMap.get("out_trade_no"));
|
|
|
+ result.put("refund_count", refundCount);
|
|
|
+
|
|
|
+ // 8. 解析退款记录列表(支持多笔退款)
|
|
|
+ if (refundCount > 0) {
|
|
|
+ java.util.List<Map<String, Object>> refundList = new java.util.ArrayList<>();
|
|
|
+
|
|
|
+ for (int i = 0; i < refundCount; i++) {
|
|
|
+ Map<String, Object> refundRecord = new HashMap<>();
|
|
|
+ String suffix = "_" + i;
|
|
|
+
|
|
|
+ // 提取每笔退款的详细信息
|
|
|
+ refundRecord.put("out_refund_id", dataMap.get("out_refund_id" + suffix));
|
|
|
+ refundRecord.put("out_refund_no", dataMap.get("out_refund_no" + suffix));
|
|
|
+ refundRecord.put("refund_id", dataMap.get("refund_id" + suffix));
|
|
|
+ refundRecord.put("refund_channel", dataMap.get("refund_channel" + suffix));
|
|
|
+ refundRecord.put("refund_fee", dataMap.get("refund_fee" + suffix));
|
|
|
+ refundRecord.put("coupon_refund_fee", dataMap.get("coupon_refund_fee" + suffix));
|
|
|
+ refundRecord.put("refund_time", dataMap.get("refund_time" + suffix));
|
|
|
+ refundRecord.put("refund_status", dataMap.get("refund_status" + suffix));
|
|
|
+ refundRecord.put("refund_status_info", dataMap.get("refund_status_info" + suffix));
|
|
|
+
|
|
|
+ refundList.add(refundRecord);
|
|
|
+
|
|
|
+ log.info("退款记录[{}]: refund_id={}, refund_status={}, refund_fee={}",
|
|
|
+ i, refundRecord.get("refund_id"),
|
|
|
+ refundRecord.get("refund_status"),
|
|
|
+ refundRecord.get("refund_fee"));
|
|
|
+ }
|
|
|
+
|
|
|
+ result.put("refund_list", refundList);
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("退款查询成功");
|
|
|
+ return result;
|
|
|
+ } else {
|
|
|
+ log.error("退款查询调用失败: {}", queryResult);
|
|
|
+ return queryResult;
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ log.error("查询退款状态异常", e);
|
|
|
+ Map<String, Object> errorResult = new HashMap<>();
|
|
|
+ errorResult.put("status", "500");
|
|
|
+ errorResult.put("msg", "系统异常: " + e.getMessage());
|
|
|
+ return errorResult;
|
|
|
+ } finally {
|
|
|
+ log.info("========== 退款状态查询完成 ==========");
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|