feat(settlement): 添加总经销商分润功能
- 引入 TOTAL_DEALER_DIVIDEND_RATE 常量用于总经销商分润计算 - 添加 findTotalDealerUserId 方法查找总经销商用户ID - 新增 settleTotalDealerCommission 方法实现总经销商分润逻辑 - 修改 settleOneOrder 方法传入总经销商用户ID参数 - 更新 createDealerOrderRecord 方法支持总经销商分润记录 - 扩展 buildCommissionTraceComment 方法包含总经销商分润信息 - 添加 TotalDealerCommission 内部类封装总经销商分润数据 - 实现总经销商分润的幂等处理和日志记录功能
This commit is contained in:
@@ -48,6 +48,7 @@ public class DealerOrderSettlement10584Task {
|
|||||||
private static final BigDecimal RATE_0_03 = new BigDecimal("0.03");
|
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 int MAX_ORDERS_PER_RUN = 50;
|
private static final int MAX_ORDERS_PER_RUN = 50;
|
||||||
private static final int MAX_REFEREE_CHAIN_DEPTH = 20;
|
private static final int MAX_REFEREE_CHAIN_DEPTH = 20;
|
||||||
@@ -95,6 +96,10 @@ 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<>();
|
||||||
|
Integer totalDealerUserId = findTotalDealerUserId();
|
||||||
|
if (totalDealerUserId == null) {
|
||||||
|
log.warn("未找到总经销商账号,订单仍可结算但不会发放总经销商分润 - tenantId={}", TENANT_ID);
|
||||||
|
}
|
||||||
|
|
||||||
log.info("租户{}待结算订单数: {}, orderNos(sample)={}",
|
log.info("租户{}待结算订单数: {}, orderNos(sample)={}",
|
||||||
TENANT_ID,
|
TENANT_ID,
|
||||||
@@ -108,7 +113,7 @@ public class DealerOrderSettlement10584Task {
|
|||||||
if (!claimOrderToSettle(order.getOrderId())) {
|
if (!claimOrderToSettle(order.getOrderId())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
settleOneOrder(order, level1ParentCache, shopRoleCache);
|
settleOneOrder(order, level1ParentCache, shopRoleCache, totalDealerUserId);
|
||||||
});
|
});
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("订单结算失败,将回滚本订单并在下次任务重试 - orderId={}, orderNo={}", order.getOrderId(), order.getOrderNo(), e);
|
log.error("订单结算失败,将回滚本订单并在下次任务重试 - orderId={}, orderNo={}", order.getOrderId(), order.getOrderNo(), e);
|
||||||
@@ -141,7 +146,12 @@ public class DealerOrderSettlement10584Task {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void settleOneOrder(ShopOrder order, Map<Integer, Integer> level1ParentCache, Map<Integer, Boolean> shopRoleCache) {
|
private void settleOneOrder(
|
||||||
|
ShopOrder order,
|
||||||
|
Map<Integer, Integer> level1ParentCache,
|
||||||
|
Map<Integer, Boolean> shopRoleCache,
|
||||||
|
Integer totalDealerUserId
|
||||||
|
) {
|
||||||
if (order.getUserId() == null || order.getOrderNo() == null) {
|
if (order.getUserId() == null || order.getOrderNo() == null) {
|
||||||
throw new IllegalStateException("订单关键信息缺失,无法结算 - orderId=" + order.getOrderId());
|
throw new IllegalStateException("订单关键信息缺失,无法结算 - orderId=" + order.getOrderId());
|
||||||
}
|
}
|
||||||
@@ -183,8 +193,11 @@ public class DealerOrderSettlement10584Task {
|
|||||||
// 2) 门店分红上级:从下单用户开始逐级向上找,命中 ShopDealerUser.type=1 的最近两级(直推门店/间推门店)。
|
// 2) 门店分红上级:从下单用户开始逐级向上找,命中 ShopDealerUser.type=1 的最近两级(直推门店/间推门店)。
|
||||||
ShopRoleCommission shopRoleCommission = settleShopRoleRefereeCommission(order, baseAmount, goodsQty, commissionConfig, level1ParentCache, shopRoleCache);
|
ShopRoleCommission shopRoleCommission = settleShopRoleRefereeCommission(order, baseAmount, goodsQty, commissionConfig, level1ParentCache, shopRoleCache);
|
||||||
|
|
||||||
// 3) 写入分销订单记录(用于排查/统计;详细分佣以 ShopDealerCapital 为准)
|
// 3) 总经销商分润:固定比率,每个订单都分。
|
||||||
createDealerOrderRecord(order, baseAmount, dealerRefereeCommission, shopRoleCommission);
|
TotalDealerCommission totalDealerCommission = settleTotalDealerCommission(order, baseAmount, goodsQty, totalDealerUserId);
|
||||||
|
|
||||||
|
// 4) 写入分销订单记录(用于排查/统计;详细分佣以 ShopDealerCapital 为准)
|
||||||
|
createDealerOrderRecord(order, baseAmount, dealerRefereeCommission, shopRoleCommission, totalDealerCommission);
|
||||||
|
|
||||||
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), baseAmount);
|
log.info("订单结算完成 - orderId={}, orderNo={}, baseAmount={}", order.getOrderId(), order.getOrderNo(), baseAmount);
|
||||||
}
|
}
|
||||||
@@ -323,6 +336,40 @@ 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 TotalDealerCommission settleTotalDealerCommission(
|
||||||
|
ShopOrder order,
|
||||||
|
BigDecimal baseAmount,
|
||||||
|
int goodsQty,
|
||||||
|
Integer totalDealerUserId
|
||||||
|
) {
|
||||||
|
if (totalDealerUserId == null) {
|
||||||
|
return TotalDealerCommission.empty();
|
||||||
|
}
|
||||||
|
BigDecimal money = calcMoneyByCommissionType(baseAmount, TOTAL_DEALER_DIVIDEND_RATE, goodsQty, DIVIDEND_SCALE, 20);
|
||||||
|
log.info("总经销商分润发放 - orderNo={}, totalDealerUserId={}, rate={}, money={}",
|
||||||
|
order.getOrderNo(), totalDealerUserId, TOTAL_DEALER_DIVIDEND_RATE, money);
|
||||||
|
creditDealerCommission(
|
||||||
|
totalDealerUserId,
|
||||||
|
money,
|
||||||
|
order,
|
||||||
|
order.getUserId(),
|
||||||
|
buildCommissionComment("总经销商分润", 20, TOTAL_DEALER_DIVIDEND_RATE, goodsQty)
|
||||||
|
);
|
||||||
|
return new TotalDealerCommission(totalDealerUserId, money);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Integer findTotalDealerUserId() {
|
||||||
|
ShopDealerUser dealerUser = shopDealerUserService.getOne(
|
||||||
|
new LambdaQueryWrapper<ShopDealerUser>()
|
||||||
|
.eq(ShopDealerUser::getTenantId, TENANT_ID)
|
||||||
|
.eq(ShopDealerUser::getType, 2)
|
||||||
|
.and(w -> w.eq(ShopDealerUser::getIsDelete, 0).or().isNull(ShopDealerUser::getIsDelete))
|
||||||
|
.orderByAsc(ShopDealerUser::getId)
|
||||||
|
.last("limit 1")
|
||||||
|
);
|
||||||
|
return dealerUser != null ? dealerUser.getUserId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 门店分红规则:
|
* 门店分红规则:
|
||||||
* - 门店角色为 ShopDealerUser.type=1;
|
* - 门店角色为 ShopDealerUser.type=1;
|
||||||
@@ -502,7 +549,8 @@ public class DealerOrderSettlement10584Task {
|
|||||||
ShopOrder order,
|
ShopOrder order,
|
||||||
BigDecimal baseAmount,
|
BigDecimal baseAmount,
|
||||||
DealerRefereeCommission dealerRefereeCommission,
|
DealerRefereeCommission dealerRefereeCommission,
|
||||||
ShopRoleCommission shopRoleCommission
|
ShopRoleCommission shopRoleCommission,
|
||||||
|
TotalDealerCommission totalDealerCommission
|
||||||
) {
|
) {
|
||||||
// 幂等:同一订单只写一条(依赖 order_no + tenant_id 作为业务唯一)
|
// 幂等:同一订单只写一条(依赖 order_no + tenant_id 作为业务唯一)
|
||||||
ShopDealerOrder existed = shopDealerOrderService.getOne(
|
ShopDealerOrder existed = shopDealerOrderService.getOne(
|
||||||
@@ -580,20 +628,25 @@ public class DealerOrderSettlement10584Task {
|
|||||||
dealerOrder.setMonth(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM")));
|
dealerOrder.setMonth(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM")));
|
||||||
dealerOrder.setTenantId(TENANT_ID);
|
dealerOrder.setTenantId(TENANT_ID);
|
||||||
|
|
||||||
dealerOrder.setComments(buildCommissionTraceComment(dealerRefereeCommission, shopRoleCommission));
|
dealerOrder.setComments(buildCommissionTraceComment(dealerRefereeCommission, shopRoleCommission, totalDealerCommission));
|
||||||
|
|
||||||
shopDealerOrderService.save(dealerOrder);
|
shopDealerOrderService.save(dealerOrder);
|
||||||
log.info("写入ShopDealerOrder完成 - orderNo={}, firstUserId={}, secondUserId={}, firstDividendUser={}, secondDividendUser={}",
|
log.info("写入ShopDealerOrder完成 - orderNo={}, firstUserId={}, secondUserId={}, firstDividendUser={}, secondDividendUser={}",
|
||||||
order.getOrderNo(), dealerOrder.getFirstUserId(), dealerOrder.getSecondUserId(), dealerOrder.getFirstDividendUser(), dealerOrder.getSecondDividendUser());
|
order.getOrderNo(), dealerOrder.getFirstUserId(), dealerOrder.getSecondUserId(), dealerOrder.getFirstDividendUser(), dealerOrder.getSecondDividendUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
private String buildCommissionTraceComment(DealerRefereeCommission dealerRefereeCommission, ShopRoleCommission shopRoleCommission) {
|
private String buildCommissionTraceComment(
|
||||||
|
DealerRefereeCommission dealerRefereeCommission,
|
||||||
|
ShopRoleCommission shopRoleCommission,
|
||||||
|
TotalDealerCommission totalDealerCommission
|
||||||
|
) {
|
||||||
// 轻量“过程”留痕,方便排查;详细分佣以 ShopDealerCapital 为准。
|
// 轻量“过程”留痕,方便排查;详细分佣以 ShopDealerCapital 为准。
|
||||||
return "direct=" + dealerRefereeCommission.directDealerId + ":" + dealerRefereeCommission.directMoney
|
return "direct=" + dealerRefereeCommission.directDealerId + ":" + dealerRefereeCommission.directMoney
|
||||||
+ ",simple=" + dealerRefereeCommission.simpleDealerId + ":" + dealerRefereeCommission.simpleMoney
|
+ ",simple=" + dealerRefereeCommission.simpleDealerId + ":" + dealerRefereeCommission.simpleMoney
|
||||||
+ ",third=" + dealerRefereeCommission.thirdDealerId + ":" + dealerRefereeCommission.thirdMoney
|
+ ",third=" + dealerRefereeCommission.thirdDealerId + ":" + dealerRefereeCommission.thirdMoney
|
||||||
+ ",dividend1=" + shopRoleCommission.storeDirectUserId + ":" + shopRoleCommission.storeDirectMoney
|
+ ",dividend1=" + shopRoleCommission.storeDirectUserId + ":" + shopRoleCommission.storeDirectMoney
|
||||||
+ ",dividend2=" + shopRoleCommission.storeSimpleUserId + ":" + shopRoleCommission.storeSimpleMoney;
|
+ ",dividend2=" + shopRoleCommission.storeSimpleUserId + ":" + shopRoleCommission.storeSimpleMoney
|
||||||
|
+ ",totalDealer=" + totalDealerCommission.userId + ":" + totalDealerCommission.money;
|
||||||
}
|
}
|
||||||
|
|
||||||
private BigDecimal getOrderBaseAmount(ShopOrder order) {
|
private BigDecimal getOrderBaseAmount(ShopOrder order) {
|
||||||
@@ -805,4 +858,18 @@ public class DealerOrderSettlement10584Task {
|
|||||||
this.storeSimpleMoney = storeSimpleMoney != null ? storeSimpleMoney : BigDecimal.ZERO;
|
this.storeSimpleMoney = storeSimpleMoney != null ? storeSimpleMoney : BigDecimal.ZERO;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class TotalDealerCommission {
|
||||||
|
private final Integer userId;
|
||||||
|
private final BigDecimal money;
|
||||||
|
|
||||||
|
private static TotalDealerCommission empty() {
|
||||||
|
return new TotalDealerCommission(null, BigDecimal.ZERO);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TotalDealerCommission(Integer userId, BigDecimal money) {
|
||||||
|
this.userId = userId;
|
||||||
|
this.money = money != null ? money : BigDecimal.ZERO;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user