1.优化分红方式

This commit is contained in:
2026-05-29 12:01:00 +08:00
parent f286fcc56f
commit d8673fb2c5
13 changed files with 457 additions and 60 deletions

View File

@@ -81,6 +81,57 @@ class AdminCommissionDistributionService
return ['used_rate' => $used, 'remaining_rate' => $remaining];
}
/**
* 同渠道下顶级代理(无上级)已占用的渠道分红比例
*
* @return array{used_rate:string,remaining_rate:string}
*/
public static function getChannelRootShareRemainder(int $channelId, ?int $excludeAdminId = null): array
{
$used = '0.00';
if ($channelId <= 0) {
return ['used_rate' => $used, 'remaining_rate' => '100.00'];
}
$query = Db::name('admin')
->where('channel_id', $channelId)
->where('status', 'enable')
->whereRaw('(parent_admin_id IS NULL OR parent_admin_id = 0)');
if ($excludeAdminId !== null && $excludeAdminId > 0) {
$query->where('id', '<>', $excludeAdminId);
}
$rows = $query->column('commission_share_rate');
foreach ($rows as $rate) {
if ($rate === null || $rate === '') {
continue;
}
$used = bcadd($used, bcadd(strval($rate), '0', 2), 2);
}
$remaining = bcsub('100.00', $used, 2);
if (bccomp($remaining, '0', 2) < 0) {
$remaining = '0.00';
}
return ['used_rate' => $used, 'remaining_rate' => $remaining];
}
public static function validateChannelRootCommissionShareRate(int $channelId, mixed $rateRaw, ?int $excludeAdminId = null): ?string
{
if ($channelId <= 0) {
return (string) __('Channel is required for top-level agent commission share');
}
if ($rateRaw === null || $rateRaw === '') {
return (string) __('Top-level agent commission share rate is required');
}
$rate = bcadd(strval($rateRaw), '0', 2);
if (bccomp($rate, '0', 2) <= 0 || bccomp($rate, '100', 2) > 0) {
return (string) __('Commission share rate must be between 0 and 100');
}
$remainder = self::getChannelRootShareRemainder($channelId, $excludeAdminId);
if (bccomp(bcadd($remainder['used_rate'], $rate, 2), '100.00', 2) > 0) {
return (string) __('Sum of channel top-level commission share rates cannot exceed 100%');
}
return null;
}
public static function validateCommissionShareRate(?int $parentAdminId, mixed $rateRaw, ?int $excludeAdminId = null): ?string
{
if ($parentAdminId === null || $parentAdminId <= 0) {
@@ -110,35 +161,66 @@ class AdminCommissionDistributionService
if ($channelId <= 0 || bccomp($totalCommission, '0', 2) <= 0) {
return [];
}
$roots = Db::name('admin')
$rootRows = Db::name('admin')
->where('channel_id', $channelId)
->where('status', 'enable')
->whereRaw('(parent_admin_id IS NULL OR parent_admin_id = 0)')
->order('id', 'asc')
->column('id');
if ($roots === []) {
->field(['id', 'commission_share_rate'])
->select()
->toArray();
if ($rootRows === []) {
return [];
}
$rootCount = count($roots);
$perRoot = bcdiv($totalCommission, strval($rootCount), 2);
$assigned = '0.00';
$useRateSplit = true;
foreach ($rootRows as $rootRow) {
$rate = bcadd(strval($rootRow['commission_share_rate'] ?? '0'), '0', 2);
if (bccomp($rate, '0', 2) <= 0) {
$useRateSplit = false;
break;
}
}
$merged = [];
foreach ($roots as $index => $rootId) {
$rootId = intval($rootId);
if ($rootId <= 0) {
continue;
}
$isLast = $index === $rootCount - 1;
$rootAmount = $isLast ? bcsub($totalCommission, $assigned, 2) : $perRoot;
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';
if ($useRateSplit) {
foreach ($rootRows as $rootRow) {
$rootId = intval($rootRow['id'] ?? 0);
if ($rootId <= 0) {
continue;
}
$rate = bcadd(strval($rootRow['commission_share_rate'] ?? '0'), '0', 2);
$rootAmount = bcmul($totalCommission, bcdiv($rate, '100', 4), 2);
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);
}
}
} else {
$rootCount = count($rootRows);
$perRoot = bcdiv($totalCommission, strval($rootCount), 2);
$assigned = '0.00';
foreach ($rootRows as $index => $rootRow) {
$rootId = intval($rootRow['id'] ?? 0);
if ($rootId <= 0) {
continue;
}
$isLast = $index === $rootCount - 1;
$rootAmount = $isLast ? bcsub($totalCommission, $assigned, 2) : $perRoot;
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);
}
$merged[$adminId] = bcadd($merged[$adminId], $amount, 2);
}
}
$out = [];