| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125 |
- <?php
- declare(strict_types=1);
- namespace plugin\saiadmin\app\service\agent;
- use InvalidArgumentException;
- use plugin\saiadmin\app\model\water\WaterCommissionSetting;
- use plugin\saiadmin\app\model\water\WaterLedger;
- use plugin\saiadmin\app\model\water\WaterModel;
- use plugin\saiadmin\exception\ApiException;
- /** Editable platform rates; each paid order keeps the rate used at accrual time. */
- final class WaterCommissionPolicy
- {
- private const RATE_FIELDS = [
- 1 => 'level1_basis_points',
- 2 => 'level2_basis_points',
- 3 => 'level3_basis_points',
- ];
- public static function current(bool $lock = false): array
- {
- $query = WaterCommissionSetting::query();
- $row = ($lock ? $query->sharedLock() : $query)->find(1);
- if (!$row) {
- throw new ApiException('请先初始化供水佣金规则');
- }
- return [
- 'level1_basis_points' => (int) $row->level1_basis_points,
- 'level2_basis_points' => (int) $row->level2_basis_points,
- 'level3_basis_points' => (int) $row->level3_basis_points,
- 'revision' => (int) $row->revision,
- 'updated_at' => $row->updated_at,
- ];
- }
- public static function rate(int $level, bool $lock = false): int
- {
- $field = self::RATE_FIELDS[$level] ?? throw new InvalidArgumentException('未知代理等级');
- return self::current($lock)[$field];
- }
- public static function message(): string
- {
- $rates = self::current();
- $percent = static fn (int $basisPoints): string => rtrim(rtrim(number_format($basisPoints / 100, 2, '.', ''), '0'), '.');
- return '新成交订单仅给归属代理计提:一级' . $percent($rates['level1_basis_points'])
- . '%、二级' . $percent($rates['level2_basis_points']) . '%、三级'
- . $percent($rates['level3_basis_points']) . '%;当前为待结算,提现尚未开放。';
- }
- public static function save(array $input, int $actor): array
- {
- $allowed = array_merge(array_values(self::RATE_FIELDS), ['revision']);
- if (array_diff(array_keys($input), $allowed)) {
- throw new ApiException('佣金规则包含不支持的字段');
- }
- $values = [];
- foreach (self::RATE_FIELDS as $field) {
- $values[$field] = self::integer($input[$field] ?? null, $field, 0, 10000);
- }
- $revision = self::integer($input['revision'] ?? null, 'revision', 1, 2147483646);
- return WaterModel::transaction(function () use ($values, $revision, $actor): array {
- $row = WaterCommissionSetting::query()->lockForUpdate()->find(1);
- if (!$row) {
- throw new ApiException('请先初始化供水佣金规则');
- }
- if ((int) $row->revision !== $revision) {
- throw new ApiException('佣金规则已被其他操作员修改,请重新打开后编辑');
- }
- $before = [(int) $row->level1_basis_points, (int) $row->level2_basis_points, (int) $row->level3_basis_points];
- $row->fill($values);
- $row->revision = $revision + 1;
- $row->updated_by = $actor;
- $row->updated_at = date('Y-m-d H:i:s');
- $row->save();
- WaterLedger::query()->create([
- 'kind' => 'commission_policy',
- 'created_by' => $actor,
- 'sku_id' => 0,
- 'enterprise_id' => 0,
- 'quantity' => 0,
- 'reference' => 'platform:commission:revision:' . $row->revision,
- 'note' => '代理佣金比例调整(基点):' . implode('/', $before) . '→' . implode('/', array_values($values)),
- 'created_at' => $row->updated_at,
- ]);
- return self::current();
- });
- }
- public static function amount(int $baseAmountCents, int $level): int
- {
- return self::amountAtRate($baseAmountCents, self::rate($level));
- }
- public static function amountAtRate(int $baseAmountCents, int $rate): int
- {
- if ($baseAmountCents < 0) {
- throw new InvalidArgumentException('佣金基数不能为负数');
- }
- if ($rate < 0 || $rate > 10000) {
- throw new InvalidArgumentException('佣金比例必须在0到100%之间');
- }
- $whole = intdiv($baseAmountCents, 10000) * $rate;
- $fraction = intdiv(($baseAmountCents % 10000) * $rate + 5000, 10000);
- return $whole + $fraction;
- }
- private static function integer(mixed $value, string $field, int $min, int $max): int
- {
- if ((!is_int($value) && !is_string($value)) || filter_var($value, FILTER_VALIDATE_INT) === false
- || (int) $value < $min || (int) $value > $max) {
- throw new ApiException($field . ' 必须是 ' . $min . ' 到 ' . $max . ' 之间的整数');
- }
- return (int) $value;
- }
- }
|