1.优化充值跳转链接的问题
2.优化后台渠道管理页面的显示样式
This commit is contained in:
@@ -152,11 +152,154 @@ class AdminCommissionDistributionService
|
||||
}
|
||||
|
||||
/**
|
||||
* 将渠道本期总佣金按管理员树分配,返回各管理员实得金额
|
||||
*
|
||||
* @return array<int, array{admin_id:int,commission_amount:string,commission_rate:string,calc_base_amount:string}>
|
||||
* 代理费前佣金占渠道本期总佣金的比例(%)
|
||||
*/
|
||||
public static function distributeChannelCommission(int $channelId, string $totalCommission, string $calcBaseAmount): array
|
||||
public static function calcCommissionSharePercent(string $gross, string $totalCommission): string
|
||||
{
|
||||
if (bccomp($totalCommission, '0', 2) <= 0 || bccomp($gross, '0', 2) <= 0) {
|
||||
return '0.00';
|
||||
}
|
||||
return bcdiv(bcmul($gross, '100', 4), $totalCommission, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按百分比计算手续费金额:手续费 = 费前佣金 × (费率% / 100)
|
||||
*/
|
||||
public static function calcHandlingFeeAmount(string $gross, string $ratePercent): string
|
||||
{
|
||||
$rate = bcadd($ratePercent, '0', 2);
|
||||
if (bccomp($gross, '0', 2) <= 0 || bccomp($rate, '0', 2) <= 0) {
|
||||
return '0.00';
|
||||
}
|
||||
if (bccomp($rate, '100', 2) > 0) {
|
||||
$rate = '100.00';
|
||||
}
|
||||
return bcmul($gross, bcdiv($rate, '100', 4), 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将渠道本期总佣金按管理员树分配,返回各管理员实得金额(费前)
|
||||
*
|
||||
* @param array<int, string>|null $handlingFeeRateByAdmin admin_id => 手续费比例(%)
|
||||
* @return array<int, array{admin_id:int,commission_amount:string,commission_rate:string,calc_base_amount:string,handling_fee_rate:string,handling_fee:string,net_commission_amount:string}>
|
||||
*/
|
||||
public static function distributeChannelCommission(
|
||||
int $channelId,
|
||||
string $totalCommission,
|
||||
string $calcBaseAmount,
|
||||
string $defaultHandlingFeeRate = '0.00',
|
||||
?array $handlingFeeRateByAdmin = null
|
||||
): array {
|
||||
$nodes = self::collectHierarchicalNodes($channelId, $totalCommission);
|
||||
if ($nodes === []) {
|
||||
return [];
|
||||
}
|
||||
$defaultRate = self::normalizeHandlingFeeRatePercent($defaultHandlingFeeRate);
|
||||
$merged = [];
|
||||
foreach ($nodes as $node) {
|
||||
$adminId = intval($node['admin_id'] ?? 0);
|
||||
if ($adminId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$gross = strval($node['commission_amount'] ?? '0.00');
|
||||
if (bccomp($gross, '0', 2) <= 0) {
|
||||
continue;
|
||||
}
|
||||
$settlementBase = strval($node['settlement_base_amount'] ?? '0.00');
|
||||
$feeRate = $defaultRate;
|
||||
if ($handlingFeeRateByAdmin !== null && isset($handlingFeeRateByAdmin[$adminId])) {
|
||||
$feeRate = self::normalizeHandlingFeeRatePercent(strval($handlingFeeRateByAdmin[$adminId]));
|
||||
}
|
||||
$feeAmount = self::calcHandlingFeeAmount($gross, $feeRate);
|
||||
$net = bcsub($gross, $feeAmount, 2);
|
||||
if (bccomp($net, '0', 2) < 0) {
|
||||
$net = '0.00';
|
||||
}
|
||||
$effectiveRate = bccomp($settlementBase, '0', 2) <= 0
|
||||
? '0.0000'
|
||||
: bcdiv($gross, $settlementBase, 6);
|
||||
$merged[$adminId] = [
|
||||
'admin_id' => $adminId,
|
||||
'commission_amount' => $gross,
|
||||
'commission_rate' => $effectiveRate,
|
||||
'calc_base_amount' => $settlementBase,
|
||||
'commission_share_percent' => self::calcCommissionSharePercent($gross, $totalCommission),
|
||||
'handling_fee_rate' => $feeRate,
|
||||
'handling_fee' => $feeAmount,
|
||||
'net_commission_amount' => $net,
|
||||
];
|
||||
}
|
||||
return array_values($merged);
|
||||
}
|
||||
|
||||
/**
|
||||
* 层级分配预览(先序遍历),含结算基数与手续费
|
||||
*
|
||||
* @param array<int, string>|null $handlingFeeRateByAdmin admin_id => 手续费比例(%)
|
||||
* @return array<int, array<string, mixed>>
|
||||
*/
|
||||
public static function buildSplitPreview(
|
||||
int $channelId,
|
||||
string $commissionTotal,
|
||||
string $calcBaseAmount,
|
||||
string $defaultHandlingFeeRate = '0.00',
|
||||
?array $handlingFeeRateByAdmin = null
|
||||
): array {
|
||||
unset($calcBaseAmount);
|
||||
$nodes = self::collectHierarchicalNodes($channelId, $commissionTotal);
|
||||
if ($nodes === []) {
|
||||
return [];
|
||||
}
|
||||
$defaultRate = self::normalizeHandlingFeeRatePercent($defaultHandlingFeeRate);
|
||||
$out = [];
|
||||
foreach ($nodes as $node) {
|
||||
$adminId = intval($node['admin_id'] ?? 0);
|
||||
if ($adminId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$gross = strval($node['commission_amount'] ?? '0.00');
|
||||
$feeRate = $defaultRate;
|
||||
if ($handlingFeeRateByAdmin !== null && isset($handlingFeeRateByAdmin[$adminId])) {
|
||||
$feeRate = self::normalizeHandlingFeeRatePercent(strval($handlingFeeRateByAdmin[$adminId]));
|
||||
}
|
||||
$feeAmount = self::calcHandlingFeeAmount($gross, $feeRate);
|
||||
$net = bcsub($gross, $feeAmount, 2);
|
||||
if (bccomp($net, '0', 2) < 0) {
|
||||
$net = '0.00';
|
||||
}
|
||||
$out[] = [
|
||||
'admin_id' => $adminId,
|
||||
'admin_username' => strval($node['admin_username'] ?? ('#' . $adminId)),
|
||||
'parent_admin_id' => intval($node['parent_admin_id'] ?? 0),
|
||||
'level' => intval($node['level'] ?? 0),
|
||||
'settlement_base_amount' => strval($node['settlement_base_amount'] ?? '0.00'),
|
||||
'share_rate' => strval($node['share_rate'] ?? '0.00'),
|
||||
'commission_amount' => $gross,
|
||||
'commission_share_percent' => self::calcCommissionSharePercent($gross, $commissionTotal),
|
||||
'handling_fee_rate' => $feeRate,
|
||||
'handling_fee' => $feeAmount,
|
||||
'net_commission_amount' => $net,
|
||||
];
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
private static function normalizeHandlingFeeRatePercent(string $rateRaw): string
|
||||
{
|
||||
$rate = bcadd($rateRaw, '0', 2);
|
||||
if (bccomp($rate, '0', 2) < 0) {
|
||||
return '0.00';
|
||||
}
|
||||
if (bccomp($rate, '100', 2) > 0) {
|
||||
return '100.00';
|
||||
}
|
||||
return $rate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{admin_id:int,admin_username:string,parent_admin_id:int,level:int,settlement_base_amount:string,share_rate:string,commission_amount:string}>
|
||||
*/
|
||||
private static function collectHierarchicalNodes(int $channelId, string $totalCommission): array
|
||||
{
|
||||
if ($channelId <= 0 || bccomp($totalCommission, '0', 2) <= 0) {
|
||||
return [];
|
||||
@@ -166,7 +309,7 @@ class AdminCommissionDistributionService
|
||||
->where('status', 'enable')
|
||||
->whereRaw('(parent_admin_id IS NULL OR parent_admin_id = 0)')
|
||||
->order('id', 'asc')
|
||||
->field(['id', 'commission_share_rate'])
|
||||
->field(['id', 'commission_share_rate', 'username'])
|
||||
->select()
|
||||
->toArray();
|
||||
if ($rootRows === []) {
|
||||
@@ -180,7 +323,7 @@ class AdminCommissionDistributionService
|
||||
break;
|
||||
}
|
||||
}
|
||||
$merged = [];
|
||||
$nodes = [];
|
||||
if ($useRateSplit) {
|
||||
foreach ($rootRows as $rootRow) {
|
||||
$rootId = intval($rootRow['id'] ?? 0);
|
||||
@@ -192,13 +335,7 @@ class AdminCommissionDistributionService
|
||||
if (bccomp($rootAmount, '0', 2) <= 0) {
|
||||
continue;
|
||||
}
|
||||
$parts = self::distributeFromAdmin($rootId, $rootAmount, $calcBaseAmount);
|
||||
foreach ($parts as $adminId => $amount) {
|
||||
if (!isset($merged[$adminId])) {
|
||||
$merged[$adminId] = '0.00';
|
||||
}
|
||||
$merged[$adminId] = bcadd($merged[$adminId], $amount, 2);
|
||||
}
|
||||
self::appendNodeTree($rootId, $rootAmount, 0, 0, $rate, $nodes);
|
||||
}
|
||||
} else {
|
||||
$rootCount = count($rootRows);
|
||||
@@ -214,31 +351,74 @@ class AdminCommissionDistributionService
|
||||
if (!$isLast) {
|
||||
$assigned = bcadd($assigned, $rootAmount, 2);
|
||||
}
|
||||
$parts = self::distributeFromAdmin($rootId, $rootAmount, $calcBaseAmount);
|
||||
foreach ($parts as $adminId => $amount) {
|
||||
if (!isset($merged[$adminId])) {
|
||||
$merged[$adminId] = '0.00';
|
||||
}
|
||||
$merged[$adminId] = bcadd($merged[$adminId], $amount, 2);
|
||||
if (bccomp($rootAmount, '0', 2) <= 0) {
|
||||
continue;
|
||||
}
|
||||
self::appendNodeTree($rootId, $rootAmount, 0, 0, '100.00', $nodes);
|
||||
}
|
||||
}
|
||||
$out = [];
|
||||
foreach ($merged as $adminId => $amount) {
|
||||
if (bccomp($amount, '0', 2) <= 0) {
|
||||
return $nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<int, array{admin_id:int,admin_username:string,parent_admin_id:int,level:int,settlement_base_amount:string,share_rate:string,commission_amount:string}> $nodes
|
||||
*/
|
||||
private static function appendNodeTree(
|
||||
int $adminId,
|
||||
string $incomingAmount,
|
||||
int $level,
|
||||
int $parentAdminId,
|
||||
string $shareRateFromParent,
|
||||
array &$nodes
|
||||
): void {
|
||||
if ($adminId <= 0 || bccomp($incomingAmount, '0', 2) <= 0) {
|
||||
return;
|
||||
}
|
||||
$adminRow = Db::name('admin')
|
||||
->where('id', $adminId)
|
||||
->field(['id', 'username', 'commission_share_rate'])
|
||||
->find();
|
||||
if (!is_array($adminRow)) {
|
||||
return;
|
||||
}
|
||||
$children = Db::name('admin')
|
||||
->where('parent_admin_id', $adminId)
|
||||
->where('status', 'enable')
|
||||
->order('id', 'asc')
|
||||
->field(['id', 'commission_share_rate'])
|
||||
->select()
|
||||
->toArray();
|
||||
$givenToChildren = '0.00';
|
||||
$childPlans = [];
|
||||
foreach ($children as $child) {
|
||||
$childId = intval($child['id'] ?? 0);
|
||||
if ($childId <= 0) {
|
||||
continue;
|
||||
}
|
||||
$effectiveRate = bccomp($calcBaseAmount, '0', 2) <= 0
|
||||
? '0.0000'
|
||||
: bcdiv($amount, $calcBaseAmount, 6);
|
||||
$out[] = [
|
||||
'admin_id' => intval($adminId),
|
||||
'commission_amount' => $amount,
|
||||
'commission_rate' => $effectiveRate,
|
||||
'calc_base_amount' => $calcBaseAmount,
|
||||
];
|
||||
$rate = bcadd(strval($child['commission_share_rate'] ?? '0'), '0', 2);
|
||||
if (bccomp($rate, '0', 2) <= 0) {
|
||||
continue;
|
||||
}
|
||||
$childAmount = bcmul($incomingAmount, bcdiv($rate, '100', 4), 2);
|
||||
if (bccomp($childAmount, '0', 2) <= 0) {
|
||||
continue;
|
||||
}
|
||||
$givenToChildren = bcadd($givenToChildren, $childAmount, 2);
|
||||
$childPlans[] = ['id' => $childId, 'amount' => $childAmount, 'rate' => $rate];
|
||||
}
|
||||
$selfKeep = bcsub($incomingAmount, $givenToChildren, 2);
|
||||
$nodes[] = [
|
||||
'admin_id' => $adminId,
|
||||
'admin_username' => strval($adminRow['username'] ?? ('#' . $adminId)),
|
||||
'parent_admin_id' => $parentAdminId,
|
||||
'level' => $level,
|
||||
'settlement_base_amount' => $incomingAmount,
|
||||
'share_rate' => $shareRateFromParent,
|
||||
'commission_amount' => bccomp($selfKeep, '0', 2) > 0 ? $selfKeep : '0.00',
|
||||
];
|
||||
foreach ($childPlans as $plan) {
|
||||
self::appendNodeTree(intval($plan['id']), strval($plan['amount']), $level + 1, $adminId, strval($plan['rate']), $nodes);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,6 +426,7 @@ class AdminCommissionDistributionService
|
||||
*/
|
||||
private static function distributeFromAdmin(int $adminId, string $amount, string $calcBaseAmount): array
|
||||
{
|
||||
unset($calcBaseAmount);
|
||||
if ($adminId <= 0 || bccomp($amount, '0', 2) <= 0) {
|
||||
return [];
|
||||
}
|
||||
@@ -272,7 +453,7 @@ class AdminCommissionDistributionService
|
||||
continue;
|
||||
}
|
||||
$givenToChildren = bcadd($givenToChildren, $childAmount, 2);
|
||||
$childParts = self::distributeFromAdmin($childId, $childAmount, $calcBaseAmount);
|
||||
$childParts = self::distributeFromAdmin($childId, $childAmount, '0.00');
|
||||
foreach ($childParts as $aid => $part) {
|
||||
if (!isset($result[$aid])) {
|
||||
$result[$aid] = '0.00';
|
||||
@@ -289,32 +470,4 @@ class AdminCommissionDistributionService
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{admin_id:int,admin_username:string,share_rate:string,commission_amount:string}>
|
||||
*/
|
||||
public static function buildSplitPreview(int $channelId, string $commissionTotal, string $calcBaseAmount): array
|
||||
{
|
||||
$rows = self::distributeChannelCommission($channelId, $commissionTotal, $calcBaseAmount);
|
||||
if ($rows === []) {
|
||||
return [];
|
||||
}
|
||||
$adminIds = array_map(static fn(array $r): int => intval($r['admin_id']), $rows);
|
||||
$adminNames = Db::name('admin')->where('id', 'in', $adminIds)->column('username', 'id');
|
||||
$parentMap = Db::name('admin')->where('id', 'in', $adminIds)->column('parent_admin_id', 'id');
|
||||
$shareRates = Db::name('admin')->where('id', 'in', $adminIds)->column('commission_share_rate', 'id');
|
||||
$out = [];
|
||||
foreach ($rows as $row) {
|
||||
$aid = intval($row['admin_id']);
|
||||
$parentId = intval($parentMap[$aid] ?? 0);
|
||||
$shareRate = $parentId > 0 ? bcadd(strval($shareRates[$aid] ?? '0'), '0', 2) : '100.00';
|
||||
$out[] = [
|
||||
'admin_id' => $aid,
|
||||
'admin_username' => strval($adminNames[$aid] ?? ('#' . $aid)),
|
||||
'share_rate' => $shareRate,
|
||||
'commission_amount' => strval($row['commission_amount']),
|
||||
];
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user