[fix]开发分账接口

This commit is contained in:
wangqx 2025-06-30 15:59:19 +08:00
parent 7e027b493d
commit 9b33dbde98
18 changed files with 328 additions and 29 deletions

View File

@ -141,7 +141,6 @@ tenant:
- sys_oss_config - sys_oss_config
- ums_member - ums_member
- ums_member_address - ums_member_address
- ums_feedback
- ums_member_login_info - ums_member_login_info
- ums_cart - ums_cart
- ums_account - ums_account
@ -153,8 +152,7 @@ tenant:
- ums_forbidden - ums_forbidden
- ums_member_bank - ums_member_bank
- ums_tenant_forbidden - ums_tenant_forbidden
- ums_charge
- ums_withdraw
- oms_aftersale - oms_aftersale
- oms_aftersale_item - oms_aftersale_item
- oms_order - oms_order
@ -169,7 +167,13 @@ tenant:
- pms_sku_snapshot - pms_sku_snapshot
- oms_verification_codes - oms_verification_codes
- oms_verification_logs - oms_verification_logs
- ums_feedback
- trans_charge
- trans_withdraw
- trans_divide
- trans_divide_detail
- trans_divide_rule
- trans_divide_rule_detail
# MyBatisPlus配置 # MyBatisPlus配置
# https://baomidou.com/config/ # https://baomidou.com/config/

View File

@ -3,5 +3,9 @@ package com.wzj.soopin.order.service;
import com.baomidou.mybatisplus.extension.service.IService; import com.baomidou.mybatisplus.extension.service.IService;
import com.wzj.soopin.order.domain.entity.OrderItem; import com.wzj.soopin.order.domain.entity.OrderItem;
import java.util.List;
public interface OrderItemService extends IService<OrderItem> { public interface OrderItemService extends IService<OrderItem> {
List<OrderItem> findByOrderId(Long orderId);
} }

View File

@ -14,4 +14,6 @@ import java.util.Map;
public interface OrderService extends IService<Order> { public interface OrderService extends IService<Order> {
IPage<OrderVO> getlist(Page<Order> page, OrderBo query); IPage<OrderVO> getlist(Page<Order> page, OrderBo query);
Order getByNo(String orderNo);
} }

View File

@ -32,4 +32,9 @@ import java.util.List;
@Service @Service
public class OrderItemServiceImpl extends ServiceImpl<OrderItemMapper, OrderItem> implements OrderItemService { public class OrderItemServiceImpl extends ServiceImpl<OrderItemMapper, OrderItem> implements OrderItemService {
@Override
public List<OrderItem> findByOrderId(Long orderId) {
return baseMapper.selectList(new QueryWrapper<OrderItem>().lambda()
.eq(OrderItem::getOrderId, orderId));
}
} }

View File

@ -543,5 +543,10 @@ public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements
// return result; // return result;
// } // }
@Override
public Order getByNo(String orderNo) {
return baseMapper.selectOne(new LambdaQueryWrapper<Order>().eq(Order::getOrderSn,orderNo));
}
} }

View File

@ -62,4 +62,15 @@ public class DivideController {
public R<Object> remove(@PathVariable Long id) { public R<Object> remove(@PathVariable Long id) {
return R.ok(service.removeById(id)); return R.ok(service.removeById(id));
} }
@Tag(name = "根据订单id分账")
@Log(title = "分账", businessType = BusinessType.DELETE)
@DeleteMapping("/divide/{orderNo}")
public R<Object> divide(@PathVariable String orderNo) {
return R.ok(service.divide(orderNo));
}
} }

View File

@ -5,6 +5,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; 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.Data; import lombok.Data;
import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.common.mybatis.core.domain.BaseEntity;
@ -18,6 +19,7 @@ import java.math.BigDecimal;
*/ */
@Schema(description = "订单分账") @Schema(description = "订单分账")
@Data @Data
@Builder(toBuilder = true)
@TableName("trans_divide") @TableName("trans_divide")
public class Divide extends BaseEntity { public class Divide extends BaseEntity {

View File

@ -5,6 +5,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; 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.Data; import lombok.Data;
import org.dromara.common.mybatis.core.domain.BaseEntity; import org.dromara.common.mybatis.core.domain.BaseEntity;
@ -19,6 +20,7 @@ import java.math.BigDecimal;
@Schema(description = "订单分账明细") @Schema(description = "订单分账明细")
@Data @Data
@TableName("trans_divide_detail") @TableName("trans_divide_detail")
@Builder(toBuilder = true)
public class DivideDetail extends BaseEntity { public class DivideDetail extends BaseEntity {
/** /**

View File

@ -0,0 +1,35 @@
package com.wzj.soopin.transaction.enums;
public enum DivideRuleDetailType {
/**
* 商家
*/
SELLER(1, "商家"),
/**
* 平台
*/
PLATFORM(2, "平台"),
/**
* 代理
*/
PROXY(3, "代理");
private int value;
private String desc;
DivideRuleDetailType(int value, String desc) {
this.value = value;
this.desc = desc;
}
public int getValue() {
return value;
}
public String getDesc() {
return desc;
}
}

View File

@ -0,0 +1,33 @@
package com.wzj.soopin.transaction.enums;
import lombok.Getter;
@Getter
public enum DivideRuleFeeType {
/**
* 按比例分配
*/
RATE(1, "按比例分配"),
/**
* 商家承担
*/
SELLER(2, "商家承担"),
/**
* 平台承担
*/
PLATFORM(3, "平台承担"),
PROXY(4, "平台代理承担");
private String desc;
private int value;
DivideRuleFeeType(int value, String desc) {
this.value = value;
this.desc = desc;
}
}

View File

@ -1,5 +1,8 @@
package com.wzj.soopin.transaction.enums; package com.wzj.soopin.transaction.enums;
import lombok.Getter;
@Getter
public enum DivideRuleStatus { public enum DivideRuleStatus {
/** /**
* 启用 * 启用
@ -19,12 +22,5 @@ public enum DivideRuleStatus {
} }
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
} }

View File

@ -1,5 +1,8 @@
package com.wzj.soopin.transaction.enums; package com.wzj.soopin.transaction.enums;
import lombok.Getter;
@Getter
public enum DivideStatus { public enum DivideStatus {
PENDING(0, "待分账"), PENDING(0, "待分账"),
@ -13,11 +16,5 @@ public enum DivideStatus {
this.desc = desc; this.desc = desc;
} }
public int getCode() {
return code;
}
public String getDesc() {
return desc;
}
} }

View File

@ -1,5 +1,9 @@
package com.wzj.soopin.transaction.enums; package com.wzj.soopin.transaction.enums;
import lombok.Data;
import lombok.Getter;
@Getter
public enum WithdrawAuditStatus { public enum WithdrawAuditStatus {
PENDING(0, "待审核"), PENDING(0, "待审核"),
APPROVED(1, "审核通过"), APPROVED(1, "审核通过"),
@ -10,11 +14,5 @@ public enum WithdrawAuditStatus {
this.code = code; this.code = code;
this.message = message; this.message = message;
} }
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
} }

View File

@ -1,5 +1,8 @@
package com.wzj.soopin.transaction.enums; package com.wzj.soopin.transaction.enums;
import lombok.Getter;
@Getter
public enum WithdrawStatus { public enum WithdrawStatus {
WAITING(0, "等待转账"), WAITING(0, "等待转账"),
PENDING(1, "转账中"), PENDING(1, "转账中"),
@ -12,11 +15,5 @@ public enum WithdrawStatus {
this.code = code; this.code = code;
this.message = message; this.message = message;
} }
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
} }

View File

@ -10,4 +10,6 @@ public interface IDivideRuleService extends IService<DivideRule> {
boolean save( DivideRuleBO bo); boolean save( DivideRuleBO bo);
DivideRuleVO getVOById(Long divideId); DivideRuleVO getVOById(Long divideId);
DivideRuleVO getVOByOrderType(Integer orderType);
} }

View File

@ -10,4 +10,16 @@ public interface IDivideService extends IService<Divide> {
boolean save( DivideBO bo); boolean save( DivideBO bo);
DivideVO getVOById( Long divideId); DivideVO getVOById( Long divideId);
boolean divide(String orderNo);
boolean cancelDivide(String orderNo);
boolean divideCallback(String divideNo);
boolean cancelDivideCallback(String divideNo);
Divide getByOrderNo(String orderNo);
} }

View File

@ -12,11 +12,13 @@ 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;
@ -96,4 +98,25 @@ public class DivideRuleServiceImpl extends ServiceImpl<DivideRuleMapper, DivideR
vo.setDetails(detailConvert.toVO(detailList)); vo.setDetails(detailConvert.toVO(detailList));
return vo; return vo;
} }
@Override
public DivideRuleVO getVOByOrderType(Integer orderType) {
List<DivideRule> divideRuleList = baseMapper.selectList(new QueryWrapper<DivideRule>().lambda()
.eq(DivideRule::getType,orderType)
.eq(DivideRule::getStatus,DivideRuleStatus.ON.getCode()));
if (CollectionUtils.isEmpty(divideRuleList)) {
return null;
}
if(divideRuleList.size()>1){
throw new ServiceException("分账规则不唯一");
}
DivideRule divideRule = divideRuleList.get(0);
List<DivideRuleDetail> detailList = detailMapper.selectList(new QueryWrapper<DivideRuleDetail>().lambda()
.eq(DivideRuleDetail::getRuleId, divideRule.getId()));
DivideRuleVO vo = convert.toVO(divideRule);
vo.setDetails(detailConvert.toVO(detailList));
return vo;
}
} }

View File

@ -2,24 +2,38 @@ package com.wzj.soopin.transaction.service.impl;
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.order.domain.entity.Order;
import com.wzj.soopin.order.service.OrderItemService;
import com.wzj.soopin.order.service.OrderService;
import com.wzj.soopin.order.utils.StringUtils;
import com.wzj.soopin.transaction.convert.DivideConvert; import com.wzj.soopin.transaction.convert.DivideConvert;
import com.wzj.soopin.transaction.convert.DivideDetailConvert; import com.wzj.soopin.transaction.convert.DivideDetailConvert;
import com.wzj.soopin.transaction.domain.bo.DivideBO; import com.wzj.soopin.transaction.domain.bo.DivideBO;
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.DivideDetail;
import com.wzj.soopin.transaction.domain.vo.DivideRuleVO;
import com.wzj.soopin.transaction.domain.vo.DivideVO; import com.wzj.soopin.transaction.domain.vo.DivideVO;
import com.wzj.soopin.transaction.enums.DivideRuleDetailType;
import com.wzj.soopin.transaction.enums.DivideRuleFeeType;
import com.wzj.soopin.transaction.enums.DivideStatus; import com.wzj.soopin.transaction.enums.DivideStatus;
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.service.IDivideRuleService;
import com.wzj.soopin.transaction.service.IDivideService; import com.wzj.soopin.transaction.service.IDivideService;
import com.wzj.soopin.transaction.service.IYishengService;
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.dromara.common.core.service.ConfigService;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable; import java.io.Serializable;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/** /**
* 分账服务实现类 * 分账服务实现类
@ -37,6 +51,18 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
private final DivideConvert divideConvert; private final DivideConvert divideConvert;
private final OrderService orderService;
private final IDivideRuleService ruleService;
private final OrderItemService orderItemService;
private final ConfigService configService;
private final IYishengService yishengService;
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public boolean save(DivideBO bo) { public boolean save(DivideBO bo) {
@ -95,4 +121,149 @@ public class DivideServiceImpl extends ServiceImpl<DivideMapper, Divide> impleme
divide.setDetails(detailConvert.toVO(detailList)); divide.setDetails(detailConvert.toVO(detailList));
return divide; return divide;
} }
@Override
public Divide getByOrderNo(String orderNo) {
return baseMapper.selectOne(new QueryWrapper<Divide>().lambda().eq(Divide::getOrderSn, orderNo));
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean divide(String orderNo) {
//获取订单信息
Order order = orderService.getByNo(orderNo);
if (order == null) {
throw new ServiceException("订单不存在");
}
if (order.getStatus() != 1) {
throw new ServiceException("订单状态不正确");
}
Divide divide = this.getByOrderNo(orderNo);
if (divide == null) {
throw new ServiceException("已存在分账记录,无需再次分账");
}
//查找分账规则
DivideRuleVO rule = ruleService.getVOByOrderType(order.getType());
if (rule == null) {
throw new ServiceException("未找到分账规则");
}
//开始分账
//计算订单可分配金额,订单只考虑整单退不考虑单独退所以直接计算订单金额
BigDecimal totalAmount = order.getTotalAmount();
BigDecimal totalFee = new BigDecimal(0);
String feeRate = configService.getConfigValue("transaction.divide.feeRate");
if (StringUtils.isNotBlank(feeRate)) {
totalFee = totalAmount.multiply(new BigDecimal(feeRate)).divide(new BigDecimal(1000), 2, BigDecimal.ROUND_HALF_UP);
}
//先生成主表信息
divide = Divide.builder()
.ruleId(rule.getId())
.orderMoney(totalAmount)
.fee(totalFee)
.actualMoney(totalAmount.subtract(totalFee))
.orderSn(orderNo)
.status(DivideStatus.PENDING.getCode())
.build();
super.save(divide);
List<DivideDetail> details = saveDetails(order, divide.getId(), totalFee, totalAmount, rule);
syncOrderStatus(order);
syncYisheng(details);
return false;
}
@Override
public boolean cancelDivide(String orderNo) {
return false;
}
@Override
public boolean divideCallback(String divideNo) {
return false;
}
@Override
public boolean cancelDivideCallback(String divideNo) {
return false;
}
private List<DivideDetail> saveDetails(Order order, Long divideId, BigDecimal totalFee, BigDecimal totalAmount, DivideRuleVO rule) {
List<DivideDetail> details = rule.getDetails().stream().map(item -> {
//计算金额
BigDecimal amount = totalAmount.multiply(item.getMoneyPercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
//如果需要分配手续费计算手续费
BigDecimal fee = new BigDecimal(0);
//
if (rule.getDivideFeeFlag() == 1) {
if (rule.getFeeType() == DivideRuleFeeType.PLATFORM.getValue() && item.getType() == DivideRuleDetailType.PLATFORM.getValue()) {
fee = totalFee;
} else if (rule.getFeeType() == DivideRuleFeeType.PROXY.getValue() && item.getType() == DivideRuleDetailType.PROXY.getValue()) {
fee = totalFee;
} else if (rule.getFeeType() == DivideRuleFeeType.SELLER.getValue() && item.getType() == DivideRuleDetailType.SELLER.getValue()) {
fee = totalFee;
} else {
fee = totalFee.multiply(item.getFeePercent()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
}
}
DivideDetail detail = DivideDetail.builder()
.divideId(divideId)
.money(amount)
.fee(fee)
.feePercent(item.getFeePercent())
.moneyPercent(item.getMoneyPercent())
.type(item.getType())
.orderId(order.getId())
.orderSn(order.getOrderSn())
.build();
Map<String, String> account = new HashMap<>();
//如果是平台代理卖家直接分配
if (item.getType() == DivideRuleDetailType.PLATFORM.getValue()) {
account = getPlatformAccount();
} else if (item.getType() == DivideRuleDetailType.PROXY.getValue()) {
account = getProxyAccount();
} else if (item.getType() == DivideRuleDetailType.SELLER.getValue()) {
account = getSellerAccount();
}
detail.setAccountId(Long.parseLong(account.get("accountId")));
detail.setAccountName(account.get("accountName"));
return detail;
}).collect(Collectors.toList());
detailMapper.insertBatch(details);
return details;
}
private Map<String, String> getPlatformAccount() {
return new HashMap<>() {{
put("account", "123456");
put("name", "平台");
}};
}
private Map<String, String> getProxyAccount() {
return new HashMap<>() {{
put("account", "123456");
put("name", "代理");
}};
}
private Map<String, String> getSellerAccount() {
return new HashMap<>() {{
put("account", "123456");
put("name", "卖家");
}};
}
private void syncOrderStatus(Order order) {
}
private void syncYisheng(List<DivideDetail> divideDetails) {
}
} }