feat(transaction): 实现分账查询功能并优化退款流程

- 新增分账查询接口和相关 BO、VO 类
- 优化退款流程,增加退款流水号字段- 更新数据库表结构和 Mapper 文件
- 重构部分代码以支持新功能
This commit is contained in:
huk 2025-09-12 17:46:27 +08:00
parent ccf2c6b02e
commit 4b738e47ea
23 changed files with 161 additions and 336 deletions

View File

@ -51,6 +51,9 @@ public class AftersaleBo {
@Schema(description = "处理人员 精确匹配")
private String handleMan;
@Schema(description = "退款流水号")
private String orgTrace;
@Schema(name = "startTime", description = "开始时间", required = true, implementation = LocalDateTime.class)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ -75,6 +78,7 @@ public class AftersaleBo {
.eq(proofPics != null && !proofPics.isEmpty(), Aftersale::getProofPics, proofPics)
.eq(handleNote != null && !handleNote.isEmpty(), Aftersale::getHandleNote, handleNote)
.eq(handleMan != null && !handleMan.isEmpty(), Aftersale::getHandleMan, handleMan)
.eq(orgTrace != null && !orgTrace.isEmpty(), Aftersale::getOrgTrace, orgTrace)
.between(startTime != null && endTime != null, Aftersale::getCreateTime, startTime, endTime)
.ge(startTime != null && endTime == null, Aftersale::getCreateTime, startTime)
.le(endTime != null && startTime == null, Aftersale::getCreateTime, endTime);

View File

@ -51,6 +51,9 @@ public class RefundBO {
@Schema(description = "退款总金额", hidden = true)
private BigDecimal totalRefundAmount;
@Schema(description = "退款流水号", hidden = true)
private String orgTrace;
@Data
@AllArgsConstructor

View File

@ -74,6 +74,10 @@ public class Aftersale extends BaseAudit {
@Excel(name = "处理人员")
private String handleMan;
@Schema(description = "退款流水号")
@Excel(name = "退款流水号")
private String orgTrace;
@Schema(description = "退款快递公司")
@Excel(name = "退款快递公司")
private String refundWpCode;

View File

@ -50,4 +50,7 @@ public class AftersaleQuery extends BaseBO {
@Schema(description = "处理人员 精确匹配")
private String handleMan;
@Schema(description = "退款流水号")
private String orgTrace;
}

View File

@ -88,6 +88,10 @@ public class AftersaleVO extends BaseAudit {
@Excel(name = "处理人员")
private String handleMan;
@Schema(description = "退款流水号")
@Excel(name = "退款流水号")
private String orgTrace;
@Schema(description = "审核状态 1.待审核;->2.审核通过;3->审核驳回")
@Excel(name = "审核状态 1.待审核;->2.审核通过;3->审核驳回")
private Integer authFlag;

View File

@ -284,7 +284,6 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
.payAmount(order.getPayAmount().subtract(refundBO.getTotalRefundAmount()))
.status(OrderStatusEnum.REFUNDED_SUCCESS.getValue())
.build());
// 更新售后记录
Aftersale aftersale = aftersaleMapper.selectOne(Wrappers.lambdaQuery(Aftersale.class)
.eq(Aftersale::getOrderId, orderId).last("limit 1"));
@ -292,6 +291,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
aftersale = new Aftersale();
aftersale.setMemberId(order.getMemberId());
aftersale.setOrderId(orderId);
aftersale.setOrgTrace(refundBO.getOrgTrace());
aftersale.setReturnAmount(refundBO.getTotalRefundAmount());
aftersale.setQuantity(refundItemBoList.size());
aftersale.setType(1);
@ -301,6 +301,7 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
aftersaleMapper.insert(aftersale);
}else{
aftersale.setReturnAmount(refundBO.getTotalRefundAmount());
aftersale.setOrgTrace(refundBO.getOrgTrace());
aftersale.setStatus(AftersaleStatus.PAID.getCode());
aftersale.setQuantity(refundItemBoList.size());
aftersaleMapper.updateById(aftersale);

View File

@ -18,6 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<result property="proofPics" column="proof_pics"/>
<result property="handleNote" column="handle_note"/>
<result property="handleMan" column="handle_man"/>
<result property="orgTrace" column="org_trace"/>
<result property="createBy" column="create_by"/>
<result property="createTime" column="create_time"/>
<result property="updateBy" column="update_by"/>
@ -29,7 +30,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
</resultMap>
<sql id="selectAftersaleVo">
select id, member_id, order_id, return_amount, type, status, handle_time, quantity, reason, description, proof_pics, handle_note, handle_man, create_by, create_time, update_by, update_time from oms_aftersale
select id, member_id, order_id, return_amount, type, status, handle_time, quantity, reason, description, proof_pics, handle_note, handle_man, org_trace, create_by, create_time, update_by, update_time from oms_aftersale
</sql>
<select id="selectByEntity" parameterType="Aftersale" resultMap="AftersaleResult">
@ -47,6 +48,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<if test="proofPics != null and proofPics != ''"> and proof_pics = #{proofPics}</if>
<if test="handleNote != null and handleNote != ''"> and handle_note = #{handleNote}</if>
<if test="handleMan != null and handleMan != ''"> and handle_man = #{handleMan}</if>
<if test="orgTrace != null and orgTrace != ''"> and org_trace = #{orgTrace}</if>
</where>
</select>
<select id="selectManagerRefundOrder" resultType="com.wzj.soopin.order.domain.vo.ManagerRefundOrderVO">
@ -63,6 +65,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
a.handle_time handleTime,
a.handle_note note,
a.handle_man,
a.org_trace,
c.nickname nickName,
c.phone_hidden phone,
c.mark,

View File

@ -59,7 +59,7 @@ public class DivideController {
@Tag(name = "根据订单id分账")
@Log(title = "分账", businessType = BusinessType.DELETE)
@GetMapping("/divide/{orderId}")
@PostMapping("/divide/{orderId}")
public R divide(@PathVariable Long orderId) {
service.divide(orderId);
return R.ok();

View File

@ -7,6 +7,7 @@ import com.wzj.soopin.transaction.domain.bo.MerchantAddBO;
import com.wzj.soopin.transaction.domain.bo.PaymentBO;
import com.wzj.soopin.order.domain.bo.RefundBO;
import com.wzj.soopin.transaction.domain.bo.easypay.EasyPayRequest;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateRespOrderInfo;
import com.wzj.soopin.transaction.domain.vo.EasypayTransResultVO;
import com.wzj.soopin.transaction.domain.vo.EasypayPrePayVO;
import com.wzj.soopin.transaction.service.IEasypayService;
@ -43,7 +44,6 @@ public class TransEasypayController {
* @param easyPayRequest
*/
@SaIgnore
@Log(title = "易生支付-支付结果通知回调", businessType = BusinessType.UPDATE)
@PostMapping("/trade/callback")
public Map tradeCallback(@RequestBody EasyPayRequest easyPayRequest) {
easypayService.handleTradeCallback(easyPayRequest);
@ -83,7 +83,7 @@ public class TransEasypayController {
* @param refundBO 退款信息
*/
@Log(title = "易生支付-实时退款", businessType = BusinessType.OTHER)
@PostMapping("/refund/{orderId}")
@PostMapping("/refund")
@SaCheckPermission(value = "trans:easypay:refund",mode = SaMode.OR, orRole = TenantConstants.TENANT_ADMIN_ROLE_KEY)
public R refund(@RequestBody RefundBO refundBO) throws ServerException {
easypayService.refund(refundBO);
@ -101,6 +101,17 @@ public class TransEasypayController {
return R.ok(easypayTransResultVO);
}
/**
* 查询分账结果
*
* @param orderItemId 订单详情id
*/
@GetMapping("/separateqQuery/{orderItemId}")
public R<SeparateRespOrderInfo> separateqQuery(@PathVariable("orderItemId") Long orderItemId) throws ServerException {
return R.ok(easypayService.separateqQuery(orderItemId));
}
/**
* 上传图片至易生
*

View File

@ -49,9 +49,9 @@ public class SeparateRespInfoList {
private Long sepaRatio;
/**
* 分账单状态处理中成功失败已退款
* REFUNDED 分账已回退
* SUCCESS 分账成功
* PENDING 待处理
* 分账已回退
* o 分账成功
* 待处理
*/
private String sepaStatus;
/**

View File

@ -37,4 +37,12 @@ public class SeparateRespOrderInfo {
* 分账单信息列表
*/
private List<SeparateRespInfoList> separateRespInfoList;
/**
* 分账总单流水号 分账查询接口返回等同于分账接口响应中的separateBatchTrace
*/
private String oriSeparateBatchTrace;
}

View File

@ -1,33 +0,0 @@
package com.wzj.soopin.transaction.domain.bo.easypay.separate.cancel.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CancelReqOrderInfo {
/**
* 商户订单号商户生成请求易生的流水号
*/
private String orgTrace;
/**
* 原分账总单流水
*/
private String oriSeparateBatchTrace;
/**
* 原分账子单流水号
*/
private String oriSeparateTrade;
/**
* 原业务日期
*/
private String oriTransDate;
/**
* 回退金额
*/
private long refundAmount;
}

View File

@ -1,30 +0,0 @@
package com.wzj.soopin.transaction.domain.bo.easypay.separate.cancel.req;
import com.wzj.soopin.transaction.domain.bo.easypay.PayInfo;
import com.wzj.soopin.transaction.domain.bo.easypay.ReqInfo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 分账回退请求体
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SeparateCancelReqBody {
/**
* 支付信息
*/
private PayInfo payInfo;
/**
* 请求方信息
*/
private ReqInfo reqInfo;
/**
* 基础订单信息
*/
private CancelReqOrderInfo reqOrderInfo;
}

View File

@ -1,106 +0,0 @@
package com.wzj.soopin.transaction.domain.bo.easypay.separate.cancel.resp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CancelRespOrderInfo {
/**
* 同批次分账笔数
*/
private Long batchNum;
/**
* 同批次分账金额合计
*/
private Long batchTransAmount;
/**
* 商户订单号商户生成请求易生的流水号每次都要唯一
*/
private String orgTrace;
/**
* 原商户订单号
*/
private String oriOrgTrace;
/**
* 产品订单号
*/
private String productTrace;
/**
* 原分账批次号原分账总单流水号
*/
private String separateBatchTrace;
/**
* 分账单信息列表
*/
private List<SeparateRespInfoList> separateRespInfoList;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class SeparateRespInfoList {
/**
* 分账订单标题请求方上送
*/
private String body;
/**
* 分账-秒到标识(1: 0)
*/
private String isD0;
/**
* 分账收款方商户号请求方上送
*/
private String receiveMchtCode;
/**
* 当前分账单已退款金额总计
*/
private Long refundAmountSum;
/**
* 分账手续费承担金额(金额和比例都支持传,2选1),根据资产单金额来算比例请求方上送
*/
private Long sepaFeeAmount;
/**
* 分账手续费承担比例(金额和比例都支持传,2选1),30代表百万分之30请求方上送
*/
private Long sepaFeeRatio;
/**
* 分账平台应结金额
*/
private Long sepaPlatStlmAmount;
/**
* 分账单商户订单号请求方上送
*/
private String separateTrade;
/**
* 分账比例请求方上送
*/
private Long sepaRatio;
/**
* 分账单状态处理中成功失败已退款
*/
private String sepaStatus;
/**
* 分账单状态说明
*/
private String sepaStatusDesc;
/**
* 分账实际结算金额
*/
private Long sepaStlmAmount;
/**
* 分账金额请求方上送
*/
private Long sepaTransAmount;
/**
* 分账订单描述请求方上送
*/
private String subject;
}
}

View File

@ -1,25 +0,0 @@
package com.wzj.soopin.transaction.domain.bo.easypay.separate.cancel.resp;
import com.wzj.soopin.transaction.domain.bo.easypay.RespStateInfo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 分账回退响应体
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class SeparateCancelRespBody {
/**
* 基础订单信息
*/
private CancelRespOrderInfo respOrderInfo;
/**
* 返回码信息
*/
private RespStateInfo respStateInfo;
}

View File

@ -1,21 +0,0 @@
package com.wzj.soopin.transaction.domain.bo.easypay.separate.query.req;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CancelQueryReqOrderInfo {
/**
* 原分账批次流水separateBatchTrace原分账总单流水号
*/
private String oriSeparateBatchTrace;
/**
* 原请求分账日期
*/
private String oriTransDate;
}

View File

@ -26,5 +26,20 @@ public class SeparateQueryReqBody {
/**
* 基础订单信息
*/
private CancelQueryReqOrderInfo reqOrderInfo;
private ReqOrderInfo reqOrderInfo;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class ReqOrderInfo {
/**
* 原分账批次流水separateBatchTrace原分账总单流水号
*/
private String oriSeparateBatchTrace;
/**
* 原请求分账日期
*/
private String oriTransDate;
}
}

View File

@ -1,99 +0,0 @@
package com.wzj.soopin.transaction.domain.bo.easypay.separate.query.resp;
import com.wzj.soopin.transaction.enums.easypay.SepaStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class CancelQueryRespOrderInfo {
/**
* 同批次分账笔数
*/
private Long batchNum;
/**
* 同批次分账金额合计
*/
private Long batchTransAmount;
/**
* 分账总单流水号
*/
private String oriSeparateBatchTrace;
/**
* 产品订单号
*/
private String productTrace;
/**
* 分账单信息列表
*/
private List<SeparateRespInfoList> separateRespInfoList;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public static class SeparateRespInfoList {
/**
* 分账订单标题
*/
private String body;
/**
* 分账D0标识
*/
private String isD0;
/**
* 分账收款方商户号
*/
private String receiveMchtCode;
/**
* 当前分账单已退款金额总计
*/
private Long refundAmountSum;
/**
* 分账手续费承担本金金额
*/
private Long sepaFeeAmount;
/**
* 分账手续费承担本金比例
*/
private Long sepaFeeRatio;
/**
* 分账平台应结金额
*/
private Long sepaPlatStlmAmount;
/**
* 分账单商户订单号
*/
private String separateTrade;
/**
* 分账比例
*/
private Long sepaRatio;
/**
* 分账单状态处理中成功失败已退款
*/
private SepaStatus sepaStatus;
/**
* 分账单状态说明
*/
private String sepaStatusDesc;
/**
* 分账实际结算金额
*/
private Long sepaStlmAmount;
/**
* 分账金额
*/
private Long sepaTransAmount;
/**
* 分账订单描述
*/
private String subject;
}
}

View File

@ -1,6 +1,7 @@
package com.wzj.soopin.transaction.domain.bo.easypay.separate.query.resp;
import com.wzj.soopin.transaction.domain.bo.easypay.RespStateInfo;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateRespOrderInfo;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@ -18,7 +19,7 @@ public class SeparateQueryRespBody {
/**
* 基础订单信息
*/
private CancelQueryRespOrderInfo respOrderInfo;
private SeparateRespOrderInfo respOrderInfo;
/**
* 返回码信息
*/

View File

@ -15,7 +15,7 @@ import java.util.Arrays;
@AllArgsConstructor
public enum SepaStatus {
SUCCESS("SUCCESS", "成功"),
SUCCESS("0", "成功"),
FAIL("FAIL", "失败"),
PENDING("PENDING", "处理中"),
PROCESSING("PROCESSING", "处理中"),

View File

@ -7,6 +7,7 @@ import com.wzj.soopin.order.domain.bo.RefundBO;
import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO;
import com.wzj.soopin.transaction.domain.bo.SeparateRefundBO;
import com.wzj.soopin.transaction.domain.bo.easypay.EasyPayRequest;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateRespOrderInfo;
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO;
import com.wzj.soopin.transaction.domain.vo.EasypayTransResultVO;
import com.wzj.soopin.transaction.domain.vo.EasypayPrePayVO;
@ -59,13 +60,25 @@ public interface IEasypayService {
*/
SeparateApplyBO separateApply(SeparateApplyBO separateApplyBO);
String merchantPicUpload(MultipartFile pic) throws IOException;
void merchantAdd(MerchantAddBO merchantAddBO);
void merchantBinding(String mchtCode);
/**
* 分账查询
*
* @param orderId
* @return
*/
SeparateRespOrderInfo separateqQuery(Long orderItemId);
/**
* 分账回退
* @param separateRefundBO
* @return
*/
boolean separateRefund(SeparateRefundBO separateRefundBO);
/**

View File

@ -243,13 +243,14 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
.transDate(payOrder.getEndTransDate())
.transSumAmt(payOrder.getTransAmount())
.transSumCount((long) separateItemBOList.size())
.separateBatchTrace(String.valueOf(divide.getId()))
.separateBatchTrace(divide.getSeparateBatchTrace())
.separateItemBOList(separateItemBOList)
.build();
// String sss = "{\"divideId\":1965718953028759554,\"orderId\":1965688269369024513,\"payId\":1965688289677844482,\"separateBatchTrace\":\"1965718953028759554\",\"separateItemBOList\":[{\"divideDetailId\":1965718953473355777,\"receiveMchtCode\":\"KK0000000000985\",\"sepaFeeRatio\":95,\"sepaRatio\":95,\"separateTrade\":\"WZJ_1965718953460236288\"},{\"divideDetailId\":1965718953515298817,\"receiveMchtCode\":\"631000000003325\",\"sepaFeeRatio\":5,\"sepaRatio\":5,\"separateTrade\":\"WZJ_1965718953514762240\"}],\"transDate\":\"2025-09-10 16:06:33\",\"transSumAmt\":100,\"transSumCount\":2}";
// separateApplyBO = JSONObject.parseObject(sss, SeparateApplyBO.class);
easypayService.separateApply(separateApplyBO);
}
// String sss = "{\"divideId\":1966406009702875137,\"orderId\":1965688269369024513,\"payId\":1965688289677844482,\"separateBatchTrace\":\"1966401173213224961\",\"separateItemBOList\":[{\"divideDetailId\":1966406024735260674,\"receiveMchtCode\":\"KK0000000000985\",\"sepaFeeRatio\":95,\"sepaRatio\":95,\"separateTrade\":\"WZJ_1966401200823730176\"},{\"divideDetailId\":1966406024768815105,\"receiveMchtCode\":\"631000000003325\",\"sepaFeeRatio\":5,\"sepaRatio\":5,\"separateTrade\":\"WZJ_1966401200882450432\"}],\"transDate\":\"2025-09-10 16:06:33\",\"transSumAmt\":100,\"transSumCount\":2}";
// SeparateApplyBO separateApplyBO = JSONObject.parseObject(sss, SeparateApplyBO.class);
// easypayService.separateApply(separateApplyBO);
}
/**

View File

@ -18,10 +18,11 @@ import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.wzj.soopin.order.domain.bo.RefundBO;
import com.wzj.soopin.order.domain.entity.Aftersale;
import com.wzj.soopin.order.domain.entity.Order;
import com.wzj.soopin.order.domain.entity.OrderItem;
import com.wzj.soopin.order.emum.OrderStatusEnum;
import com.wzj.soopin.order.mapper.OrderMapper;
import com.wzj.soopin.order.service.AftersaleService;
import com.wzj.soopin.order.service.OrderItemService;
import com.wzj.soopin.order.service.OrderService;
import com.wzj.soopin.transaction.config.EasypayConfig;
@ -40,6 +41,8 @@ import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.req.SeparateR
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateApplyRespBody;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateRespInfoList;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateRespOrderInfo;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.query.req.SeparateQueryReqBody;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.query.resp.SeparateQueryRespBody;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.refund.resp.SeparateRefundRespBody;
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.req.*;
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.JsApiRespBody;
@ -77,6 +80,7 @@ import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.rmi.ServerException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@ -102,6 +106,8 @@ public class EasypayServiceImpl implements IEasypayService {
private final OrderItemService orderItemService;
private final AftersaleService aftersaleService;
private final PayOrderMapper payOrderMapper;
private final DivideMapper divideMapper;
@ -579,16 +585,18 @@ public class EasypayServiceImpl implements IEasypayService {
}
refundBO.setTotalRefundAmount(refundAmount);
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
String orgTrace = StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString();
RefundApplyReqBody refundApplyReqBody = RefundApplyReqBody.builder()
.reqInfo(ReqInfo.builder().mchtCode(easypayConfig.getMchtCode()).build())
.payInfo(PayInfo.builder().transDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, new Date())).build())
.reqOrderInfo(RefundReqOrderInfo.builder()
.orgTrace(StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString())
.orgTrace(orgTrace)
.oriOrgTrace(String.valueOf(order.getPayId()))
.oriTransDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, payOrder.getEndTransDate()))
.refundAmount(refundAmount.multiply(BigDecimal.valueOf(100)).longValue())
.build())
.build();
refundBO.setOrgTrace(orgTrace);
String reqSign = getSignStr(reqHeader, refundApplyReqBody);
EasyPayRequest easyRequest = EasyPayRequest.builder()
.reqHeader(reqHeader)
@ -641,6 +649,9 @@ public class EasypayServiceImpl implements IEasypayService {
if (payOrder.getTransState() == TransState.REFUNDED.getCode()) {
return easypayTransResultVO;
}
Aftersale aftersale = aftersaleService.getOne(Wrappers.lambdaQuery(Aftersale.class)
.eq(Aftersale::getOrderId, orderId).orderByDesc(Aftersale::getCreateTime).last("limit 1"));
Assert.notNull(aftersale, () -> new ServiceException("订单无售后单"));
Assert.isTrue(payOrder.getTransState() == TransState.PAID.getCode() || payOrder.getTransState() == TransState.REFUND_PENDING.getCode(), () -> new ServiceException("订单未支付或退款中"));
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
RefundApplyReqBody refundApplyReqBody = RefundApplyReqBody.builder()
@ -648,7 +659,8 @@ public class EasypayServiceImpl implements IEasypayService {
.payInfo(PayInfo.builder().transDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, new Date())).build())
.reqOrderInfo(RefundReqOrderInfo.builder()
.orgTrace(StrBuilder.create(TRACE_PREFIX).append(SnowFlake.getIdStr()).toString())
.oriOrgTrace(String.valueOf(order.getPayId()))
.oriOrgTrace(aftersale.getOrgTrace())
.oriOutTrace(String.valueOf(order.getPayId()))
.oriTransDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, payOrder.getEndTransDate()))
.refundAmount(payOrder.getTransAmount())
.build())
@ -659,14 +671,14 @@ public class EasypayServiceImpl implements IEasypayService {
.reqBody(refundApplyReqBody)
.reqSign(reqSign)
.build();
log.debug("调用易生实时退款接口请求:{}", JSONObject.toJSONString(easyRequest));
log.debug("调用易生实时退款查询接口请求:{}", JSONObject.toJSONString(easyRequest));
String url = StrBuilder.create(easypayConfig.getApiPathPrefix()).append("/trade/refund/query").toString();
String body = HttpRequest.post(url)
.timeout(3000)
.body(JSON.toJSONString(easyRequest))
.execute()
.body();
log.debug("调用易实时退款接口响应:{}", body);
log.debug("调用易实时退款查询接口响应:{}", body);
EasyPayResponse easyPayResponse = JSONObject.parseObject(body, EasyPayResponse.class);
if (StrUtil.equals(RSP_HEADER_OK, easyPayResponse.getRspHeader().getRspCode())) {
verify(easyPayResponse.getRspHeader(), easyPayResponse.getRspBody(), easyPayResponse.getRspSign());
@ -719,7 +731,7 @@ public class EasypayServiceImpl implements IEasypayService {
.body(JSON.toJSONString(easyRequest))
.execute()
.body();
// String body = "{\"rspBody\":{\"respStateInfo\":{\"respDesc\":\"结算域处理成功\",\"transStatusDesc\":\"成功\",\"transState\":\"0\",\"respCode\":\"000000\"},\"respOrderInfo\":{\"separateBatchTrace\":\"1965718953028759554\",\"batchNum\":2,\"separateRespInfoList\":[{\"sepaStatusDesc\":\"分账成功\",\"separateTrade\":\"WZJ_1965718953460236288\",\"sepaFeeRatio\":950000,\"sepaTransAmount\":95,\"sepaPlatStlmAmount\":95,\"sepaStatus\":\"0\",\"sepaStlmAmount\":94,\"sepaRatio\":950000,\"receiveMchtCode\":\"KK0000000000985\"},{\"sepaStatusDesc\":\"分账成功\",\"separateTrade\":\"WZJ_1965718953514762240\",\"sepaFeeRatio\":50000,\"sepaTransAmount\":5,\"sepaPlatStlmAmount\":5,\"sepaStatus\":\"0\",\"sepaStlmAmount\":5,\"sepaRatio\":50000,\"receiveMchtCode\":\"631000000003325\"}],\"productTrace\":\"YQ20250910174300269926\",\"batchTransAmount\":100}},\"rspHeader\":{\"easyPayCertificateId\":\"00000000\",\"rspCode\":\"000000\",\"rspInfo\":\"SUCCESS\"},\"rspSign\":\"VqMb/QGAW1JfL7iAT2HoUP9hbyDah8StIAUJCG9IFvpUC8vSGSBsRIMb/sKUFkBh2oYmNDXkZeD/NRhy1vc8Fe1uZZQAwTUo77fect7FcfxnoYFUHmTrEhekJaozObU8Ks3v2WJ2XDDIk7m4D0uX0dm5cZ25ml4xGf67Y+HN6n0ZF31ESFz9hPARDflumSFAcYf0Inw/3oybU0OBUkLDtT+Mi3cLVShdLmtzvcf6cR2p8k3jUpbyd+eDtQ8FPnkhQP8QmnkDF944VmARlexrS+BqBt5XtcXyL5qLXpj0wm0/ps9mK7c2ZWJt5pjgYTi5w4h0TL9JuEFoVESg33Otkg==\"}";
// String body = "{\"rspBody\":{\"respStateInfo\":{\"respDesc\":\"结算域处理成功\",\"transStatusDesc\":\"成功\",\"transState\":\"0\",\"respCode\":\"000000\"},\"respOrderInfo\":{\"separateBatchTrace\":\"1966401173213224961\",\"batchNum\":2,\"separateRespInfoList\":[{\"sepaStatusDesc\":\"分账成功\",\"separateTrade\":\"WZJ_1966401200823730176\",\"sepaFeeRatio\":950000,\"sepaTransAmount\":95,\"sepaPlatStlmAmount\":95,\"sepaStatus\":\"0\",\"sepaStlmAmount\":94,\"sepaRatio\":950000,\"receiveMchtCode\":\"KK0000000000985\"},{\"sepaStatusDesc\":\"分账成功\",\"separateTrade\":\"WZJ_1966401200882450432\",\"sepaFeeRatio\":50000,\"sepaTransAmount\":5,\"sepaPlatStlmAmount\":5,\"sepaStatus\":\"0\",\"sepaStlmAmount\":5,\"sepaRatio\":50000,\"receiveMchtCode\":\"631000000003325\"}],\"productTrace\":\"YQ20250912151915270199\",\"batchTransAmount\":100}},\"rspHeader\":{\"easyPayCertificateId\":\"00000000\",\"rspCode\":\"000000\",\"rspInfo\":\"SUCCESS\"},\"rspSign\":\"bFVXEDsVM1oSZxyigMFRQgK2LOee+sy2OiyTjdMkfL58NSKk2VKaH6WCnedassTY5k809+wlqI0smKOhCNCjZz+Z7E6p4dx3uOMtRdHTyYZ07o2qmy3EUOFcDBmfCiSJPEKXcRsRXMjipzvFKLFsNY+W03HdxBswXefcFUSVo4YZ9s+FGQpISjtr0aQiJgMk8mDFbqm6ocYvnbCpnu594YgJFVY7+rQNknY1M7RLTWlyUMiZq6rvDuM+Ii8sHJS7npnbhwLwYDNQKYmcTav2GckVPxlVPsFnlaDAMyObziYVpqL6xLA8A3ourxgpWxgffQuz6IkD0KwKEO1WQ1jjOw==\"}";
log.debug("调用易生请求分账接口响应:{}", body);
EasyPayResponse easyPayResponse = JSONObject.parseObject(body, EasyPayResponse.class);
if (StrUtil.equals(RSP_HEADER_OK, easyPayResponse.getRspHeader().getRspCode())) {
@ -759,9 +771,10 @@ public class EasypayServiceImpl implements IEasypayService {
DivideDetail divideDetail = DivideDetail.builder()
.id(separateItemBO.getDivideDetailId())
.separateTrade(separateRespInfo.getSeparateTrade())
.separateTime(LocalDateTime.now())
.build();
divideDetail.setMoney(BigDecimal.valueOf(separateRespInfo.getSepaTransAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
divideDetail.setFee(BigDecimal.valueOf(separateRespInfo.getSepaFeeAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
divideDetail.setFee(BigDecimal.valueOf(separateRespInfo.getSepaPlatStlmAmount() - separateRespInfo.getSepaStlmAmount()));
SepaStatus sepaStatus = SepaStatus.getByValue(separateRespInfo.getSepaStatus());
switch (sepaStatus) {
case SUCCESS -> divideDetail.setStatus(DivideStatus.SUCCESS.getCode());
@ -923,6 +936,61 @@ public class EasypayServiceImpl implements IEasypayService {
}
}
@Override
public SeparateRespOrderInfo separateqQuery(Long orderItemId) {
SeparateRespOrderInfo separateRespOrderInfo = null;
OrderItem orderItem = orderItemService.getById(orderItemId);
Assert.notNull(orderItem, () -> new ServiceException("订单子项不存在"));
Divide divide = divideMapper.selectOne(Wrappers.lambdaQuery(Divide.class).eq(Divide::getOrderItemId, orderItemId).last("limit 1"));
Assert.notNull(divide, () -> new ServiceException("订单子项未分账"));
EasyPayRequestHeader reqHeader = generateEasyPayRequestHeader();
SeparateQueryReqBody queryReqBody = SeparateQueryReqBody.builder()
.reqInfo(ReqInfo.builder().mchtCode(easypayConfig.getMchtCode()).build())
.payInfo(PayInfo.builder().transDate(DateUtils.parseDateToStr(FormatsType.YYYYMMDD, new Date())).build())
.reqOrderInfo(SeparateQueryReqBody.ReqOrderInfo.builder()
.oriSeparateBatchTrace(divide.getSeparateBatchTrace())
.oriTransDate(LocalDateTimeUtil.format(divide.getUpdateTime(), "yyyyMMdd"))
.build())
.build();
String reqSign = getSignStr(reqHeader, queryReqBody);
EasyPayRequest easyRequest = EasyPayRequest.builder()
.reqHeader(reqHeader)
.reqBody(queryReqBody)
.reqSign(reqSign)
.build();
log.debug("调用易生查询分账接口请求:{}", JSONObject.toJSONString(easyRequest));
String url = StrBuilder.create(easypayConfig.getApiPathPrefix()).append("/trade/separate/query").toString();
String body = HttpRequest.post(url)
.timeout(3000)
.body(JSON.toJSONString(easyRequest))
.execute()
.body();
log.debug("调用易生查询分账接口响应:{}", body);
EasyPayResponse easyPayResponse = JSONObject.parseObject(body, EasyPayResponse.class);
if (StrUtil.equals(RSP_HEADER_OK, easyPayResponse.getRspHeader().getRspCode())) {
verify(easyPayResponse.getRspHeader(), easyPayResponse.getRspBody(), easyPayResponse.getRspSign());
SeparateQueryRespBody separateQueryRespBody = JSON.parseObject(JSONObject.toJSONString(easyPayResponse.getRspBody()), SeparateQueryRespBody.class);
RespStateInfo respStateInfo = separateQueryRespBody.getRespStateInfo();
if (StrUtil.equals(RSP_BODY_RESP_OK, respStateInfo.getRespCode())) {
// 支付完成 进入终态
if (StrUtil.equalsAny(respStateInfo.getTransState(), RSP_BODY_TRANS_OK, RSP_BODY_TRANS_OK_WETCAT, RSP_BODY_TRANS_PARTIALLY_OK)) {
SeparateRespOrderInfo respOrderInfo = separateQueryRespBody.getRespOrderInfo();
respOrderInfo.setSeparateBatchTrace(divide.getSeparateBatchTrace());
// TODO 处理
// handleSeparateInfo(null,respOrderInfo);
separateRespOrderInfo = respOrderInfo;
}
} else {
log.error("查询支付结果失败:{}", respStateInfo.getRespDesc());
throw new ServiceException("查询支付结果失败:" + respStateInfo.getRespDesc());
}
} else {
log.error("查询支付结果通讯失败:{}", easyPayResponse.getRspHeader().getRspInfo());
throw new ServiceException("查询支付结果通讯失败:" + easyPayResponse.getRspHeader().getRspInfo());
}
return separateRespOrderInfo;
}
/**
* 分账回退
*