1.调整订单分销、分润、分红结算算法功能
2.商品订单支付成功增加执行分销员分销、统计门店/服务商分销业务、执行总分红业务功能 3.配送员完成配送增加解冻商品订单业务功能 4.订单分销记录增加关联结算单号、结算状态字段,方便门店/服务商做计算做准备
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -2,11 +2,11 @@ package com.gxwebsoft.glt.service;
|
|||||||
|
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.gxwebsoft.common.core.annotation.IgnoreTenant;
|
|
||||||
import com.gxwebsoft.glt.entity.GltTicketTemplate;
|
import com.gxwebsoft.glt.entity.GltTicketTemplate;
|
||||||
import com.gxwebsoft.glt.entity.GltUserTicket;
|
import com.gxwebsoft.glt.entity.GltUserTicket;
|
||||||
import com.gxwebsoft.glt.entity.GltUserTicketLog;
|
import com.gxwebsoft.glt.entity.GltUserTicketLog;
|
||||||
import com.gxwebsoft.glt.entity.GltUserTicketRelease;
|
import com.gxwebsoft.glt.entity.GltUserTicketRelease;
|
||||||
|
import com.gxwebsoft.glt.task.DealerOrderSettlement10584Task;
|
||||||
import com.gxwebsoft.shop.entity.ShopOrder;
|
import com.gxwebsoft.shop.entity.ShopOrder;
|
||||||
import com.gxwebsoft.shop.entity.ShopOrderGoods;
|
import com.gxwebsoft.shop.entity.ShopOrderGoods;
|
||||||
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
||||||
@@ -15,7 +15,6 @@ import lombok.RequiredArgsConstructor;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections4.CollectionUtils;
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.springframework.scheduling.annotation.Async;
|
import org.springframework.scheduling.annotation.Async;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
|
||||||
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.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
@@ -56,6 +55,7 @@ public class GltTicketIssueService {
|
|||||||
private final GltUserTicketReleaseService gltUserTicketReleaseService;
|
private final GltUserTicketReleaseService gltUserTicketReleaseService;
|
||||||
private final GltUserTicketLogService gltUserTicketLogService;
|
private final GltUserTicketLogService gltUserTicketLogService;
|
||||||
private final TransactionTemplate transactionTemplate;
|
private final TransactionTemplate transactionTemplate;
|
||||||
|
private final DealerOrderSettlement10584Task dealerOrderSettlement;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 扫描“今日订单”,执行套票发放。
|
* 扫描“今日订单”,执行套票发放。
|
||||||
@@ -140,7 +140,10 @@ public class GltTicketIssueService {
|
|||||||
//1.发送水票
|
//1.发送水票
|
||||||
suerTicketRelease(orderNo, tenantId);
|
suerTicketRelease(orderNo, tenantId);
|
||||||
|
|
||||||
//2.优惠券扣减、积分发送、消息通知
|
//2.执行分销员分销、统计门店/服务商分销业务
|
||||||
|
dealerOrderSettlement.orderSettlement(orderNo);
|
||||||
|
|
||||||
|
//3.执行平台分红业务 TODO 待开发
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,6 +152,7 @@ public class GltTicketIssueService {
|
|||||||
* @param orderNo 订单号
|
* @param orderNo 订单号
|
||||||
* @param tenantId 租户ID
|
* @param tenantId 租户ID
|
||||||
*/
|
*/
|
||||||
|
@Transactional
|
||||||
public void suerTicketRelease(String orderNo, Integer tenantId){
|
public void suerTicketRelease(String orderNo, Integer tenantId){
|
||||||
//1.订单为空跳过执行
|
//1.订单为空跳过执行
|
||||||
ShopOrder shopOrder = shopOrderService.getByOrderNo(orderNo, tenantId);
|
ShopOrder shopOrder = shopOrderService.getByOrderNo(orderNo, tenantId);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import cn.hutool.core.util.StrUtil;
|
|||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import com.gxwebsoft.common.core.enums.ShopDealerCapitalUpdateEnum;
|
||||||
|
import com.gxwebsoft.common.core.enums.ShopDealerTypeEnum;
|
||||||
import com.gxwebsoft.common.core.exception.BusinessException;
|
import com.gxwebsoft.common.core.exception.BusinessException;
|
||||||
import com.gxwebsoft.common.core.web.PageParam;
|
import com.gxwebsoft.common.core.web.PageParam;
|
||||||
import com.gxwebsoft.common.core.web.PageResult;
|
import com.gxwebsoft.common.core.web.PageResult;
|
||||||
@@ -19,6 +21,7 @@ import com.gxwebsoft.glt.param.GltTicketOrderParam;
|
|||||||
import com.gxwebsoft.glt.service.GltTicketOrderService;
|
import com.gxwebsoft.glt.service.GltTicketOrderService;
|
||||||
import com.gxwebsoft.glt.service.GltUserTicketLogService;
|
import com.gxwebsoft.glt.service.GltUserTicketLogService;
|
||||||
import com.gxwebsoft.glt.service.GltUserTicketService;
|
import com.gxwebsoft.glt.service.GltUserTicketService;
|
||||||
|
import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto;
|
||||||
import com.gxwebsoft.shop.entity.*;
|
import com.gxwebsoft.shop.entity.*;
|
||||||
import com.gxwebsoft.shop.mapper.ShopUserAddressMapper;
|
import com.gxwebsoft.shop.mapper.ShopUserAddressMapper;
|
||||||
import com.gxwebsoft.shop.service.ShopDealerCapitalService;
|
import com.gxwebsoft.shop.service.ShopDealerCapitalService;
|
||||||
@@ -765,6 +768,25 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//查询未完成订单,完成资金解冻
|
||||||
|
LambdaQueryWrapper<ShopOrder> orderLambdaQueryWrapper;
|
||||||
|
if(shopOrderId != null){
|
||||||
|
orderLambdaQueryWrapper = new LambdaQueryWrapper<ShopOrder>().eq(ShopOrder::getOrderId, shopOrderId).eq(ShopOrder::getOrderStatus, 0);
|
||||||
|
}else{
|
||||||
|
orderLambdaQueryWrapper = new LambdaQueryWrapper<ShopOrder>().eq(ShopOrder::getOrderId, shopOrderNo).eq(ShopOrder::getOrderStatus, 0);
|
||||||
|
}
|
||||||
|
ShopOrder order = shopOrderService.getOne(orderLambdaQueryWrapper);
|
||||||
|
if(order != null){
|
||||||
|
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
|
||||||
|
reduceDto.setTypeEnum(ShopDealerTypeEnum.DEFROST);
|
||||||
|
reduceDto.setOrderUserId(order.getUserId());
|
||||||
|
reduceDto.setOrderNo(order.getOrderNo());
|
||||||
|
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.FREEZE_MONEY_THAW);
|
||||||
|
|
||||||
|
//按订单号资金解冻
|
||||||
|
shopDealerUserService.reduceBalance(reduceDto);
|
||||||
|
}
|
||||||
|
|
||||||
LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>()
|
LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>()
|
||||||
.eq(ShopOrder::getTenantId, tenantId)
|
.eq(ShopOrder::getTenantId, tenantId)
|
||||||
.eq(ShopOrder::getDeleted, 0)
|
.eq(ShopOrder::getDeleted, 0)
|
||||||
@@ -776,7 +798,6 @@ public class GltTicketOrderServiceImpl extends ServiceImpl<GltTicketOrderMapper,
|
|||||||
} else {
|
} else {
|
||||||
uw.eq(ShopOrder::getOrderNo, shopOrderNo);
|
uw.eq(ShopOrder::getOrderNo, shopOrderNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean updated = shopOrderService.update(uw);
|
boolean updated = shopOrderService.update(uw);
|
||||||
if (updated) {
|
if (updated) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,41 +1,37 @@
|
|||||||
package com.gxwebsoft.glt.task;
|
package com.gxwebsoft.glt.task;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||||
import com.gxwebsoft.common.core.annotation.IgnoreTenant;
|
import com.gxwebsoft.common.core.annotation.IgnoreTenant;
|
||||||
import com.gxwebsoft.glt.entity.GltTicketTemplate;
|
import com.gxwebsoft.common.core.enums.ShopDealerCapitalUpdateEnum;
|
||||||
import com.gxwebsoft.glt.service.GltTicketTemplateService;
|
import com.gxwebsoft.common.core.enums.ShopDealerTypeEnum;
|
||||||
import com.gxwebsoft.shop.entity.ShopDealerCapital;
|
|
||||||
import com.gxwebsoft.shop.entity.ShopDealerOrder;
|
|
||||||
import com.gxwebsoft.shop.entity.ShopDealerReferee;
|
|
||||||
import com.gxwebsoft.shop.entity.ShopDealerSetting;
|
|
||||||
import com.gxwebsoft.shop.entity.ShopDealerUser;
|
|
||||||
import com.gxwebsoft.shop.entity.ShopGoods;
|
|
||||||
import com.gxwebsoft.shop.entity.ShopOrder;
|
|
||||||
import com.gxwebsoft.shop.entity.ShopOrderGoods;
|
|
||||||
import com.gxwebsoft.common.system.entity.User;
|
import com.gxwebsoft.common.system.entity.User;
|
||||||
import com.gxwebsoft.common.system.mapper.UserMapper;
|
import com.gxwebsoft.common.system.mapper.UserMapper;
|
||||||
import com.gxwebsoft.shop.service.ShopDealerCapitalService;
|
import com.gxwebsoft.glt.entity.GltTicketTemplate;
|
||||||
import com.gxwebsoft.shop.service.ShopDealerOrderService;
|
import com.gxwebsoft.glt.service.GltTicketTemplateService;
|
||||||
import com.gxwebsoft.shop.service.ShopDealerRefereeService;
|
import com.gxwebsoft.shop.dto.ShopDealerUserReduceDto;
|
||||||
import com.gxwebsoft.shop.service.ShopDealerSettingService;
|
import com.gxwebsoft.shop.entity.*;
|
||||||
import com.gxwebsoft.shop.service.ShopDealerUserService;
|
import com.gxwebsoft.shop.mapper.ShopDealerRefereeMapper;
|
||||||
import com.gxwebsoft.shop.service.ShopGoodsService;
|
import com.gxwebsoft.shop.mapper.ShopOrderMapper;
|
||||||
import com.gxwebsoft.shop.service.ShopOrderService;
|
import com.gxwebsoft.shop.service.*;
|
||||||
import com.gxwebsoft.shop.service.ShopOrderGoodsService;
|
|
||||||
import com.gxwebsoft.shop.util.UpstreamUserFinder;
|
import com.gxwebsoft.shop.util.UpstreamUserFinder;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.gxwebsoft.shop.vo.ShopOrderGoodsVO;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.apache.commons.collections4.CollectionUtils;
|
||||||
import org.springframework.scheduling.annotation.Scheduled;
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 租户10584:分销订单结算任务
|
* 租户10584:分销订单结算任务
|
||||||
@@ -50,7 +46,6 @@ public class DealerOrderSettlement10584Task {
|
|||||||
|
|
||||||
private static final BigDecimal RATE_0_10 = new BigDecimal("0.10");
|
private static final BigDecimal RATE_0_10 = new BigDecimal("0.10");
|
||||||
private static final BigDecimal RATE_0_05 = new BigDecimal("0.05");
|
private static final BigDecimal RATE_0_05 = new BigDecimal("0.05");
|
||||||
private static final BigDecimal RATE_0_03 = new BigDecimal("0.03");
|
|
||||||
private static final BigDecimal RATE_0_02 = new BigDecimal("0.02");
|
private static final BigDecimal RATE_0_02 = new BigDecimal("0.02");
|
||||||
private static final BigDecimal RATE_0_01 = new BigDecimal("0.01");
|
private static final BigDecimal RATE_0_01 = new BigDecimal("0.01");
|
||||||
private static final BigDecimal TOTAL_DEALER_DIVIDEND_RATE = RATE_0_01;
|
private static final BigDecimal TOTAL_DEALER_DIVIDEND_RATE = RATE_0_01;
|
||||||
@@ -92,14 +87,23 @@ public class DealerOrderSettlement10584Task {
|
|||||||
@Resource
|
@Resource
|
||||||
private GltTicketTemplateService gltTicketTemplateService;
|
private GltTicketTemplateService gltTicketTemplateService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ShopOrderMapper shopOrderMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ShopDealerRefereeMapper shopDealerRefereeMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 每10秒执行一次。
|
* 每10秒执行一次。
|
||||||
*/
|
*/
|
||||||
@Scheduled(cron = "0/10 * * * * ?")
|
// @Scheduled(cron = "0/10 * * * * ?")
|
||||||
@IgnoreTenant("该定时任务仅处理租户10584,但需要显式按tenantId过滤,避免定时任务线程无租户上下文导致查询异常")
|
@IgnoreTenant("该定时任务仅处理租户10584,但需要显式按tenantId过滤,避免定时任务线程无租户上下文导致查询异常")
|
||||||
public void settleTenant10584Orders() {
|
public void settleTenant10584Orders() {
|
||||||
try {
|
try {
|
||||||
|
//获取水票模板对应的商品信息列表
|
||||||
Set<Integer> waterFormIds = loadWaterFormIds();
|
Set<Integer> waterFormIds = loadWaterFormIds();
|
||||||
|
|
||||||
|
//查询商品列表存在已支付未核销订单数据
|
||||||
List<ShopOrder> orders = findUnsettledPaidOrders(waterFormIds);
|
List<ShopOrder> orders = findUnsettledPaidOrders(waterFormIds);
|
||||||
if (orders.isEmpty()) {
|
if (orders.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -108,7 +112,11 @@ public class DealerOrderSettlement10584Task {
|
|||||||
// Per-run caches to reduce DB chatter across orders.
|
// Per-run caches to reduce DB chatter across orders.
|
||||||
Map<Integer, Integer> level1ParentCache = new HashMap<>();
|
Map<Integer, Integer> level1ParentCache = new HashMap<>();
|
||||||
Map<Integer, Boolean> shopRoleCache = new HashMap<>();
|
Map<Integer, Boolean> shopRoleCache = new HashMap<>();
|
||||||
|
|
||||||
|
//获取系统设置分销等级
|
||||||
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
|
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
|
||||||
|
|
||||||
|
//获取分销员type=2第一个分销人作为平台总分红人
|
||||||
ShopDealerUser totalDealerUser = findTotalDealerUser();
|
ShopDealerUser totalDealerUser = findTotalDealerUser();
|
||||||
if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
|
if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
|
||||||
log.warn("未找到分红账号,订单仍可结算但不会发放分红 - tenantId={}", TENANT_ID);
|
log.warn("未找到分红账号,订单仍可结算但不会发放分红 - tenantId={}", TENANT_ID);
|
||||||
@@ -124,6 +132,7 @@ public class DealerOrderSettlement10584Task {
|
|||||||
try {
|
try {
|
||||||
transactionTemplate.executeWithoutResult(status -> {
|
transactionTemplate.executeWithoutResult(status -> {
|
||||||
// 先“认领”订单:并发/多实例下避免重复结算(update=0 表示被其他线程/实例处理)
|
// 先“认领”订单:并发/多实例下避免重复结算(update=0 表示被其他线程/实例处理)
|
||||||
|
//更新商品订单为已结算状态
|
||||||
if (!claimOrderToSettle(order.getOrderId(), waterFormIds)) {
|
if (!claimOrderToSettle(order.getOrderId(), waterFormIds)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -138,6 +147,88 @@ public class DealerOrderSettlement10584Task {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 每10分钟执行一次。
|
||||||
|
*/
|
||||||
|
@Scheduled(cron = "0 0/10 * * * ?")
|
||||||
|
@IgnoreTenant("该定时任务仅处理租户10584,但需要显式按tenantId过滤,避免定时任务线程无租户上下文导致查询异常")
|
||||||
|
public void settleTenant10584OrdersV2() {
|
||||||
|
try {
|
||||||
|
//获取水票模板对应的商品信息列表
|
||||||
|
Set<Integer> waterFormIds = loadWaterFormIds();
|
||||||
|
|
||||||
|
//查询商品列表存在已支付未核销订单数据【isSettled = 0, payStatus= 1, orderStatus 不在列表(2, 3, 4, 5, 6, 7)】
|
||||||
|
List<ShopOrder> orders = findUnsettledPaidOrders(waterFormIds);
|
||||||
|
if (orders.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Per-run caches to reduce DB chatter across orders.
|
||||||
|
Map<Integer, Integer> level1ParentCache = new HashMap<>();
|
||||||
|
Map<Integer, Boolean> shopRoleCache = new HashMap<>();
|
||||||
|
|
||||||
|
//获取系统设置分销等级
|
||||||
|
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
|
||||||
|
|
||||||
|
//获取分销员type=2第一个分销人作为平台总分红人
|
||||||
|
ShopDealerUser totalDealerUser = findTotalDealerUser();
|
||||||
|
if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
|
||||||
|
log.warn("未找到分红账号,订单仍可结算但不会发放分红 - tenantId={}", TENANT_ID);
|
||||||
|
}
|
||||||
|
log.debug("租户{}分销设置 - level={}", TENANT_ID, dealerBasicSetting.level);
|
||||||
|
|
||||||
|
log.info("租户{}待结算订单数: {}, orderNos(sample)={}",
|
||||||
|
TENANT_ID,
|
||||||
|
orders.size(),
|
||||||
|
orders.stream().limit(10).map(ShopOrder::getOrderNo).toList());
|
||||||
|
|
||||||
|
for (ShopOrder order : orders) {
|
||||||
|
try {
|
||||||
|
transactionTemplate.executeWithoutResult(status -> {
|
||||||
|
// 先“认领”订单:并发/多实例下避免重复结算(update=0 表示被其他线程/实例处理)
|
||||||
|
//更新商品订单为已结算状态
|
||||||
|
if (!claimOrderToSettle(order.getOrderId(), waterFormIds)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settleOneOrderV2(order, level1ParentCache, shopRoleCache, totalDealerUser, dealerBasicSetting.level);
|
||||||
|
});
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("订单结算失败,将回滚本订单并在下次任务重试 - orderId={}, orderNo={}", order.getOrderId(), order.getOrderNo(), e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("租户{}分销订单结算任务执行失败", TENANT_ID, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单分销金、分润金结算
|
||||||
|
*/
|
||||||
|
@Transactional
|
||||||
|
public void orderSettlement(String orderNo){
|
||||||
|
LambdaQueryWrapper<ShopOrder> orderLambdaQueryWrapper = new LambdaQueryWrapper<ShopOrder>().eq(ShopOrder::getOrderNo, orderNo).eq(ShopOrder::getIsSettled, 0).eq(ShopOrder::getPayStatus, 1);
|
||||||
|
ShopOrder order = shopOrderService.getOne(orderLambdaQueryWrapper);
|
||||||
|
if(order != null){
|
||||||
|
//获取系统设置分销等级
|
||||||
|
DealerBasicSetting dealerBasicSetting = findDealerBasicSetting();
|
||||||
|
|
||||||
|
//获取分销员type=2第一个分销人作为平台总分红人
|
||||||
|
ShopDealerUser totalDealerUser = findTotalDealerUser();
|
||||||
|
|
||||||
|
Map<Integer, Integer> level1ParentCache = new HashMap<>();
|
||||||
|
Map<Integer, Boolean> shopRoleCache = new HashMap<>();
|
||||||
|
|
||||||
|
transactionTemplate.executeWithoutResult(status -> {
|
||||||
|
// 先“认领”订单:并发/多实例下避免重复结算(update=0 表示被其他线程/实例处理)
|
||||||
|
//更新商品订单为已结算状态
|
||||||
|
if (!claimOrderToSettleV2(order.getOrderId())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
settleOneOrderV2(order, level1ParentCache, shopRoleCache, totalDealerUser, dealerBasicSetting.level);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<ShopOrder> findUnsettledPaidOrders(Set<Integer> waterFormIds) {
|
private List<ShopOrder> findUnsettledPaidOrders(Set<Integer> waterFormIds) {
|
||||||
// 租户10584约定:
|
// 租户10584约定:
|
||||||
// - 普通订单:以发货为准(deliveryStatus=20)才结算;
|
// - 普通订单:以发货为准(deliveryStatus=20)才结算;
|
||||||
@@ -148,7 +239,7 @@ public class DealerOrderSettlement10584Task {
|
|||||||
.eq(ShopOrder::getPayStatus, true)
|
.eq(ShopOrder::getPayStatus, true)
|
||||||
.eq(ShopOrder::getIsSettled, 0)
|
.eq(ShopOrder::getIsSettled, 0)
|
||||||
// 退款/取消订单不结算,避免“退款后仍发放分红/分润/佣金”
|
// 退款/取消订单不结算,避免“退款后仍发放分红/分润/佣金”
|
||||||
.and(w -> w.notIn(ShopOrder::getOrderStatus, 2, 4, 5, 6, 7).or().isNull(ShopOrder::getOrderStatus));
|
.and(w -> w.notIn(ShopOrder::getOrderStatus, 2, 3, 4, 5, 6, 7).or().isNull(ShopOrder::getOrderStatus));
|
||||||
|
|
||||||
if (waterFormIds != null && !waterFormIds.isEmpty()) {
|
if (waterFormIds != null && !waterFormIds.isEmpty()) {
|
||||||
qw.and(w -> w.eq(ShopOrder::getDeliveryStatus, 20).or().in(ShopOrder::getFormId, waterFormIds));
|
qw.and(w -> w.eq(ShopOrder::getDeliveryStatus, 20).or().in(ShopOrder::getFormId, waterFormIds));
|
||||||
@@ -178,6 +269,17 @@ public class DealerOrderSettlement10584Task {
|
|||||||
return shopOrderService.update(uw);
|
return shopOrderService.update(uw);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean claimOrderToSettleV2(Integer orderId) {
|
||||||
|
LambdaUpdateWrapper<ShopOrder> uw = new LambdaUpdateWrapper<ShopOrder>()
|
||||||
|
.eq(ShopOrder::getOrderId, orderId)
|
||||||
|
.eq(ShopOrder::getTenantId, TENANT_ID)
|
||||||
|
.eq(ShopOrder::getIsSettled, 0)
|
||||||
|
// 二次防御:退款/取消订单不允许被“认领结算”
|
||||||
|
.and(w -> w.notIn(ShopOrder::getOrderStatus, 2, 3, 4, 5, 6, 7).or().isNull(ShopOrder::getOrderStatus));
|
||||||
|
uw.set(ShopOrder::getIsSettled, 1);
|
||||||
|
return shopOrderService.update(uw);
|
||||||
|
}
|
||||||
|
|
||||||
private Set<Integer> loadWaterFormIds() {
|
private Set<Integer> loadWaterFormIds() {
|
||||||
try {
|
try {
|
||||||
return gltTicketTemplateService.list(
|
return gltTicketTemplateService.list(
|
||||||
@@ -252,6 +354,45 @@ public class DealerOrderSettlement10584Task {
|
|||||||
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), baseAmount);
|
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), baseAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void settleOneOrderV2(ShopOrder order, Map<Integer, Integer> level1ParentCache, Map<Integer, Boolean> shopRoleCache,
|
||||||
|
ShopDealerUser totalDealerUser, int dealerLevel) {
|
||||||
|
if (order.getUserId() == null || order.getOrderNo() == null) {
|
||||||
|
throw new IllegalStateException("订单关键信息缺失,无法结算 - orderId=" + order.getOrderId());
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal totalPrice = order.getTotalPrice();
|
||||||
|
BigDecimal payPrice = order.getPayPrice();
|
||||||
|
BigDecimal rate = payPrice.divide(totalPrice, 2, RoundingMode.HALF_UP);
|
||||||
|
|
||||||
|
if(payPrice.compareTo(BigDecimal.ZERO) <= 0){
|
||||||
|
log.info("订单号:{},实付金额为0,无需执行分销逻辑" + order.getOrderNo());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//查询订单号订单所有已开启分销的商品分润信息
|
||||||
|
List<ShopOrderGoodsVO> orderGoodsVOList = shopOrderMapper.getOrderGoodsInfo(order.getOrderNo());
|
||||||
|
if(CollectionUtils.isNotEmpty(orderGoodsVOList)){
|
||||||
|
// 1) 直推/间推(直接增加冻结账户余额)
|
||||||
|
DealerRefereeCommissionV2 dealerRefereeCommission = settleDealerRefereeCommissionV2(order, rate, orderGoodsVOList, dealerLevel);
|
||||||
|
|
||||||
|
// 2) 门店分润上级:从下单用户开始逐级向上找,命中 ShopDealerUser.type=1 的最近两级(直推门店/间推门店)【只统计数据,不对分销账户进行处理,
|
||||||
|
// 已日结形式,统计分销记录表:shop_dealer_order 做对应一级二级管理津贴结算】
|
||||||
|
ShopRoleCommission shopRoleCommission = settleShopRoleRefereeCommissionV2(order, rate, orderGoodsVOList, level1ParentCache, shopRoleCache);
|
||||||
|
|
||||||
|
// 3) 分红:固定比率,每个订单都分 TODO 总分红未开发,还按原逻辑走
|
||||||
|
int goodsQty = orderGoodsVOList.stream().mapToInt(ShopOrderGoodsVO::getTotalNum).sum();
|
||||||
|
TotalDealerCommission totalDealerCommission = settleTotalDealerCommissionV2(order, goodsQty, totalDealerUser);
|
||||||
|
|
||||||
|
// 4) 写入分销订单记录(用于排查/统计;详细分佣以 ShopDealerCapital 为准)
|
||||||
|
createDealerOrderRecordV2(order, dealerRefereeCommission, shopRoleCommission, totalDealerCommission);
|
||||||
|
|
||||||
|
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), payPrice);
|
||||||
|
}else {
|
||||||
|
log.error("订单号:{},未找到下单分销商品数据!", order.getOrderNo());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private DealerRefereeCommission settleDealerRefereeCommission(
|
private DealerRefereeCommission settleDealerRefereeCommission(
|
||||||
ShopOrder order,
|
ShopOrder order,
|
||||||
BigDecimal baseAmount,
|
BigDecimal baseAmount,
|
||||||
@@ -329,6 +470,85 @@ public class DealerOrderSettlement10584Task {
|
|||||||
return new DealerRefereeCommission(directDealerId, directMoney, simpleDealerId, simpleMoney, thirdDealerId, thirdMoney);
|
return new DealerRefereeCommission(directDealerId, directMoney, simpleDealerId, simpleMoney, thirdDealerId, thirdMoney);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取分销员分销霍金数据
|
||||||
|
* @param order
|
||||||
|
* @param orderGoodsVOList
|
||||||
|
* @param dealerLevel
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private DealerRefereeCommissionV2 settleDealerRefereeCommissionV2(ShopOrder order, BigDecimal rate, List<ShopOrderGoodsVO> orderGoodsVOList, int dealerLevel) {
|
||||||
|
Integer directDealerId = null;
|
||||||
|
Integer simpleDealerId = null;
|
||||||
|
AtomicReference<BigDecimal> directMoney = new AtomicReference<>(BigDecimal.ZERO);
|
||||||
|
AtomicReference<BigDecimal> simpleMoney = new AtomicReference<>(BigDecimal.ZERO);
|
||||||
|
|
||||||
|
|
||||||
|
if (dealerLevel >= 1) {
|
||||||
|
Integer dealerId = shopDealerRefereeMapper.getDealerIdByUserId(order.getUserId());
|
||||||
|
if(dealerId != null){
|
||||||
|
directDealerId = dealerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (dealerLevel >= 2 && directDealerId != null) {
|
||||||
|
Integer dealerId = shopDealerRefereeMapper.getDealerIdByUserId(directDealerId);
|
||||||
|
if(dealerId != null){
|
||||||
|
simpleDealerId = dealerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(directDealerId != null || simpleDealerId != null){
|
||||||
|
Integer finalDirectDealerId = directDealerId;
|
||||||
|
Integer finalSimpleDealerId = simpleDealerId;
|
||||||
|
orderGoodsVOList.forEach(orderGoodsVO -> {
|
||||||
|
//获取商品分润比例/金额
|
||||||
|
BigDecimal firstMoney = orderGoodsVO.getFirstMoney();
|
||||||
|
BigDecimal secondMoney = orderGoodsVO.getSecondMoney();
|
||||||
|
|
||||||
|
//按实付比例计算单项应参与分润金额
|
||||||
|
BigDecimal itemRatePrice = orderGoodsVO.getPrice().multiply(BigDecimal.valueOf(orderGoodsVO.getTotalNum())).multiply(rate);
|
||||||
|
|
||||||
|
//一级分销员存在(type = 0)且单项实付金额大于0及商品设置了一级分销比例/金额
|
||||||
|
if(finalDirectDealerId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0 && firstMoney.compareTo(BigDecimal.ZERO) > 0){
|
||||||
|
BigDecimal one = calcMoneyByCommissionType(itemRatePrice, firstMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
|
||||||
|
directMoney.accumulateAndGet(one, BigDecimal::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
//一级分销员存在(type = 0)且单项实付金额大于0及商品设置了一级分销比例/金额
|
||||||
|
if(finalSimpleDealerId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0 && secondMoney.compareTo(BigDecimal.ZERO) > 0 ){
|
||||||
|
BigDecimal two = calcMoneyByCommissionType(itemRatePrice, secondMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
|
||||||
|
simpleMoney.accumulateAndGet(two, BigDecimal::add);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//一级分销员账户增加冻结金额
|
||||||
|
if (directDealerId != null && directMoney.get().compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
|
||||||
|
reduceDto.setTypeEnum(ShopDealerTypeEnum.FREEZE_ACCOUNT);
|
||||||
|
reduceDto.setUserId(directDealerId);
|
||||||
|
reduceDto.setOrderUserId(order.getUserId());
|
||||||
|
reduceDto.setOrderNo(order.getOrderNo());
|
||||||
|
reduceDto.setPrice(directMoney.get());
|
||||||
|
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DISTRIBUTION_INCOME);
|
||||||
|
shopDealerUserService.reduceBalance(reduceDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
//二级分销员账户增加冻结金额
|
||||||
|
if (simpleDealerId != null && simpleMoney.get().compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
|
||||||
|
reduceDto.setTypeEnum(ShopDealerTypeEnum.FREEZE_ACCOUNT);
|
||||||
|
reduceDto.setUserId(simpleDealerId);
|
||||||
|
reduceDto.setOrderUserId(order.getUserId());
|
||||||
|
reduceDto.setOrderNo(order.getOrderNo());
|
||||||
|
reduceDto.setPrice(simpleMoney.get());
|
||||||
|
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DISTRIBUTION_INCOME);
|
||||||
|
shopDealerUserService.reduceBalance(reduceDto);
|
||||||
|
}
|
||||||
|
return new DealerRefereeCommissionV2(directDealerId, directMoney.get(), simpleDealerId, simpleMoney.get());
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private Integer getDealerRefereeId(Integer userId) {
|
private Integer getDealerRefereeId(Integer userId) {
|
||||||
return getDealerRefereeId(userId, 1);
|
return getDealerRefereeId(userId, 1);
|
||||||
}
|
}
|
||||||
@@ -412,6 +632,54 @@ public class DealerOrderSettlement10584Task {
|
|||||||
return new ShopRoleCommission(shopRoleReferees.get(0), storeDirectMoney, shopRoleReferees.get(1), storeSimpleMoney);
|
return new ShopRoleCommission(shopRoleReferees.get(0), storeDirectMoney, shopRoleReferees.get(1), storeSimpleMoney);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private ShopRoleCommission settleShopRoleRefereeCommissionV2(ShopOrder order, BigDecimal rate, List<ShopOrderGoodsVO> orderGoodsVOList, Map<Integer, Integer> level1ParentCache, Map<Integer, Boolean> shopRoleCache) {
|
||||||
|
List<Integer> shopRoleReferees = findFirstTwoShopRoleReferees(order.getUserId(), level1ParentCache, shopRoleCache);
|
||||||
|
log.info("门店分润命中结果(type=1门店角色取前两级) - orderNo={}, buyerUserId={}, shopRoleReferees={}",
|
||||||
|
order.getOrderNo(), order.getUserId(), shopRoleReferees);
|
||||||
|
if (shopRoleReferees.isEmpty()) {
|
||||||
|
return ShopRoleCommission.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CollectionUtils.isNotEmpty(shopRoleReferees)){
|
||||||
|
Integer storeDirectUserId;
|
||||||
|
Integer storeSimpleUserId = null;
|
||||||
|
AtomicReference<BigDecimal> storeDirectMoney = new AtomicReference<>(BigDecimal.ZERO);
|
||||||
|
AtomicReference<BigDecimal> storeSimpleMoney = new AtomicReference<>(BigDecimal.ZERO);
|
||||||
|
|
||||||
|
if(shopRoleReferees.size() == 1){
|
||||||
|
storeDirectUserId = shopRoleReferees.get(0);
|
||||||
|
}else {
|
||||||
|
storeDirectUserId = shopRoleReferees.get(0);
|
||||||
|
storeSimpleUserId = shopRoleReferees.get(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Integer finalStoreDirectUserId = storeDirectUserId;
|
||||||
|
Integer finalStoreSimpleUserId = storeSimpleUserId;
|
||||||
|
orderGoodsVOList.forEach(orderGoodsVO ->{
|
||||||
|
//获取商品对应服务商管理费分润比例/金额
|
||||||
|
BigDecimal firstMoney = orderGoodsVO.getFirstDividend();
|
||||||
|
BigDecimal secondMoney = orderGoodsVO.getSecondDividend();
|
||||||
|
|
||||||
|
//按实付比例计算单项应参与分润金额
|
||||||
|
BigDecimal itemRatePrice = orderGoodsVO.getPrice().multiply(BigDecimal.valueOf(orderGoodsVO.getTotalNum())).multiply(rate);
|
||||||
|
|
||||||
|
if(finalStoreDirectUserId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0){
|
||||||
|
BigDecimal one = calcMoneyByCommissionType(itemRatePrice, firstMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
|
||||||
|
storeDirectMoney.accumulateAndGet(one, BigDecimal::add);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(finalStoreSimpleUserId != null && itemRatePrice.compareTo(BigDecimal.ZERO) > 0){
|
||||||
|
BigDecimal two = calcMoneyByCommissionType(itemRatePrice, secondMoney, orderGoodsVO.getTotalNum(), 2, orderGoodsVO.getCommissionType());
|
||||||
|
storeSimpleMoney.accumulateAndGet(two, BigDecimal::add);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return new ShopRoleCommission(storeDirectUserId, storeDirectMoney.get(), storeSimpleUserId, storeSimpleMoney.get());
|
||||||
|
}else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private TotalDealerCommission settleTotalDealerCommission(
|
private TotalDealerCommission settleTotalDealerCommission(
|
||||||
ShopOrder order,
|
ShopOrder order,
|
||||||
BigDecimal baseAmount,
|
BigDecimal baseAmount,
|
||||||
@@ -438,6 +706,32 @@ public class DealerOrderSettlement10584Task {
|
|||||||
return new TotalDealerCommission(totalDealerUser.getUserId(), money);
|
return new TotalDealerCommission(totalDealerUser.getUserId(), money);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private TotalDealerCommission settleTotalDealerCommissionV2(ShopOrder order, int goodsQty, ShopDealerUser totalDealerUser) {
|
||||||
|
if (totalDealerUser == null || totalDealerUser.getUserId() == null) {
|
||||||
|
return TotalDealerCommission.empty();
|
||||||
|
}
|
||||||
|
BigDecimal rate = safePositive(totalDealerUser.getRate());
|
||||||
|
if (rate.signum() <= 0) {
|
||||||
|
rate = TOTAL_DEALER_DIVIDEND_RATE;
|
||||||
|
}
|
||||||
|
BigDecimal money = calcMoneyByCommissionType(order.getPayPrice(), rate, goodsQty, DIVIDEND_SCALE, 20);
|
||||||
|
|
||||||
|
//一级分销员账户增加冻结金额
|
||||||
|
if (money.compareTo(BigDecimal.ZERO) > 0) {
|
||||||
|
ShopDealerUserReduceDto reduceDto = new ShopDealerUserReduceDto();
|
||||||
|
reduceDto.setTypeEnum(ShopDealerTypeEnum.FREEZE_ACCOUNT);
|
||||||
|
reduceDto.setUserId(totalDealerUser.getUserId());
|
||||||
|
reduceDto.setOrderUserId(order.getUserId());
|
||||||
|
reduceDto.setOrderNo(order.getOrderNo());
|
||||||
|
reduceDto.setPrice(money);
|
||||||
|
reduceDto.setUpdateEnum(ShopDealerCapitalUpdateEnum.DIVIDEND_INCOME);
|
||||||
|
shopDealerUserService.reduceBalance(reduceDto);
|
||||||
|
|
||||||
|
return new TotalDealerCommission(totalDealerUser.getUserId(), money);
|
||||||
|
}
|
||||||
|
return TotalDealerCommission.empty();
|
||||||
|
}
|
||||||
|
|
||||||
private ShopDealerUser findTotalDealerUser() {
|
private ShopDealerUser findTotalDealerUser() {
|
||||||
return shopDealerUserService.getOne(
|
return shopDealerUserService.getOne(
|
||||||
new LambdaQueryWrapper<ShopDealerUser>()
|
new LambdaQueryWrapper<ShopDealerUser>()
|
||||||
@@ -756,6 +1050,92 @@ public class DealerOrderSettlement10584Task {
|
|||||||
order.getOrderNo(), dealerOrder.getFirstUserId(), dealerOrder.getSecondUserId(), dealerOrder.getFirstDividendUser(), dealerOrder.getSecondDividendUser());
|
order.getOrderNo(), dealerOrder.getFirstUserId(), dealerOrder.getSecondUserId(), dealerOrder.getFirstDividendUser(), dealerOrder.getSecondDividendUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 记录订单分销业务
|
||||||
|
* @param order 商品订单
|
||||||
|
* @param dealerRefereeCommission 一级、二级分销员分销数据
|
||||||
|
* @param shopRoleCommission 门店/服务商一级、二级管理津贴数据
|
||||||
|
*/
|
||||||
|
private void createDealerOrderRecordV2(ShopOrder order, DealerRefereeCommissionV2 dealerRefereeCommission, ShopRoleCommission shopRoleCommission, TotalDealerCommission totalDealerCommission) {
|
||||||
|
// 幂等:同一订单只写一条(依赖 order_no + tenant_id 作为业务唯一)
|
||||||
|
ShopDealerOrder existed = shopDealerOrderService.getOne(
|
||||||
|
new LambdaQueryWrapper<ShopDealerOrder>()
|
||||||
|
.eq(ShopDealerOrder::getTenantId, TENANT_ID)
|
||||||
|
.eq(ShopDealerOrder::getOrderNo, order.getOrderNo())
|
||||||
|
.last("limit 1")
|
||||||
|
);
|
||||||
|
if (existed != null) {
|
||||||
|
// 允许“补发”门店分润时回填分润字段,避免订单已结算但分润字段一直为空,影响排查/对账。
|
||||||
|
LambdaUpdateWrapper<ShopDealerOrder> uw = new LambdaUpdateWrapper<ShopDealerOrder>()
|
||||||
|
.eq(ShopDealerOrder::getTenantId, TENANT_ID)
|
||||||
|
.eq(ShopDealerOrder::getOrderNo, order.getOrderNo());
|
||||||
|
boolean needUpdate = false;
|
||||||
|
if (shopRoleCommission != null && shopRoleCommission.storeDirectUserId != null) {
|
||||||
|
Integer existedUser = existed.getFirstDividendUser();
|
||||||
|
boolean needSetUser = existedUser == null;
|
||||||
|
boolean needSetMoney = existed.getFirstDividend() == null || existed.getFirstDividend().signum() == 0;
|
||||||
|
if (needSetUser) {
|
||||||
|
uw.set(ShopDealerOrder::getFirstDividendUser, shopRoleCommission.storeDirectUserId);
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
boolean sameUser = existedUser == null || Objects.equals(existedUser, shopRoleCommission.storeDirectUserId);
|
||||||
|
if (sameUser && needSetMoney && shopRoleCommission.storeDirectMoney != null && shopRoleCommission.storeDirectMoney.signum() > 0) {
|
||||||
|
uw.set(ShopDealerOrder::getFirstDividend, shopRoleCommission.storeDirectMoney);
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (shopRoleCommission != null && shopRoleCommission.storeSimpleUserId != null) {
|
||||||
|
Integer existedUser = existed.getSecondDividendUser();
|
||||||
|
boolean needSetUser = existedUser == null;
|
||||||
|
boolean needSetMoney = existed.getSecondDividend() == null || existed.getSecondDividend().signum() == 0;
|
||||||
|
if (needSetUser) {
|
||||||
|
uw.set(ShopDealerOrder::getSecondDividendUser, shopRoleCommission.storeSimpleUserId);
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
boolean sameUser = existedUser == null || Objects.equals(existedUser, shopRoleCommission.storeSimpleUserId);
|
||||||
|
if (sameUser && needSetMoney && shopRoleCommission.storeSimpleMoney != null && shopRoleCommission.storeSimpleMoney.signum() > 0) {
|
||||||
|
uw.set(ShopDealerOrder::getSecondDividend, shopRoleCommission.storeSimpleMoney);
|
||||||
|
needUpdate = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (needUpdate) {
|
||||||
|
shopDealerOrderService.update(uw);
|
||||||
|
log.info("ShopDealerOrder已存在,回填门店分润字段 - orderNo={}, firstDividendUser={}, secondDividendUser={}",
|
||||||
|
order.getOrderNo(), shopRoleCommission.storeDirectUserId, shopRoleCommission.storeSimpleUserId);
|
||||||
|
} else {
|
||||||
|
log.info("ShopDealerOrder已存在,跳过写入 - orderNo={}", order.getOrderNo());
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}else {
|
||||||
|
|
||||||
|
ShopDealerOrder dealerOrder = new ShopDealerOrder();
|
||||||
|
dealerOrder.setUserId(order.getUserId()); // 买家用户ID
|
||||||
|
dealerOrder.setOrderNo(order.getOrderNo());
|
||||||
|
dealerOrder.setOrderPrice(order.getTotalPrice());
|
||||||
|
dealerOrder.setPayPrice(order.getPayPrice());
|
||||||
|
|
||||||
|
//一级、二级分销员分销佣金统计
|
||||||
|
dealerOrder.setFirstUserId(dealerRefereeCommission != null ? dealerRefereeCommission.directDealerId : null);
|
||||||
|
dealerOrder.setFirstMoney(dealerRefereeCommission != null ? dealerRefereeCommission.directMoney : BigDecimal.ZERO);
|
||||||
|
dealerOrder.setSecondUserId(dealerRefereeCommission != null ? dealerRefereeCommission.simpleDealerId : null);
|
||||||
|
dealerOrder.setSecondMoney(dealerRefereeCommission != null ? dealerRefereeCommission.simpleMoney : BigDecimal.ZERO);
|
||||||
|
|
||||||
|
//门店(角色shop)两级分润单独落字段(详细以 ShopDealerCapital 为准)
|
||||||
|
dealerOrder.setFirstDividendUser(shopRoleCommission != null ? shopRoleCommission.storeDirectUserId : null);
|
||||||
|
dealerOrder.setFirstDividend(shopRoleCommission != null ? shopRoleCommission.storeDirectMoney : BigDecimal.ZERO);
|
||||||
|
dealerOrder.setSecondDividendUser(shopRoleCommission != null ? shopRoleCommission.storeSimpleUserId : null);
|
||||||
|
dealerOrder.setSecondDividend(shopRoleCommission != null ? shopRoleCommission.storeSimpleMoney : BigDecimal.ZERO);
|
||||||
|
|
||||||
|
dealerOrder.setIsSettled(1);
|
||||||
|
dealerOrder.setSettleTime(LocalDateTime.now());
|
||||||
|
dealerOrder.setMonth(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM")));
|
||||||
|
dealerOrder.setTenantId(TENANT_ID);
|
||||||
|
dealerOrder.setComments(buildCommissionTraceCommentV2(dealerRefereeCommission, shopRoleCommission, totalDealerCommission));
|
||||||
|
|
||||||
|
shopDealerOrderService.save(dealerOrder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private String buildCommissionTraceComment(
|
private String buildCommissionTraceComment(
|
||||||
DealerRefereeCommission dealerRefereeCommission,
|
DealerRefereeCommission dealerRefereeCommission,
|
||||||
ShopRoleCommission shopRoleCommission,
|
ShopRoleCommission shopRoleCommission,
|
||||||
@@ -770,6 +1150,30 @@ public class DealerOrderSettlement10584Task {
|
|||||||
+ ",totalDealer=" + totalDealerCommission.userId + ":" + totalDealerCommission.money;
|
+ ",totalDealer=" + totalDealerCommission.userId + ":" + totalDealerCommission.money;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String buildCommissionTraceCommentV2(
|
||||||
|
DealerRefereeCommissionV2 dealerRefereeCommission,
|
||||||
|
ShopRoleCommission shopRoleCommission,
|
||||||
|
TotalDealerCommission totalDealerCommission
|
||||||
|
) {
|
||||||
|
// 轻量“过程”留痕,方便排查;详细分佣以 ShopDealerCapital 为准。
|
||||||
|
Integer direct = dealerRefereeCommission != null ? dealerRefereeCommission.directDealerId : null;
|
||||||
|
BigDecimal directMoney = dealerRefereeCommission != null ? dealerRefereeCommission.directMoney : BigDecimal.ZERO;
|
||||||
|
Integer simpleDealerId = dealerRefereeCommission != null ? dealerRefereeCommission.simpleDealerId : null;
|
||||||
|
BigDecimal simpleMoney = dealerRefereeCommission != null ? dealerRefereeCommission.simpleMoney : BigDecimal.ZERO;
|
||||||
|
Integer storeDirectUserId = shopRoleCommission != null ? shopRoleCommission.storeDirectUserId : null;
|
||||||
|
BigDecimal storeDirectMoney = shopRoleCommission != null ? shopRoleCommission.storeDirectMoney : BigDecimal.ZERO;
|
||||||
|
Integer storeSimpleUserId = shopRoleCommission != null ? shopRoleCommission.storeSimpleUserId : null;
|
||||||
|
BigDecimal storeSimpleMoney = shopRoleCommission != null ? shopRoleCommission.storeSimpleMoney : BigDecimal.ZERO;
|
||||||
|
Integer userId = totalDealerCommission != null ? totalDealerCommission.userId : null;
|
||||||
|
BigDecimal money = totalDealerCommission != null ? totalDealerCommission.money : BigDecimal.ZERO;
|
||||||
|
|
||||||
|
return "direct=" + direct + ":" + directMoney
|
||||||
|
+ ",simple=" + simpleDealerId + ":" + simpleMoney
|
||||||
|
+ ",dividend1=" + storeDirectUserId + ":" + storeDirectMoney
|
||||||
|
+ ",dividend2=" + storeSimpleUserId + ":" + storeSimpleMoney
|
||||||
|
+ ",totalDealer=" + userId + ":" + money;
|
||||||
|
}
|
||||||
|
|
||||||
private BigDecimal getOrderBaseAmount(ShopOrder order) {
|
private BigDecimal getOrderBaseAmount(ShopOrder order) {
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
return null;
|
return null;
|
||||||
@@ -962,6 +1366,25 @@ public class DealerOrderSettlement10584Task {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class DealerRefereeCommissionV2 {
|
||||||
|
private final Integer directDealerId;
|
||||||
|
private final BigDecimal directMoney;
|
||||||
|
private final Integer simpleDealerId;
|
||||||
|
private final BigDecimal simpleMoney;
|
||||||
|
|
||||||
|
private DealerRefereeCommissionV2(
|
||||||
|
Integer directDealerId,
|
||||||
|
BigDecimal directMoney,
|
||||||
|
Integer simpleDealerId,
|
||||||
|
BigDecimal simpleMoney
|
||||||
|
) {
|
||||||
|
this.directDealerId = directDealerId;
|
||||||
|
this.directMoney = directMoney != null ? directMoney : BigDecimal.ZERO;
|
||||||
|
this.simpleDealerId = simpleDealerId;
|
||||||
|
this.simpleMoney = simpleMoney != null ? simpleMoney : BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class ShopRoleCommission {
|
private static class ShopRoleCommission {
|
||||||
private final Integer storeDirectUserId;
|
private final Integer storeDirectUserId;
|
||||||
private final BigDecimal storeDirectMoney;
|
private final BigDecimal storeDirectMoney;
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.annotation.IdType;
|
|||||||
import com.baomidou.mybatisplus.annotation.TableField;
|
import com.baomidou.mybatisplus.annotation.TableField;
|
||||||
import com.baomidou.mybatisplus.annotation.TableId;
|
import com.baomidou.mybatisplus.annotation.TableId;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.TableName;
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
@@ -23,6 +25,7 @@ import lombok.EqualsAndHashCode;
|
|||||||
@Data
|
@Data
|
||||||
@EqualsAndHashCode(callSuper = false)
|
@EqualsAndHashCode(callSuper = false)
|
||||||
@Schema(name = "ShopDealerOrder对象", description = "分销商订单记录表")
|
@Schema(name = "ShopDealerOrder对象", description = "分销商订单记录表")
|
||||||
|
@TableName("shop_dealer_order")
|
||||||
public class ShopDealerOrder implements Serializable {
|
public class ShopDealerOrder implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@@ -66,6 +69,9 @@ public class ShopDealerOrder implements Serializable {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String firstNickname;
|
private String firstNickname;
|
||||||
|
|
||||||
|
@Schema(description = "分销佣金(一级)")
|
||||||
|
private BigDecimal firstMoney;
|
||||||
|
|
||||||
@Schema(description = "分销商用户id(二级)")
|
@Schema(description = "分销商用户id(二级)")
|
||||||
private Integer secondUserId;
|
private Integer secondUserId;
|
||||||
|
|
||||||
@@ -73,42 +79,57 @@ public class ShopDealerOrder implements Serializable {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String secondNickname;
|
private String secondNickname;
|
||||||
|
|
||||||
@Schema(description = "分销商用户id(三级)")
|
|
||||||
private Integer thirdUserId;
|
|
||||||
|
|
||||||
@Schema(description = "分销商用户昵称(三级)")
|
|
||||||
@TableField(exist = false)
|
|
||||||
private String thirdNickname;
|
|
||||||
|
|
||||||
@Schema(description = "分销佣金(一级)")
|
|
||||||
private BigDecimal firstMoney;
|
|
||||||
|
|
||||||
@Schema(description = "分销佣金(二级)")
|
@Schema(description = "分销佣金(二级)")
|
||||||
private BigDecimal secondMoney;
|
private BigDecimal secondMoney;
|
||||||
|
|
||||||
@Schema(description = "分销佣金(三级)")
|
@Schema(description = "分销商用户id(弃用)")
|
||||||
|
private Integer thirdUserId;
|
||||||
|
|
||||||
|
@Schema(description = "分销商用户昵称(弃用)")
|
||||||
|
@TableField(exist = false)
|
||||||
|
private String thirdNickname;
|
||||||
|
|
||||||
|
@Schema(description = "分销佣金(弃用)")
|
||||||
private BigDecimal thirdMoney;
|
private BigDecimal thirdMoney;
|
||||||
|
|
||||||
@Schema(description = "门店(一级)")
|
@Schema(description = "一级服务商/门店")
|
||||||
private Integer firstDividendUser;
|
private Integer firstDividendUser;
|
||||||
|
|
||||||
@Schema(description = "门店名称(一级)")
|
@Schema(description = "一级服务商/门店名称")
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String firstDividendUserName;
|
private String firstDividendUserName;
|
||||||
|
|
||||||
@Schema(description = "分红(一级)")
|
@Schema(description = "一级服务商/门店管理津贴")
|
||||||
private BigDecimal firstDividend;
|
private BigDecimal firstDividend;
|
||||||
|
|
||||||
@Schema(description = "门店(二级)")
|
@Schema(description = "一级服务商/门店结算标识 0-否 1-是")
|
||||||
|
private Integer firstDividendFlag;
|
||||||
|
|
||||||
|
@Schema(description = "一级服务商/门店结算单号")
|
||||||
|
private String firstDividendNo;
|
||||||
|
|
||||||
|
@Schema(description = "一级服务商/门店结算时间")
|
||||||
|
private LocalDateTime firstDividendTime;
|
||||||
|
|
||||||
|
@Schema(description = "二级服务商/门店")
|
||||||
private Integer secondDividendUser;
|
private Integer secondDividendUser;
|
||||||
|
|
||||||
@Schema(description = "门店名称(二级)")
|
@Schema(description = "二级服务商/门店名称")
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private String secondDividendUserName;
|
private String secondDividendUserName;
|
||||||
|
|
||||||
@Schema(description = "分红(二级)")
|
@Schema(description = "二级服务商/门店管理津贴")
|
||||||
private BigDecimal secondDividend;
|
private BigDecimal secondDividend;
|
||||||
|
|
||||||
|
@Schema(description = "二级服务商/门店结算标识 0-否 1-是")
|
||||||
|
private Integer secondDividendFlag;
|
||||||
|
|
||||||
|
@Schema(description = "二级服务商/门店结算单号")
|
||||||
|
private String secondDividendNo;
|
||||||
|
|
||||||
|
@Schema(description = "二级服务商/门店结算时间")
|
||||||
|
private LocalDateTime secondDividendTime;
|
||||||
|
|
||||||
@Schema(description = "佣金比例")
|
@Schema(description = "佣金比例")
|
||||||
private BigDecimal rate;
|
private BigDecimal rate;
|
||||||
|
|
||||||
|
|||||||
@@ -34,4 +34,11 @@ public interface ShopDealerRefereeMapper extends BaseMapper<ShopDealerReferee> {
|
|||||||
*/
|
*/
|
||||||
List<ShopDealerReferee> selectListRel(@Param("param") ShopDealerRefereeParam param);
|
List<ShopDealerReferee> selectListRel(@Param("param") ShopDealerRefereeParam param);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过用户ID查询上一级分销人信息【type = 0】
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Integer getDealerIdByUserId(@Param("userId") Integer userId);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
|||||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||||
import com.gxwebsoft.shop.entity.ShopOrder;
|
import com.gxwebsoft.shop.entity.ShopOrder;
|
||||||
import com.gxwebsoft.shop.param.ShopOrderParam;
|
import com.gxwebsoft.shop.param.ShopOrderParam;
|
||||||
|
import com.gxwebsoft.shop.vo.ShopOrderGoodsVO;
|
||||||
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.springframework.transaction.annotation.Transactional;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -60,4 +60,11 @@ public interface ShopOrderMapper extends BaseMapper<ShopOrder> {
|
|||||||
Map<String, Object> selectUserOrderStats(@Param("userId") Integer userId,
|
Map<String, Object> selectUserOrderStats(@Param("userId") Integer userId,
|
||||||
@Param("tenantId") Integer tenantId,
|
@Param("tenantId") Integer tenantId,
|
||||||
@Param("type") Integer type);
|
@Param("type") Integer type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过订单号查询订单所有商品分润信息
|
||||||
|
* @param orderNo 订单号
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<ShopOrderGoodsVO> getOrderGoodsInfo(@Param("orderNo") String orderNo);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,5 +57,16 @@
|
|||||||
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopDealerReferee">
|
<select id="selectListRel" resultType="com.gxwebsoft.shop.entity.ShopDealerReferee">
|
||||||
<include refid="selectSql"></include>
|
<include refid="selectSql"></include>
|
||||||
</select>
|
</select>
|
||||||
|
<select id="getDealerIdByUserId" resultType="java.lang.Integer">
|
||||||
|
SELECT
|
||||||
|
a.dealer_id
|
||||||
|
FROM
|
||||||
|
shop_dealer_referee a
|
||||||
|
LEFT JOIN shop_dealer_user b ON a.dealer_id = b.user_id
|
||||||
|
WHERE
|
||||||
|
b.is_delete = 0
|
||||||
|
AND b.type = 0
|
||||||
|
AND a.user_id = #{userId}
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|||||||
@@ -320,6 +320,28 @@
|
|||||||
<select id="getByOutTradeNo" resultType="com.gxwebsoft.shop.entity.ShopOrder">
|
<select id="getByOutTradeNo" resultType="com.gxwebsoft.shop.entity.ShopOrder">
|
||||||
SELECT * FROM shop_order WHERE order_no = #{outTradeNo}
|
SELECT * FROM shop_order WHERE order_no = #{outTradeNo}
|
||||||
</select>
|
</select>
|
||||||
|
<select id="getOrderGoodsInfo" resultType="com.gxwebsoft.shop.vo.ShopOrderGoodsVO">
|
||||||
|
SELECT
|
||||||
|
a.order_no,
|
||||||
|
b.goods_id,
|
||||||
|
c.`name`,
|
||||||
|
b.total_num,
|
||||||
|
b.price,
|
||||||
|
c.first_money,
|
||||||
|
c.second_money,
|
||||||
|
c.first_dividend,
|
||||||
|
c.second_dividend,
|
||||||
|
c.commission_type
|
||||||
|
FROM
|
||||||
|
shop_order a
|
||||||
|
LEFT JOIN shop_order_goods b ON a.order_id = b.order_id
|
||||||
|
LEFT JOIN shop_goods c ON b.goods_id = c.goods_id
|
||||||
|
WHERE
|
||||||
|
a.deleted = 0
|
||||||
|
AND c.deleted = 0
|
||||||
|
AND c.is_open_commission = 1
|
||||||
|
AND a.order_no = #{orderNo}
|
||||||
|
</select>
|
||||||
|
|
||||||
<!-- 根据订单号修改订单 -->
|
<!-- 根据订单号修改订单 -->
|
||||||
<update id="updateByOutTradeNo" parameterType="com.gxwebsoft.cms.entity.CmsWebsite">
|
<update id="updateByOutTradeNo" parameterType="com.gxwebsoft.cms.entity.CmsWebsite">
|
||||||
|
|||||||
47
src/main/java/com/gxwebsoft/shop/vo/ShopOrderGoodsVO.java
Normal file
47
src/main/java/com/gxwebsoft/shop/vo/ShopOrderGoodsVO.java
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
package com.gxwebsoft.shop.vo;
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 订单商品信息
|
||||||
|
* @author xm
|
||||||
|
* @since 2025-01-12
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@Schema(description = "订单商品信息")
|
||||||
|
public class ShopOrderGoodsVO {
|
||||||
|
|
||||||
|
@Schema(description = "订单号")
|
||||||
|
private String orderNo;
|
||||||
|
|
||||||
|
@Schema(description = "商品ID")
|
||||||
|
private Integer goodsId;
|
||||||
|
|
||||||
|
@Schema(description = "品名")
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@Schema(description = "购买数量")
|
||||||
|
private Integer totalNum;
|
||||||
|
|
||||||
|
@Schema(description = "单价")
|
||||||
|
private BigDecimal price;
|
||||||
|
|
||||||
|
@Schema(description = "结算方式 10按金额 20按比率")
|
||||||
|
private Integer commissionType;
|
||||||
|
|
||||||
|
@Schema(description = "一级分销员佣金比例/金额")
|
||||||
|
private BigDecimal firstMoney;
|
||||||
|
|
||||||
|
@Schema(description = "二级分销员佣金比例/金额")
|
||||||
|
private BigDecimal secondMoney;
|
||||||
|
|
||||||
|
@Schema(description = "一级服务商管理津贴比例/金额")
|
||||||
|
private BigDecimal firstDividend;
|
||||||
|
|
||||||
|
@Schema(description = "二级服务商管理津贴比例/金额")
|
||||||
|
private BigDecimal secondDividend;
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user