feat(transaction): 完善分账功能并更新订单状态

- 在订单表中添加分账状态- 新增分账规则校验逻辑
- 更新分账和订单状态处理流程
- 优化分账失败和异常处理
This commit is contained in:
huk 2025-09-04 14:57:31 +08:00
parent 793c34a96a
commit 15690ac810
17 changed files with 209 additions and 85 deletions

View File

@ -76,8 +76,13 @@ public class Order extends BaseAudit {
@Excel(name = "支付方式0->未支付1->支付宝2->微信") @Excel(name = "支付方式0->未支付1->支付宝2->微信")
private Integer payType; private Integer payType;
@Schema(description = "订单状态0->待支付1->支付中2->已支付3->已关闭4->已退款10->无效订单") @Schema(description = "订单状态0->待支付1->支付中2->已支付3->已关闭4->已退款9->已分账10->无效订单")
@Excel(name = "订单状态0->待付款1->待发货2->已发货3->已完成4->已关闭5->无效订单") @Excel(name = "订单状态0->待支付1->支付中2->已支付3->已关闭4->已退款9->已分账10->无效订单")
/**
* 订单状态0->待支付1->支付中2->已支付3->已关闭4->已退款9->已分账10->无效订单
* 枚举类型见{@link com.wzj.soopin.order.emum.OrderStatusEnum}
*/
private Integer status; private Integer status;
@Schema(description = "退款状态枚举值1无售后或售后关闭2售后处理中3退款中4 退款成功") @Schema(description = "退款状态枚举值1无售后或售后关闭2售后处理中3退款中4 退款成功")

View File

@ -1,29 +1,24 @@
package com.wzj.soopin.order.emum; package com.wzj.soopin.order.emum;
import lombok.AllArgsConstructor;
import lombok.Getter;
/** /**
* 订单状态0->待支付1->支付中2->已支付3->已关闭4->已退款10->无效订单 * 订单状态0->待支付1->支付中2->已支付3->已关闭4->已退款9->已分账10->无效订单
*/ */
@Getter
@AllArgsConstructor
public enum OrderStatusEnum { public enum OrderStatusEnum {
UNPAID(0, "待支付"), UNPAID(0, "待支付"),
PAYMENT(1, "支付中"), PAYMENT(1, "支付中"),
PAID(2, "已支付"), PAID(2, "已支付"),
CLOSED(3, "已关闭"), CLOSED(3, "已关闭"),
REFUNDED(4, "已退款"), REFUNDED(4, "已退款"),
DIVIDED(9, "已分账"),
INVALID(10, "无效订单"); INVALID(10, "无效订单");
private final Integer value; private final Integer value;
private final String info; private final String info;
OrderStatusEnum(Integer value, String info) {
this.value = value;
this.info = info;
}
public Integer getValue() {
return value;
}
public String getInfo() {
return info;
}
} }

View File

@ -11,6 +11,7 @@ import com.wzj.soopin.order.domain.form.ManagerOrderQueryForm;
import com.wzj.soopin.order.domain.vo.*; import com.wzj.soopin.order.domain.vo.*;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -43,4 +44,6 @@ public interface OrderMapper extends BaseMapper<Order> {
Map<String, Object> countOrder(); Map<String, Object> countOrder();
@Update("update oms_order set status = #{status} where id = #{orderId}")
void updateStatusById(@Param("orderId")Long orderId, @Param("status") Integer status);
} }

View File

@ -257,6 +257,10 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
@Override @Override
public void cancel(Long orderId) { public void cancel(Long orderId) {
Order order = orderMapper.selectById(orderId);
LoginUser loginUser = LoginHelper.getLoginUser();
Assert.isTrue(Objects.equals(loginUser.getUserId(), order.getMemberId()), () -> new ServiceException("无权限取消非本人订单"));
Assert.isTrue(OrderStatusEnum.UNPAID.getValue().equals(order.getStatus()), () -> new ServiceException("订单已支付,不能取消"));
orderMapper.updateById(Order.builder().id(orderId).status(OrderStatusEnum.CLOSED.getValue()).build()); orderMapper.updateById(Order.builder().id(orderId).status(OrderStatusEnum.CLOSED.getValue()).build());
} }

View File

@ -1,5 +1,7 @@
package com.wzj.soopin.transaction.domain.bo; package com.wzj.soopin.transaction.domain.bo;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
@ -27,6 +29,12 @@ public class SeparateApplyBO {
*/ */
private Long payId; private Long payId;
/**
* 分账id
*/
private Long divideId;
/** /**
* 支付完成时间 * 支付完成时间
*/ */

View File

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

View File

@ -61,6 +61,7 @@ public class Divide extends BaseEntity {
/** /**
* 状态 * 状态
* 枚举类型见 {@link com.wzj.soopin.transaction.enums.DivideStatus}
*/ */
@Schema(description = "状态") @Schema(description = "状态")
@ExcelProperty(value = "状态", order = 5) @ExcelProperty(value = "状态", order = 5)
@ -89,5 +90,7 @@ public class Divide extends BaseEntity {
@ExcelProperty(value = "订单编号", order = 9) @ExcelProperty(value = "订单编号", order = 9)
private String orderSn; private String orderSn;
private String delFlag;
} }

View File

@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder; import lombok.Builder;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode;
import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.common.mybatis.core.domain.BaseEntity;
import java.math.BigDecimal; import java.math.BigDecimal;
@ -17,6 +18,7 @@ import java.math.BigDecimal;
* @author wzj * @author wzj
* @date 2023-03-07 * @date 2023-03-07
*/ */
@EqualsAndHashCode(callSuper = true)
@Schema(description = "订单分账明细") @Schema(description = "订单分账明细")
@Data @Data
@TableName("trans_divide_detail") @TableName("trans_divide_detail")
@ -78,10 +80,11 @@ public class DivideDetail extends BaseEntity {
* */ * */
private Integer type; private Integer type;
/** /**
* 状态 * 状态
* 枚举类型见 {@link com.wzj.soopin.transaction.enums.DivideStatus}
*/ */
@Schema(description = "状态 0 未分账 1 分账成功 2 分账失败")
@ExcelProperty(value = "状态", order = 5) @ExcelProperty(value = "状态", order = 5)
private Integer status; private Integer status;

View File

@ -67,5 +67,7 @@ public class DivideRule extends BaseEntity {
@ExcelProperty(value ="类型", order = 8) @ExcelProperty(value ="类型", order = 8)
private Integer type; private Integer type;
private String delFlag;
} }

View File

@ -6,10 +6,14 @@ import lombok.Getter;
public enum DivideStatus { public enum DivideStatus {
PENDING(0, "待分账"), PENDING(0, "待分账"),
SUCCESS(1, "分账成功"), PROCESSING(1, "分账中"),
FAIL(2, "分账失败"); SUCCESS(2, "分账成功"),
private int code; FAIL(3, "分账失败"),
private String desc; REFUNDED(4, "已退款");
private final int code;
private final String desc;
DivideStatus(int code, String desc) { DivideStatus(int code, String desc) {
this.code = code; this.code = code;

View File

@ -3,8 +3,12 @@ package com.wzj.soopin.transaction.mapper;
import com.wzj.soopin.transaction.domain.po.DivideDetail; import com.wzj.soopin.transaction.domain.po.DivideDetail;
import com.wzj.soopin.transaction.domain.vo.DivideDetailVO; import com.wzj.soopin.transaction.domain.vo.DivideDetailVO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
import java.util.List;
/** /**
* 意见反馈Mapper接口 * 意见反馈Mapper接口
* *
@ -13,4 +17,6 @@ import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
@Mapper @Mapper
public interface DivideDetailMapper extends BaseMapperPlus<DivideDetail, DivideDetailVO> { public interface DivideDetailMapper extends BaseMapperPlus<DivideDetail, DivideDetailVO> {
@Select("select * from trans_divide_detail where divide_id = #{divideId} and del_flag = '0' ")
List<DivideDetail> selectByDivideId(@Param("divideId") Long divideId);
} }

View File

@ -6,6 +6,7 @@ import com.wzj.soopin.transaction.domain.vo.DivideVO;
import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param; import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
/** /**
* 意见反馈Mapper接口 * 意见反馈Mapper接口
@ -17,6 +18,9 @@ public interface DivideMapper extends BaseMapper<Divide> {
DivideVO getVOById(Long divideId); DivideVO getVOById(Long divideId);
@Select("select * from trans_divide where order_id = #{orderId}") @Select("select * from trans_divide where order_id = #{orderId} and del_flag = '0'")
Divide selectByOrderId(@Param("orderId") Long orderId); Divide selectByOrderId(@Param("orderId") Long orderId);
@Update("update trans_divide set status = #{divideStatus} where id = #{divideId}")
void updateStatus(@Param("divideId") Long divideId, @Param("divideStatus") int divideStatus);
} }

View File

@ -2,12 +2,18 @@ package com.wzj.soopin.transaction.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.wzj.soopin.transaction.domain.po.DivideRule; import com.wzj.soopin.transaction.domain.po.DivideRule;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
/** /**
* 意见反馈Mapper接口 * 意见反馈Mapper接口
* *
* @author zcc * @author zcc
*/ */
@Mapper
public interface DivideRuleMapper extends BaseMapper<DivideRule> { public interface DivideRuleMapper extends BaseMapper<DivideRule> {
@Select("select * from trans_divide_rule where type = #{type} and status = #{status} and del_flag = '0'")
DivideRule getByTypeAndStatus(@Param("type") Integer type, @Param("status") int status);
} }

View File

@ -3,7 +3,11 @@ package com.wzj.soopin.transaction.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.transaction.domain.bo.DivideRuleBO; import com.wzj.soopin.transaction.domain.bo.DivideRuleBO;
import com.wzj.soopin.transaction.domain.po.DivideRule; import com.wzj.soopin.transaction.domain.po.DivideRule;
import com.wzj.soopin.transaction.domain.vo.DivideRuleDetailVO;
import com.wzj.soopin.transaction.domain.vo.DivideRuleVO; import com.wzj.soopin.transaction.domain.vo.DivideRuleVO;
import com.wzj.soopin.transaction.enums.DivideRuleFeeType;
import java.util.List;
public interface IDivideRuleService extends IService<DivideRule> { public interface IDivideRuleService extends IService<DivideRule> {
@ -12,4 +16,6 @@ public interface IDivideRuleService extends IService<DivideRule> {
DivideRuleVO getVOById(Long divideId); DivideRuleVO getVOById(Long divideId);
DivideRuleVO getVOByOrderType(Integer orderType); DivideRuleVO getVOByOrderType(Integer orderType);
void checkRule(List<DivideRuleDetailVO> details, DivideRuleFeeType divideRuleFeeType);
} }

View File

@ -1,6 +1,7 @@
package com.wzj.soopin.transaction.service.impl; package com.wzj.soopin.transaction.service.impl;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrBuilder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.wzj.soopin.transaction.convert.DivideRuleConvert; import com.wzj.soopin.transaction.convert.DivideRuleConvert;
@ -8,18 +9,19 @@ import com.wzj.soopin.transaction.convert.DivideRuleDetailConvert;
import com.wzj.soopin.transaction.domain.bo.DivideRuleBO; import com.wzj.soopin.transaction.domain.bo.DivideRuleBO;
import com.wzj.soopin.transaction.domain.po.DivideRule; import com.wzj.soopin.transaction.domain.po.DivideRule;
import com.wzj.soopin.transaction.domain.po.DivideRuleDetail; import com.wzj.soopin.transaction.domain.po.DivideRuleDetail;
import com.wzj.soopin.transaction.domain.vo.DivideRuleDetailVO;
import com.wzj.soopin.transaction.domain.vo.DivideRuleVO; import com.wzj.soopin.transaction.domain.vo.DivideRuleVO;
import com.wzj.soopin.transaction.enums.DivideRuleDetailType;
import com.wzj.soopin.transaction.enums.DivideRuleFeeType;
import com.wzj.soopin.transaction.enums.DivideRuleStatus; import com.wzj.soopin.transaction.enums.DivideRuleStatus;
import com.wzj.soopin.transaction.mapper.DivideRuleDetailMapper; import com.wzj.soopin.transaction.mapper.DivideRuleDetailMapper;
import com.wzj.soopin.transaction.mapper.DivideRuleMapper; import com.wzj.soopin.transaction.mapper.DivideRuleMapper;
import com.wzj.soopin.transaction.service.IDivideRuleService; import com.wzj.soopin.transaction.service.IDivideRuleService;
import jodd.util.CollectionUtil;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.exception.ServiceException;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;
@ -103,8 +105,8 @@ public class DivideRuleServiceImpl extends ServiceImpl<DivideRuleMapper, DivideR
@Override @Override
public DivideRuleVO getVOByOrderType(Integer orderType) { public DivideRuleVO getVOByOrderType(Integer orderType) {
List<DivideRule> divideRuleList = baseMapper.selectList(new QueryWrapper<DivideRule>().lambda() List<DivideRule> divideRuleList = baseMapper.selectList(new QueryWrapper<DivideRule>().lambda()
.eq(DivideRule::getType,orderType) .eq(DivideRule::getType, orderType)
.eq(DivideRule::getStatus,DivideRuleStatus.ON.getCode())); .eq(DivideRule::getStatus, DivideRuleStatus.ON.getCode()));
Assert.notEmpty(divideRuleList, () -> new ServiceException("未找到品类的分账规则")); Assert.notEmpty(divideRuleList, () -> new ServiceException("未找到品类的分账规则"));
Assert.isTrue(divideRuleList.size() == 1, () -> new ServiceException("品类分账规则不唯一")); Assert.isTrue(divideRuleList.size() == 1, () -> new ServiceException("品类分账规则不唯一"));
DivideRule divideRule = divideRuleList.get(0); DivideRule divideRule = divideRuleList.get(0);
@ -114,4 +116,37 @@ public class DivideRuleServiceImpl extends ServiceImpl<DivideRuleMapper, DivideR
vo.setDetails(detailConvert.toVO(detailList)); vo.setDetails(detailConvert.toVO(detailList));
return vo; return vo;
} }
/**
* 校验分账规则详情和规则中的手续费承担类型是否一致
*
* @param details
* @param divideRuleFeeType
*/
@Override
public void checkRule(List<DivideRuleDetailVO> details, DivideRuleFeeType divideRuleFeeType) {
String type = null;
if (DivideRuleFeeType.SELLER == divideRuleFeeType) {
if (details.stream().filter(item -> item.getType() == DivideRuleDetailType.SELLER.getValue()).count() != 1) {
type = DivideRuleDetailType.SELLER.getDesc();
}
}
if (DivideRuleFeeType.PLATFORM == divideRuleFeeType) {
if (details.stream().filter(item -> item.getType() == DivideRuleDetailType.PLATFORM.getValue()).count() != 1) {
type = DivideRuleDetailType.PLATFORM.getDesc();
}
}
if (DivideRuleFeeType.PROXY == divideRuleFeeType) {
if (details.stream().filter(item -> item.getType() == DivideRuleDetailType.PROXY.getValue()).count() != 1) {
type = DivideRuleDetailType.PROXY.getDesc();
}
}
if (DivideRuleFeeType.REFERENCE == divideRuleFeeType) {
if (details.stream().filter(item -> item.getType() == DivideRuleDetailType.REFERENCE.getValue()).count() != 1) {
type = DivideRuleDetailType.REFERENCE.getDesc();
}
}
String finalType = type;
Assert.isTrue(type == null, () -> new ServiceException("分账规则中的手续费承担者[" + finalType + "]未配置相应的分账规则详情"));
}
} }

View File

@ -3,6 +3,7 @@ package com.wzj.soopin.transaction.service.impl;
import cn.hutool.core.lang.Assert; import cn.hutool.core.lang.Assert;
import cn.hutool.core.text.StrBuilder; import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@ -73,7 +74,7 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
private final IEasypayService easypayService; private final IEasypayService easypayService;
private final ISysTenantService sysTenantService; private final ISysTenantService sysTenantService;
private final DivideMapper divideMapper;
@Override @Override
@ -130,7 +131,8 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
if (divide == null) { if (divide == null) {
return null; return null;
} }
List<DivideDetail> detailList = detailMapper.selectList(new QueryWrapper<DivideDetail>().lambda().eq(DivideDetail::getDivideId, divideId)); detailMapper.selectByDivideId(divideId);
List<DivideDetail> detailList = detailMapper.selectByDivideId(divideId);
divide.setDetails(detailConvert.toVO(detailList)); divide.setDetails(detailConvert.toVO(detailList));
return divide; return divide;
} }
@ -163,23 +165,23 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
Integer feeType = rule.getFeeType(); Integer feeType = rule.getFeeType();
DivideRuleFeeType divideRuleFeeType = DivideRuleFeeType.getByValue(feeType); DivideRuleFeeType divideRuleFeeType = DivideRuleFeeType.getByValue(feeType);
List<DivideRuleDetailVO> details = rule.getDetails(); List<DivideRuleDetailVO> details = rule.getDetails();
checkRule(details, divideRuleFeeType); ruleService.checkRule(details, divideRuleFeeType);
//根据易生支付的合同查看手续费金额 //根据易生支付的合同查看手续费金额
BigDecimal totalAmount = order.getTotalAmount(); BigDecimal totalAmount = order.getTotalAmount();
//计算订单可分配金额,订单只考虑整单退不考虑单独退所以直接计算订单金额 //计算订单可分配金额,订单只考虑整单退不考虑单独退所以直接计算订单金额
//先生成主表信息 //先生成主表信息
Divide divide = Divide.builder() Divide divide = divideMapper.selectByOrderId(orderId);
.ruleId(rule.getId()) if (divide == null) {
.orderMoney(totalAmount) divide = Divide.builder()
.separateBatchTrace(StrBuilder.create(TRACE_PREFIX).append(System.currentTimeMillis()).append(RandomUtil.randomString(4)).toString()) .ruleId(rule.getId())
// .fee(totalFee) .orderMoney(totalAmount)
// .actualMoney(actualMoney) .separateBatchTrace(StrBuilder.create(TRACE_PREFIX).append(System.currentTimeMillis()).append(RandomUtil.randomString(4)).toString())
.orderSn(order.getOrderSn()) .orderSn(order.getOrderSn())
.status(DivideStatus.PENDING.getCode()) .status(DivideStatus.PENDING.getCode())
.build(); .build();
super.save(divide); super.save(divide);
}
Long divideId = divide.getId();
List<DivideDetail> detailList = new ArrayList<>(); List<DivideDetail> detailList = new ArrayList<>();
List<SeparateItemBO> separateItemBOList = new ArrayList<>(); List<SeparateItemBO> separateItemBOList = new ArrayList<>();
// 从租户信息得到商户的分账比例,先分给商户 // 从租户信息得到商户的分账比例,先分给商户
@ -191,13 +193,13 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
.filter(item -> item.getType() == DivideRuleDetailType.PROXY.getValue()) .filter(item -> item.getType() == DivideRuleDetailType.PROXY.getValue())
.findFirst() .findFirst()
.ifPresent(ruleDetailVO -> { .ifPresent(ruleDetailVO -> {
DivideDetail proxyDivideDetail = divideProxy(totalAmount, ruleDetailVO, divide.getId(), order.getTenantId(),divideRuleFeeType, detailList, separateItemBOList); DivideDetail proxyDivideDetail = divideProxy(totalAmount, ruleDetailVO, divideId, order.getTenantId(), divideRuleFeeType, detailList, separateItemBOList);
}); });
rule.getDetails().stream() rule.getDetails().stream()
.filter(item -> item.getType() == DivideRuleDetailType.REFERENCE.getValue()) .filter(item -> item.getType() == DivideRuleDetailType.REFERENCE.getValue())
.findFirst() .findFirst()
.ifPresent(ruleDetailVO -> { .ifPresent(ruleDetailVO -> {
DivideDetail divideReference = divideReference(totalAmount, ruleDetailVO, divide.getId(), order.getMemberId(),divideRuleFeeType, detailList, separateItemBOList); DivideDetail divideReference = divideReference(totalAmount, ruleDetailVO, divideId, order.getMemberId(), divideRuleFeeType, detailList, separateItemBOList);
detailList.add(divideReference); detailList.add(divideReference);
}); });
@ -205,7 +207,7 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
.filter(item -> item.getType() == DivideRuleDetailType.PLATFORM.getValue()) .filter(item -> item.getType() == DivideRuleDetailType.PLATFORM.getValue())
.findFirst() .findFirst()
.ifPresent(ruleDetailVO -> { .ifPresent(ruleDetailVO -> {
DivideDetail dividePlatform = dividePlatform(totalAmount, ruleDetailVO, divide.getId(),divideRuleFeeType, detailList, separateItemBOList); DivideDetail dividePlatform = dividePlatform(totalAmount, ruleDetailVO, divideId, divideRuleFeeType, detailList, separateItemBOList);
detailList.add(dividePlatform); detailList.add(dividePlatform);
}); });
@ -216,6 +218,7 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
SeparateApplyBO separateApplyBO = SeparateApplyBO.builder() SeparateApplyBO separateApplyBO = SeparateApplyBO.builder()
.orderId(order.getId()) .orderId(order.getId())
.payId(order.getPayId()) .payId(order.getPayId())
.divideId(divide.getId())
.transDate(payOrder.getEndTransDate()) .transDate(payOrder.getEndTransDate())
.transSumAmt(payOrder.getTransAmount()) .transSumAmt(payOrder.getTransAmount())
.transSumCount((long) separateItemBOList.size()) .transSumCount((long) separateItemBOList.size())
@ -226,32 +229,6 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
return true; return true;
} }
/**
* 校验分账规则详情和规则中的手续费承担类型是否一致
*
* @param details
* @param divideRuleFeeType
*/
private void checkRule(List<DivideRuleDetailVO> details, DivideRuleFeeType divideRuleFeeType) {
if (DivideRuleFeeType.SELLER == divideRuleFeeType) {
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.SELLER.getValue()).count();
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置商户承担手续费,但未配置商户分账规则详情"));
}
if (DivideRuleFeeType.PLATFORM == divideRuleFeeType) {
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.PLATFORM.getValue()).count();
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置平台承担手续费,但未配置平台分账规则详情"));
}
if (DivideRuleFeeType.PROXY == divideRuleFeeType) {
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.PROXY.getValue()).count();
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置代理承担手续费,但未配置代理分账规则详情"));
}
if (DivideRuleFeeType.REFERENCE == divideRuleFeeType) {
long count = details.stream().filter(item -> item.getType() == DivideRuleDetailType.REFERENCE.getValue()).count();
Assert.isTrue(count == 1, () -> new ServiceException("分账总规则中已配置达人承担手续费,但未配置达人分账规则详情"));
}
}
/** /**
* 商户分账 * 商户分账
* *
@ -278,7 +255,9 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
.accountCode(mchtCode) .accountCode(mchtCode)
.money(sellerAmount) .money(sellerAmount)
.moneyPercent(divideRate) .moneyPercent(divideRate)
.type(DivideRuleDetailType.SELLER.getValue()).build(); .type(DivideRuleDetailType.SELLER.getValue())
.status(DivideStatus.PENDING.getCode())
.build();
detailMapper.insert(sellerDetail); detailMapper.insert(sellerDetail);
detailList.add(sellerDetail); detailList.add(sellerDetail);
Integer sepaFeeAmount = 0; Integer sepaFeeAmount = 0;
@ -319,6 +298,7 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
.money(proxyAmount) .money(proxyAmount)
.moneyPercent(rule.getMoneyPercent()) .moneyPercent(rule.getMoneyPercent())
.type(DivideRuleDetailType.PROXY.getValue()) .type(DivideRuleDetailType.PROXY.getValue())
.status(DivideStatus.PENDING.getCode())
.build(); .build();
detailMapper.insert(proxyDetail); detailMapper.insert(proxyDetail);
detailList.add(proxyDetail); detailList.add(proxyDetail);
@ -360,6 +340,7 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
.money(proxyAmount) .money(proxyAmount)
.moneyPercent(rule.getMoneyPercent()) .moneyPercent(rule.getMoneyPercent())
.type(DivideRuleDetailType.REFERENCE.getValue()) .type(DivideRuleDetailType.REFERENCE.getValue())
.status(DivideStatus.PENDING.getCode())
.build(); .build();
detailMapper.insert(referenceDetail); detailMapper.insert(referenceDetail);
detailList.add(referenceDetail); detailList.add(referenceDetail);
@ -389,6 +370,7 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
.money(platformAmount) .money(platformAmount)
.moneyPercent(rule.getMoneyPercent()) .moneyPercent(rule.getMoneyPercent())
.type(DivideRuleDetailType.PLATFORM.getValue()) .type(DivideRuleDetailType.PLATFORM.getValue())
.status(DivideStatus.PENDING.getCode())
.build(); .build();
detailMapper.insert(platformDetail); detailMapper.insert(platformDetail);
detailList.add(platformDetail); detailList.add(platformDetail);

View File

@ -24,6 +24,7 @@ import com.wzj.soopin.transaction.config.EasypayConfig;
import com.wzj.soopin.transaction.config.WechatMiniProgramConfig; import com.wzj.soopin.transaction.config.WechatMiniProgramConfig;
import com.wzj.soopin.transaction.domain.bo.PaymentBO; import com.wzj.soopin.transaction.domain.bo.PaymentBO;
import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO; import com.wzj.soopin.transaction.domain.bo.SeparateApplyBO;
import com.wzj.soopin.transaction.domain.bo.SeparateItemBO;
import com.wzj.soopin.transaction.domain.bo.easypay.*; import com.wzj.soopin.transaction.domain.bo.easypay.*;
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundApplyReqBody; import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundApplyReqBody;
import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundReqOrderInfo; import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.req.RefundReqOrderInfo;
@ -31,6 +32,7 @@ import com.wzj.soopin.transaction.domain.bo.easypay.refund.apply.resp.RefundAppl
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.req.SeparateApplyReqBody; import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.req.SeparateApplyReqBody;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.req.SeparateReqOrderInfo; import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.req.SeparateReqOrderInfo;
import com.wzj.soopin.transaction.domain.bo.easypay.separate.apply.resp.SeparateApplyRespBody; 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.apply.resp.SeparateRespOrderInfo;
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.req.*; import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.req.*;
import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.JsApiRespBody; import com.wzj.soopin.transaction.domain.bo.easypay.trade.jsapi.resp.JsApiRespBody;
@ -41,18 +43,20 @@ import com.wzj.soopin.transaction.domain.bo.easypay.trade.query.resp.TradeQueryR
import com.wzj.soopin.transaction.domain.bo.easypay.trade.query.resp.TradeQueryRespOrderInfo; import com.wzj.soopin.transaction.domain.bo.easypay.trade.query.resp.TradeQueryRespOrderInfo;
import com.wzj.soopin.transaction.domain.entity.WxAuthResponse; import com.wzj.soopin.transaction.domain.entity.WxAuthResponse;
import com.wzj.soopin.transaction.domain.po.Divide; import com.wzj.soopin.transaction.domain.po.Divide;
import com.wzj.soopin.transaction.domain.po.DivideDetail;
import com.wzj.soopin.transaction.domain.po.DivideRule;
import com.wzj.soopin.transaction.domain.po.PayOrder; import com.wzj.soopin.transaction.domain.po.PayOrder;
import com.wzj.soopin.transaction.domain.vo.EasypayAccountVO; import com.wzj.soopin.transaction.domain.vo.*;
import com.wzj.soopin.transaction.domain.vo.EasypayTransResultVO; import com.wzj.soopin.transaction.enums.DivideRuleFeeType;
import com.wzj.soopin.transaction.domain.vo.EasypayPrePayVO; import com.wzj.soopin.transaction.enums.DivideRuleStatus;
import com.wzj.soopin.transaction.enums.DivideStatus;
import com.wzj.soopin.transaction.enums.TransState; import com.wzj.soopin.transaction.enums.TransState;
import com.wzj.soopin.transaction.enums.easypay.DelaySettleFlag; import com.wzj.soopin.transaction.enums.easypay.*;
import com.wzj.soopin.transaction.enums.easypay.PatnerSettleFlag;
import com.wzj.soopin.transaction.enums.easypay.PayType;
import com.wzj.soopin.transaction.enums.easypay.SplitSettleFlag;
import com.wzj.soopin.transaction.mapper.DivideDetailMapper; import com.wzj.soopin.transaction.mapper.DivideDetailMapper;
import com.wzj.soopin.transaction.mapper.DivideMapper; import com.wzj.soopin.transaction.mapper.DivideMapper;
import com.wzj.soopin.transaction.mapper.DivideRuleMapper;
import com.wzj.soopin.transaction.mapper.PayOrderMapper; import com.wzj.soopin.transaction.mapper.PayOrderMapper;
import com.wzj.soopin.transaction.service.IDivideRuleService;
import com.wzj.soopin.transaction.service.IEasypayService; import com.wzj.soopin.transaction.service.IEasypayService;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -64,8 +68,10 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.RoundingMode;
import java.rmi.ServerException; import java.rmi.ServerException;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
import static com.wzj.soopin.transaction.constans.EasypayConstants.*; import static com.wzj.soopin.transaction.constans.EasypayConstants.*;
@ -91,7 +97,7 @@ public class EasypayServiceImpl implements IEasypayService {
private final DivideMapper divideMapper; private final DivideMapper divideMapper;
private final DivideDetailMapper divideDetailMapper; private final DivideRuleMapper divideRuleMapper;
/** /**
@ -490,7 +496,20 @@ public class EasypayServiceImpl implements IEasypayService {
.paymentTime(LocalDateTimeUtil.parse(StrBuilder.create(respOrderInfo.getDateEnd()).append(respOrderInfo.getTimeEnd()).toString(), "yyyyMMddHHmmss")) .paymentTime(LocalDateTimeUtil.parse(StrBuilder.create(respOrderInfo.getDateEnd()).append(respOrderInfo.getTimeEnd()).toString(), "yyyyMMddHHmmss"))
.payType(PayType.getByValue(payOrder.getPayType()).getChannel()) .payType(PayType.getByValue(payOrder.getPayType()).getChannel())
.build()); .build());
}else{ // 生产待分账信息
DivideRule divideRule = divideRuleMapper.getByTypeAndStatus(order.getType(), DivideRuleStatus.ON.getCode());
if (divideRule == null) {
log.warn("订单类型的分账规则不存在,暂不生成待分账记录");
} else {
divideMapper.insert(Divide.builder()
.ruleId(divideRule.getId())
.orderMoney(order.getTotalAmount())
.separateBatchTrace(StrBuilder.create(TRACE_PREFIX).append(System.currentTimeMillis()).append(RandomUtil.randomString(4)).toString())
.orderSn(order.getOrderSn())
.status(DivideStatus.PENDING.getCode())
.build());
}
} else {
// 支付失败支付状态重置为待支付 // 支付失败支付状态重置为待支付
payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.PENDING.getCode()).build()); payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.PENDING.getCode()).build());
} }
@ -553,7 +572,7 @@ public class EasypayServiceImpl implements IEasypayService {
if (StrUtil.equalsAny(respStateInfo.getTransState(), RSP_BODY_TRANS_OK)) { if (StrUtil.equalsAny(respStateInfo.getTransState(), RSP_BODY_TRANS_OK)) {
// 更新支付单退款状态 // 更新支付单退款状态
payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.REFUNDED.getCode()).refundDate(new Date()).build()); payOrderMapper.updateById(PayOrder.builder().id(payOrder.getId()).transState(TransState.REFUNDED.getCode()).refundDate(new Date()).build());
orderMapper.updateById(Order.builder().id(order.getId()).status(OrderStatusEnum.REFUNDED.getValue()).build()); orderMapper.updateStatusById(order.getId(), OrderStatusEnum.REFUNDED.getValue());
} }
} else { } else {
log.error("易生退款失败:{}", respStateInfo.getRespDesc()); log.error("易生退款失败:{}", respStateInfo.getRespDesc());
@ -653,6 +672,7 @@ public class EasypayServiceImpl implements IEasypayService {
.reqSign(reqSign) .reqSign(reqSign)
.build(); .build();
log.debug("调用易生请求分账接口请求:{}", JSONObject.toJSONString(easyRequest)); log.debug("调用易生请求分账接口请求:{}", JSONObject.toJSONString(easyRequest));
divideMapper.updateStatus(separateApplyBO.getDivideId(), DivideStatus.PENDING.getCode());
String url = StrBuilder.create(easypayConfig.getApiPathPrefix()).append("/trade/separate/orderApply").toString(); String url = StrBuilder.create(easypayConfig.getApiPathPrefix()).append("/trade/separate/orderApply").toString();
String body = HttpRequest.post(url) String body = HttpRequest.post(url)
.timeout(3000) .timeout(3000)
@ -688,14 +708,49 @@ public class EasypayServiceImpl implements IEasypayService {
* *
* @param respOrderInfo * @param respOrderInfo
*/ */
private SeparateApplyBO handleSeparateInfo(SeparateApplyBO separateApplyBO, SeparateRespOrderInfo respOrderInfo) { private void handleSeparateInfo(SeparateApplyBO separateApplyBO, SeparateRespOrderInfo respOrderInfo) {
Long orderId = separateApplyBO.getOrderId(); Long orderId = separateApplyBO.getOrderId();
Divide divide = divideMapper.selectByOrderId(orderId); Map<String, SeparateItemBO> separateItemBOMap = separateApplyBO.getSeparateItemBOList().stream().collect(Collectors.toMap(SeparateItemBO::getSeparateTrade, o -> o));
List<DivideDetail> updateDetailList = new ArrayList<>();
return separateApplyBO; List<SeparateRespInfoList> separateRespInfoList = respOrderInfo.getSeparateRespInfoList();
separateRespInfoList.forEach(separateRespInfo -> {
String separateTrade = separateRespInfo.getSeparateTrade();
SeparateItemBO separateItemBO = separateItemBOMap.get(separateTrade);
DivideDetail divideDetail = DivideDetail.builder()
.id(Long.valueOf(separateItemBO.getSeparateTrade()))
.separateTrade(separateRespInfo.getSeparateTrade())
.build();
if (separateRespInfo.getSepaFeeAmount() != null) {
divideDetail.setMoney(BigDecimal.valueOf(separateRespInfo.getSepaFeeAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
}
if (separateRespInfo.getSepaFeeAmount() != null) {
divideDetail.setFee(BigDecimal.valueOf(separateRespInfo.getSepaFeeAmount()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP));
}
SepaStatus sepaStatus = SepaStatus.getByValue(separateRespInfo.getSepaStatus());
switch (sepaStatus) {
case SUCCESS -> divideDetail.setStatus(DivideStatus.SUCCESS.getCode());
case FAIL -> divideDetail.setStatus(DivideStatus.FAIL.getCode());
case PENDING -> divideDetail.setStatus(DivideStatus.PENDING.getCode());
case REFUNDED -> divideDetail.setStatus(DivideStatus.REFUNDED.getCode());
case PROCESSING -> divideDetail.setStatus(DivideStatus.PROCESSING.getCode());
default -> divideDetail.setStatus(DivideStatus.PROCESSING.getCode());
}
updateDetailList.add(divideDetail);
});
long itemOkCount = updateDetailList.stream().filter(item -> item.getStatus() == DivideStatus.SUCCESS.getCode())
.count();
int actualSeparate = separateItemBOMap.values().stream().mapToInt(SeparateItemBO::getSepaTransAmount).sum();
Divide divideUpdate = Divide.builder()
.id(separateApplyBO.getDivideId())
.actualMoney(BigDecimal.valueOf(actualSeparate).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP))
.status(DivideStatus.PROCESSING.getCode()).build();
if (itemOkCount == separateItemBOMap.size()) {
divideUpdate.setStatus(DivideStatus.SUCCESS.getCode());
orderMapper.updateStatusById(orderId, OrderStatusEnum.DIVIDED.getValue());
}
divideMapper.updateById(divideUpdate);
} }
@Override @Override
public EasypayAccountVO getEasypayAccount(Long memberId) { public EasypayAccountVO getEasypayAccount(Long memberId) {
return EasypayAccountVO.builder().balance(new BigDecimal(1000)).build(); return EasypayAccountVO.builder().balance(new BigDecimal(1000)).build();