@@ -6,10 +6,12 @@ import com.gxwebsoft.common.core.annotation.IgnoreTenant;
import com.gxwebsoft.common.system.entity.Role ;
import com.gxwebsoft.common.system.service.UserRoleService ;
import com.gxwebsoft.shop.entity.ShopDealerCapital ;
import com.gxwebsoft.shop.entity.ShopDealerOrder ;
import com.gxwebsoft.shop.entity.ShopDealerReferee ;
import com.gxwebsoft.shop.entity.ShopDealerUser ;
import com.gxwebsoft.shop.entity.ShopOrder ;
import com.gxwebsoft.shop.service.ShopDealerCapitalService ;
import com.gxwebsoft.shop.service.ShopDealerOrderService ;
import com.gxwebsoft.shop.service.ShopDealerRefereeService ;
import com.gxwebsoft.shop.service.ShopDealerUserService ;
import com.gxwebsoft.shop.service.ShopOrderService ;
@@ -58,6 +60,9 @@ public class DealerOrderSettlement10584Task {
@Resource
private ShopDealerCapitalService shopDealerCapitalService ;
@Resource
private ShopDealerOrderService shopDealerOrderService ;
@Resource
private UserRoleService userRoleService ;
@@ -73,6 +78,11 @@ public class DealerOrderSettlement10584Task {
return ;
}
log . info ( " 租户{}待结算订单数: {}, orderNos(sample)={} " ,
TENANT_ID ,
orders . size ( ) ,
orders . stream ( ) . limit ( 10 ) . map ( ShopOrder : : getOrderNo ) . toList ( ) ) ;
// 缓存:减少同一批次内重复查角色
Map < Integer , Boolean > shopRoleCache = new HashMap < > ( ) ;
@@ -126,27 +136,37 @@ public class DealerOrderSettlement10584Task {
throw new IllegalStateException ( " 订单金额为空或<=0, 无法结算 - orderId= " + order . getOrderId ( ) + " , orderNo= " + order . getOrderNo ( ) ) ;
}
log . info ( " 开始结算订单 - orderId={}, orderNo={}, buyerUserId={}, payPrice={} " ,
order . getOrderId ( ) , order . getOrderNo ( ) , order . getUserId ( ) , baseAmount ) ;
// 1) 直推/简推( shop_dealer_referee)
settleDealerRefereeCommission ( order , baseAmount ) ;
DealerRefereeCommission dealerRefereeCommission = settleDealerRefereeCommission( order , baseAmount ) ;
// 2) 角色为shop的推荐人( shop_dealer_referee 链路向上查找 role=shop 的上级)
settleShopRoleRefereeCommission ( order , baseAmount , shopRoleCache ) ;
ShopRoleCommission shopRoleCommission = settleShopRoleRefereeCommission( order , baseAmount , shopRoleCache ) ;
// 3) 写入分销订单记录(用于排查/统计;详细分佣以 ShopDealerCapital 为准)
createDealerOrderRecord ( order , baseAmount , dealerRefereeCommission , shopRoleCommission ) ;
log . info ( " 订单结算完成 - orderId={}, orderNo={}, baseAmount={} " , order . getOrderId ( ) , order . getOrderNo ( ) , baseAmount ) ;
}
private void settleDealerRefereeCommission ( ShopOrder order , BigDecimal baseAmount ) {
private DealerRefereeCommission settleDealerRefereeCommission ( ShopOrder order , BigDecimal baseAmount ) {
// level=2 可能不可靠:按“查两次”方式获取简推(直推的上级)。
Integer directDealerId = getDealerRefereeId ( order . getUserId ( ) ) ;
Integer simpleDealerId = directDealerId ! = null ? getDealerRefereeId ( directDealerId ) : null ;
BigDecimal directMoney = calcMoney ( baseAmount , RATE_0_10 ) ;
BigDecimal simpleMoney = calcMoney ( baseAmount , RATE_0_10 ) ;
BigDecimal directMoney = directDealerId ! = null ? calcMoney( baseAmount , RATE_0_10 ) : BigDecimal . ZERO ;
boolean samePerson = directDealerId ! = null & & directDealerId . equals ( simpleDealerId ) ;
BigDecimal simpleMoney = ( simpleDealerId ! = null & & ! samePerson ) ? calcMoney ( baseAmount , RATE_0_10 ) : BigDecimal . ZERO ;
log . info ( " 分销直推/简推查询结果 - orderNo={}, buyerUserId={}, directDealerId={}, directMoney={}, simpleDealerId={}, simpleMoney={} " ,
order . getOrderNo ( ) , order . getUserId ( ) , directDealerId , directMoney , simpleDealerId , simpleMoney ) ;
creditDealerCommission ( directDealerId , directMoney , order , " 直推佣金(10%) " ) ;
if ( simpleDealerId ! = null & & ! simpleDealerId . equals ( directDealerId ) ) {
creditDealerCommission ( simpleDealerId , simpleMoney , order , " 简推佣金(10%) " ) ;
}
creditDealerCommission ( simpleDealerId , simpleMoney , order , " 简推佣金(10%) " ) ;
return new DealerRefereeCommission ( directDealerId , directMoney , simpleDealerId , simpleMoney ) ;
}
private Integer getDealerRefereeId ( Integer userId ) {
@@ -161,23 +181,34 @@ public class DealerOrderSettlement10584Task {
. orderByDesc ( ShopDealerReferee : : getId )
. last ( " limit 1 " )
) ;
log . debug ( " shop_dealer_referee(level=1) 查询 - tenantId={}, userId={}, dealerId={} " ,
TENANT_ID , userId , rel ! = null ? rel . getDealerId ( ) : null ) ;
return rel ! = null ? rel . getDealerId ( ) : null ;
}
private void settleShopRoleRefereeCommission ( ShopOrder order , BigDecimal baseAmount , Map < Integer , Boolean > shopRoleCache ) {
private ShopRoleCommission settleShopRoleRefereeCommission ( ShopOrder order , BigDecimal baseAmount , Map < Integer , Boolean > shopRoleCache ) {
List < Integer > shopRoleReferees = findFirstTwoShopRoleRefereesByDealerReferee ( order . getUserId ( ) , shopRoleCache ) ;
log . info ( " 门店(角色shop)上级链路结果 - orderNo={}, buyerUserId={}, shopRoleReferees={} " ,
order . getOrderNo ( ) , order . getUserId ( ) , shopRoleReferees ) ;
if ( shopRoleReferees . isEmpty ( ) ) {
return ;
return ShopRoleCommission . empty ( ) ;
}
if ( shopRoleReferees . size ( ) = = 1 ) {
creditDealerCommission ( shopRoleReferees . get ( 0 ) , calcMoney ( baseAmount , RATE_0_10 ) , order , " shop角色推荐人佣金(仅1人, 10%) " ) ;
return ;
BigDecimal money = calcMoney ( baseAmount , RATE_0_10 ) ;
log . info ( " 门店直推/简推发放(仅1人) - orderNo={}, storeDirectUserId={}, money={} " , order . getOrderNo ( ) , shopRoleReferees . get ( 0 ) , money ) ;
creditDealerCommission ( shopRoleReferees . get ( 0 ) , money , order , " 门店直推佣金(角色shop, 仅1人, 10%) " ) ;
return new ShopRoleCommission ( shopRoleReferees . get ( 0 ) , money , null , BigDecimal . ZERO ) ;
}
// 两个或以上: 第一个0.02, 第二个0.08
creditDealerCommission ( shopRoleReferees . get ( 0 ) , calcMoney ( baseAmount , RATE_0_02 ) , order , " shop角色推荐人佣金(第1个, 2%) " ) ;
creditDealerCommission ( shopRoleReferees . get ( 1 ) , calcMoney ( baseAmount , RATE_0_08 ) , order , " shop角色推荐人佣金(第2个, 8%) " ) ;
BigDecimal storeDirectMoney = calcMoney ( baseAmount , RATE_0_02 ) ;
BigDecimal storeSimpleMoney = calcMoney ( baseAmount , RATE_0_08 ) ;
log . info ( " 门店直推/门店简推发放 - orderNo={}, storeDirectUserId={}, storeDirectMoney={}, storeSimpleUserId={}, storeSimpleMoney={} " ,
order . getOrderNo ( ) , shopRoleReferees . get ( 0 ) , storeDirectMoney , shopRoleReferees . get ( 1 ) , storeSimpleMoney ) ;
creditDealerCommission ( shopRoleReferees . get ( 0 ) , storeDirectMoney , order , " 门店直推佣金(角色shop, 第1个, 2%) " ) ;
creditDealerCommission ( shopRoleReferees . get ( 1 ) , storeSimpleMoney , order , " 门店简推佣金(角色shop, 第2个, 8%) " ) ;
return new ShopRoleCommission ( shopRoleReferees . get ( 0 ) , storeDirectMoney , shopRoleReferees . get ( 1 ) , storeSimpleMoney ) ;
}
private List < Integer > findFirstTwoShopRoleRefereesByDealerReferee ( Integer buyerUserId , Map < Integer , Boolean > shopRoleCache ) {
@@ -195,11 +226,14 @@ public class DealerOrderSettlement10584Task {
break ;
}
log . debug ( " 门店(角色shop)链路向上 - buyerOrChildUserId={}, parentId={} " , current , parentId ) ;
if ( ! visited . add ( parentId ) ) {
break ;
}
if ( hasShopRole ( parentId , shopRoleCache ) ) {
log . debug ( " 门店(角色shop)命中 - parentId={} " , parentId ) ;
result . add ( parentId ) ;
if ( result . size ( ) > = 2 ) {
break ;
@@ -220,6 +254,10 @@ public class DealerOrderSettlement10584Task {
List < Role > roles = userRoleService . listByUserId ( userId ) ;
boolean isShop = roles ! = null & & roles . stream ( ) . anyMatch ( r - > " shop " . equalsIgnoreCase ( r . getRoleCode ( ) ) ) ;
log . debug ( " 角色判定 - userId={}, roles={}, isShop={} " ,
userId ,
roles = = null ? null : roles . stream ( ) . map ( Role : : getRoleCode ) . toList ( ) ,
isShop ) ;
shopRoleCache . put ( userId , isShop ) ;
return isShop ;
}
@@ -229,6 +267,8 @@ public class DealerOrderSettlement10584Task {
return ;
}
log . info ( " 佣金入账 - orderNo={}, toDealerUserId={}, money={}, comments={} " , order . getOrderNo ( ) , dealerUserId , money , comments ) ;
// 先累加佣金到分销商账户( 避免并发下丢失更新, 用SQL自增)
boolean updated = shopDealerUserService . update (
new LambdaUpdateWrapper < ShopDealerUser > ( )
@@ -255,6 +295,57 @@ public class DealerOrderSettlement10584Task {
shopDealerCapitalService . save ( cap ) ;
}
private void createDealerOrderRecord (
ShopOrder order ,
BigDecimal baseAmount ,
DealerRefereeCommission dealerRefereeCommission ,
ShopRoleCommission shopRoleCommission
) {
// 幂等:同一订单只写一条(依赖 order_no + tenant_id 作为业务唯一)
boolean exists = shopDealerOrderService . count (
new LambdaQueryWrapper < ShopDealerOrder > ( )
. eq ( ShopDealerOrder : : getTenantId , TENANT_ID )
. eq ( ShopDealerOrder : : getOrderNo , order . getOrderNo ( ) )
) > 0 ;
if ( exists ) {
log . info ( " ShopDealerOrder已存在, 跳过写入 - orderNo={} " , order . getOrderNo ( ) ) ;
return ;
}
ShopDealerOrder dealerOrder = new ShopDealerOrder ( ) ;
dealerOrder . setUserId ( order . getUserId ( ) ) ; // 买家用户ID
dealerOrder . setOrderNo ( order . getOrderNo ( ) ) ;
dealerOrder . setOrderPrice ( baseAmount ) ;
dealerOrder . setPayPrice ( baseAmount ) ;
dealerOrder . setFirstUserId ( dealerRefereeCommission . directDealerId ) ;
dealerOrder . setFirstMoney ( dealerRefereeCommission . directMoney ) ;
dealerOrder . setSecondUserId ( dealerRefereeCommission . simpleDealerId ) ;
dealerOrder . setSecondMoney ( dealerRefereeCommission . simpleMoney ) ;
// 表结构只有三级,门店(角色shop)两级放入 third + comments( 详细以 capital 为准)
dealerOrder . setThirdUserId ( shopRoleCommission . storeDirectUserId ) ;
dealerOrder . setThirdMoney ( shopRoleCommission . storeDirectMoney ) ;
dealerOrder . setIsSettled ( 1 ) ;
dealerOrder . setSettleTime ( java . time . LocalDateTime . now ( ) ) ;
dealerOrder . setTenantId ( TENANT_ID ) ;
dealerOrder . setComments ( buildCommissionTraceComment ( dealerRefereeCommission , shopRoleCommission ) ) ;
shopDealerOrderService . save ( dealerOrder ) ;
log . info ( " 写入ShopDealerOrder完成 - orderNo={}, firstUserId={}, secondUserId={}, thirdUserId={} " ,
order . getOrderNo ( ) , dealerOrder . getFirstUserId ( ) , dealerOrder . getSecondUserId ( ) , dealerOrder . getThirdUserId ( ) ) ;
}
private String buildCommissionTraceComment ( DealerRefereeCommission dealerRefereeCommission , ShopRoleCommission shopRoleCommission ) {
// 轻量“过程”留痕,方便排查;详细分佣以 ShopDealerCapital 为准。
return " direct= " + dealerRefereeCommission . directDealerId + " : " + dealerRefereeCommission . directMoney
+ " ,simple= " + dealerRefereeCommission . simpleDealerId + " : " + dealerRefereeCommission . simpleMoney
+ " ,storeDirect= " + shopRoleCommission . storeDirectUserId + " : " + shopRoleCommission . storeDirectMoney
+ " ,storeSimple= " + shopRoleCommission . storeSimpleUserId + " : " + shopRoleCommission . storeSimpleMoney ;
}
private BigDecimal getOrderBaseAmount ( ShopOrder order ) {
if ( order = = null ) {
return null ;
@@ -268,4 +359,36 @@ public class DealerOrderSettlement10584Task {
}
return base . multiply ( rate ) . setScale ( 2 , RoundingMode . HALF_UP ) ;
}
private static class DealerRefereeCommission {
private final Integer directDealerId ;
private final BigDecimal directMoney ;
private final Integer simpleDealerId ;
private final BigDecimal simpleMoney ;
private DealerRefereeCommission ( 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 final Integer storeDirectUserId ;
private final BigDecimal storeDirectMoney ;
private final Integer storeSimpleUserId ;
private final BigDecimal storeSimpleMoney ;
private static ShopRoleCommission empty ( ) {
return new ShopRoleCommission ( null , BigDecimal . ZERO , null , BigDecimal . ZERO ) ;
}
private ShopRoleCommission ( Integer storeDirectUserId , BigDecimal storeDirectMoney , Integer storeSimpleUserId , BigDecimal storeSimpleMoney ) {
this . storeDirectUserId = storeDirectUserId ;
this . storeDirectMoney = storeDirectMoney ! = null ? storeDirectMoney : BigDecimal . ZERO ;
this . storeSimpleUserId = storeSimpleUserId ;
this . storeSimpleMoney = storeSimpleMoney ! = null ? storeSimpleMoney : BigDecimal . ZERO ;
}
}
}