1.优化分红方式

This commit is contained in:
2026-05-29 11:06:24 +08:00
parent eba80b1bf4
commit f3677eb0e3
15 changed files with 982 additions and 487 deletions

View File

@@ -23,9 +23,13 @@ class ChannelSettlementService
if (Db::name('agent_settlement_period')->where('settlement_no', $settlementNo)->value('id')) {
return ['ok' => false, 'msg' => __('Settlement number conflict, please retry')];
}
$shareRows = self::resolveCommissionSharesForChannel($channelId);
if ($shareRows === []) {
return ['ok' => false, 'msg' => __('No available admin share ratios under this channel; cannot settle')];
$distributions = AdminCommissionDistributionService::distributeChannelCommission(
$channelId,
strval($payload['commission_amount']),
strval($payload['calc_base_amount'])
);
if ($distributions === []) {
return ['ok' => false, 'msg' => __('No channel root agent configured for commission distribution')];
}
$now = time();
Db::startTrans();
@@ -42,12 +46,10 @@ class ChannelSettlementService
'create_time' => $now,
'update_time' => $now,
]));
$rows = self::buildCommissionRowsForSplit(
$shareRows,
$rows = self::buildCommissionRowsFromDistribution(
$distributions,
$channelId,
$periodId,
strval($payload['calc_base_amount']),
strval($payload['commission_amount']),
$remark !== '' ? $remark : '渠道待分红记录',
$now
);
@@ -189,7 +191,11 @@ class ChannelSettlementService
'calc_base_amount' => $commission['calc_base_amount'],
'commission_amount' => $commission['commission_amount'],
'agent_mode' => $mode,
'commission_split' => self::buildCommissionSplitPreview(self::resolveCommissionSharesForChannel($channelId), $commission['commission_amount']),
'commission_split' => AdminCommissionDistributionService::buildSplitPreview(
$channelId,
$commission['commission_amount'],
$commission['calc_base_amount']
),
];
}
@@ -325,93 +331,33 @@ class ChannelSettlementService
return $base . strtoupper(substr(bin2hex(random_bytes(4)), 0, 2));
}
private static function resolveCommissionSharesForChannel(int $channelId): array
/**
* @param array<int, array{admin_id:int,commission_amount:string,commission_rate:string,calc_base_amount:string}> $distributions
*/
private static function buildCommissionRowsFromDistribution(array $distributions, int $channelId, int $periodId, string $remark, int $now): array
{
$rows = Db::name('channel_admin_share')->alias('cas')
->join('admin a', 'cas.admin_id = a.id')
->field(['cas.admin_id', 'cas.share_rate'])
->where('cas.channel_id', $channelId)
->where('cas.status', 1)
->where('a.status', 'enable')
->order('cas.admin_id', 'asc')
->select()
->toArray();
if ($rows === []) {
return [];
}
$sum = '0.00';
$out = [];
foreach ($rows as $row) {
$adminId = intval($row['admin_id'] ?? 0);
$shareRate = bcadd(strval($row['share_rate'] ?? '0'), '0', 2);
if ($adminId <= 0 || bccomp($shareRate, '0', 2) <= 0) {
$rows = [];
foreach ($distributions as $dist) {
$adminId = intval($dist['admin_id'] ?? 0);
if ($adminId <= 0) {
continue;
}
$sum = bcadd($sum, $shareRate, 2);
$out[] = ['admin_id' => $adminId, 'share_rate' => $shareRate];
}
if ($out === [] || bccomp($sum, '100.00', 2) !== 0) {
return [];
}
return $out;
}
private static function buildCommissionRowsForSplit(array $shareRows, int $channelId, int $periodId, string $calcBaseAmount, string $commissionTotal, string $remark, int $now): array
{
$sum = '0.00';
$rows = [];
$lastIndex = count($shareRows) - 1;
foreach ($shareRows as $index => $shareRow) {
$shareRate = bcadd(strval($shareRow['share_rate'] ?? '0.00'), '0', 2);
$shareDec = bcdiv($shareRate, '100', 4);
$amount = $index === $lastIndex ? bcsub($commissionTotal, $sum, 2) : bcmul($commissionTotal, $shareDec, 2);
if ($index !== $lastIndex) {
$sum = bcadd($sum, $amount, 2);
}
$effectiveRate = bccomp($calcBaseAmount, '0', 2) <= 0 ? '0.0000' : bcdiv($amount, $calcBaseAmount, 6);
$amount = strval($dist['commission_amount'] ?? '0.00');
$rows[] = [
'settlement_period_id' => $periodId,
'channel_id' => $channelId,
'admin_id' => intval($shareRow['admin_id'] ?? 0),
'commission_rate' => $effectiveRate,
'calc_base_amount' => $calcBaseAmount,
'admin_id' => $adminId,
'commission_rate' => strval($dist['commission_rate'] ?? '0.0000'),
'calc_base_amount' => strval($dist['calc_base_amount'] ?? '0.00'),
'commission_amount' => $amount,
'status' => 0,
'settled_at' => null,
'remark' => $remark . ' | 分配比例=' . $shareRate . '%',
'remark' => $remark . ' | 树形分红实发',
'create_time' => $now,
'update_time' => $now,
];
}
return $rows;
}
private static function buildCommissionSplitPreview(array $shareRows, string $commissionTotal): array
{
if ($shareRows === []) {
return [];
}
$adminIds = array_map(static fn(array $row): int => intval($row['admin_id'] ?? 0), $shareRows);
$adminNames = Db::name('admin')->where('id', 'in', $adminIds)->column('username', 'id');
$sum = '0.00';
$out = [];
$lastIndex = count($shareRows) - 1;
foreach ($shareRows as $index => $shareRow) {
$shareRate = bcadd(strval($shareRow['share_rate'] ?? '0.00'), '0', 2);
$shareDec = bcdiv($shareRate, '100', 4);
$amount = $index === $lastIndex ? bcsub($commissionTotal, $sum, 2) : bcmul($commissionTotal, $shareDec, 2);
if ($index !== $lastIndex) {
$sum = bcadd($sum, $amount, 2);
}
$aid = intval($shareRow['admin_id'] ?? 0);
$out[] = [
'admin_id' => $aid,
'admin_username' => strval($adminNames[$aid] ?? ('#' . $aid)),
'share_rate' => $shareRate,
'commission_amount' => $amount,
];
}
return $out;
}
}