'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; } }