| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- <?php
- declare(strict_types=1);
- namespace app\miniapi\service;
- use app\miniapi\http\Fields;
- use app\miniapi\exception\ApiException;
- use app\miniapi\http\Pagination;
- use plugin\saiadmin\app\model\water\WaterEnterprise;
- use plugin\saiadmin\app\model\water\WaterOrder;
- use plugin\saiadmin\app\model\water\WaterLedger;
- use plugin\saiadmin\app\model\water\WaterCommission;
- use app\miniapi\auth\TestPhoneIdentityProvider;
- use plugin\saiadmin\app\service\agent\WaterCommissionPolicy;
- final class AgentQuery
- {
- public function withdraw(int $agent): array
- {
- $this->access->resource('agent', $agent);
- throw new ApiException(50303, '佣金提现尚未开通,未创建提现申请', 503);
- }
- public function __construct(private readonly Access $access)
- {
- }
- private function enterpriseIds(array $agents)
- {
- return WaterEnterprise::query()->whereIn('agent_id', $agents)->select('id');
- }
- public function dashboard(int $agent): array
- {
- $agentRow = $this->access->resource('agent', $agent);
- $agentIds = $this->access->agentIds($agent);
- $start = date('Y-m-01 00:00:00');
- $now = date('Y-m-d H:i:s');
- $orders = WaterOrder::query()->whereIn('enterprise_id', $this->enterpriseIds($agentIds));
- $month = (int) (clone $orders)->whereBetween('created_at', [$start, $now])->sum('amount_cents');
- $previousStart = date('Y-m-01 00:00:00', strtotime('first day of last month'));
- $previousEnd = date('Y-m-d H:i:s', strtotime($start) - 1);
- $previous = (int) (clone $orders)->whereBetween('created_at', [$previousStart, $previousEnd])->sum('amount_cents');
- $trend = [];
- for ($i = 6;$i >= 0;$i--) {
- $day = date('Y-m-d', strtotime('-' . $i . ' days'));
- $trend[] = [
- 'day' => $day,
- 'amount_cents' => (int) (clone $orders)->whereBetween('created_at', [$day . ' 00:00:00', min($day . ' 23:59:59', $now)])->sum('amount_cents'),
- ];
- }
- $customers = WaterEnterprise::query()->whereIn('agent_id', $agentIds);
- $pendingCommission = (int) WaterCommission::query()->where('agent_id', $agent)
- ->where('status', 'pending')->sum('amount_cents');
- return [
- 'agent' => [
- 'id' => (int) $agentRow->id,
- 'name' => $agentRow->name,
- 'region' => $agentRow->region,
- ],
- 'summary' => [
- 'month_amount_cents' => $month,
- 'previous_month_amount_cents' => $previous,
- 'growth_percent' => $previous > 0 ? round(($month - $previous) * 100 / $previous, 2) : null,
- 'customer_count' => (clone $customers)->count(),
- 'new_customers' => (clone $customers)->whereBetween('created_at', [$start, $now])->count(),
- 'team_count' => count($agentIds) - 1,
- 'estimated_commission_cents' => $pendingCommission,
- 'withdrawable_cents' => 0,
- 'pending_commission_cents' => $pendingCommission,
- ],
- 'trend' => $trend,
- 'attribution' => 'current_enterprise_agent',
- 'capabilities' => [
- 'commission' => true,
- 'withdrawal' => false,
- ],
- ];
- }
- public function customers(int $agent, array $input): array
- {
- $agentIds = $this->access->agentIds($agent);
- $page = new Pagination($input);
- $keyword = Fields::text($input, 'keyword', 120, false);
- $filter = Fields::choice($input, 'filter', ['all', 'new', 'unpaid'], 'all');
- $asOf = date('Y-m-d H:i:s');
- $base = WaterEnterprise::query()->whereIn('agent_id', $agentIds);
- $paid = WaterOrder::query()->where('created_at', '<=', $asOf)->select('enterprise_id');
- $summary = [
- 'all' => (clone $base)->count(),
- 'new' => (clone $base)->whereBetween('created_at', [date('Y-m-01 00:00:00'), date('Y-m-d H:i:s')])->count(),
- 'unpaid' => (clone $base)->whereNotIn('id', $paid)->count(),
- ];
- if ($filter === 'new') {
- $base->whereBetween('created_at', [date('Y-m-01 00:00:00'), date('Y-m-d H:i:s')]);
- }
- if ($filter === 'unpaid') {
- $base->whereNotIn('id', $paid);
- }
- if ($keyword !== '') {
- $base->where(fn ($query) => $query->where('name', 'like', '%' . $keyword . '%')->orWhere('contact', 'like', '%' . $keyword . '%')->orWhere('phone', 'like', '%' . $keyword . '%'));
- }
- $total = (clone $base)->count();
- $paidOrders = static fn ($query) => $query->where('created_at', '<=', $asOf);
- $rows = $base
- ->withSum(['orders as purchased_amount' => $paidOrders], 'amount_cents')
- ->withMax(['orders as last_purchase_at' => $paidOrders], 'created_at')
- ->withExists(['orders as has_purchased' => $paidOrders])
- ->withCount('devices')
- ->orderByDesc('id')->offset($page->offset())->limit($page->pageSize)->get()->map(function ($enterprise) {
- return [
- 'id' => (int) $enterprise->id,
- 'name' => $enterprise->name,
- 'contact' => $enterprise->contact,
- 'phone' => WaterPresenter::phone($enterprise->phone),
- 'region' => $enterprise->region,
- 'created_at' => $enterprise->created_at,
- 'amount_cents' => (int) $enterprise->purchased_amount,
- 'last_purchase_at' => $enterprise->last_purchase_at,
- 'has_purchased' => (bool) $enterprise->has_purchased,
- 'device_count' => (int) $enterprise->devices_count,
- ];
- })->all();
- return $page->result($rows, $total) + ['summary' => $summary];
- }
- public function orders(int $agent, array $input): array
- {
- $agentIds = $this->access->agentIds($agent);
- $page = new Pagination($input);
- $query = WaterOrder::query()->whereIn('enterprise_id', $this->enterpriseIds($agentIds))->where('created_at', '<=', date('Y-m-d H:i:s'));
- if (isset($input['enterprise_id'])) {
- $query->where('enterprise_id', Fields::id($input, 'enterprise_id'));
- }
- $total = (clone $query)->count();
- return $page->result($query->orderByDesc('id')->offset($page->offset())->limit($page->pageSize)
- ->get([
- 'id',
- 'enterprise_id',
- 'package_name',
- 'buckets',
- 'amount_cents',
- 'created_at',
- ])->toArray(), $total);
- }
- public function commissions(int $agent, array $input = []): array
- {
- $this->access->resource('agent', $agent);
- $page = new Pagination($input);
- $status = Fields::choice($input, 'status', ['all', 'pending', 'settled', 'adjustment', 'withdrawn'], 'all');
- $source = Fields::choice($input, 'source', ['regular', 'demo'], 'regular');
- if ($source === 'demo' && $agent === 7 && TestPhoneIdentityProvider::enabled()) {
- $fixture = WaterLedger::query()->where('enterprise_id', 49)->where('kind', 'demo_seed')
- ->where('reference', 'TEST-MINI-COMMISSIONS-7-20261007')->first();
- if ($fixture) {
- $data = json_decode($fixture->note, true, 512, JSON_THROW_ON_ERROR);
- $query = WaterLedger::query()->where('enterprise_id', 49)->where('kind', 'demo_seed')
- ->where('reference', 'like', 'TEST-MINI-COMMISSIONS-7-20261007-ITEM-%');
- if ($status !== 'all') {
- $query->where('note->status', $status);
- }
- $total = (clone $query)->count();
- $items = $query->orderByDesc('id')->offset($page->offset())->limit($page->pageSize)->get()
- ->map(fn ($record) => json_decode($record->note, true, 512, JSON_THROW_ON_ERROR))->all();
- return array_replace($data, $page->result($items, $total));
- }
- }
- if ($source === 'demo') {
- return [
- 'enabled' => false,
- 'reason' => '当前账号没有佣金演示数据。',
- 'withdrawable_cents' => null,
- 'pending_cents' => null,
- 'total_cents' => null,
- 'withdrawn_cents' => null,
- 'demo' => true,
- ] + $page->result([], 0);
- }
- $base = WaterCommission::query()->where('agent_id', $agent);
- $pending = (int) (clone $base)->where('status', 'pending')->sum('amount_cents');
- $totalAmount = (int) (clone $base)->sum('amount_cents');
- $list = clone $base;
- if ($status !== 'all') {
- $list->where('status', $status);
- }
- $total = (clone $list)->count();
- $items = $list->orderByDesc('id')->offset($page->offset())->limit($page->pageSize)
- ->get()->map(static fn (WaterCommission $row) => [
- 'id' => (int) $row->id,
- 'customer_name' => $row->enterprise_name,
- 'title' => '购水订单佣金(' . intdiv((int) $row->rate_basis_points, 100) . '%)',
- 'status' => $row->status,
- 'status_text' => match ($row->status) {
- 'pending' => '待结算',
- 'settled' => '已结算',
- 'adjustment' => '已冲减',
- 'withdrawn' => '已提现',
- default => $row->status,
- },
- 'amount_cents' => (int) $row->amount_cents,
- 'created_at' => $row->created_at,
- ])->all();
- return [
- 'enabled' => true,
- 'reason' => WaterCommissionPolicy::message(),
- 'withdrawable_cents' => 0,
- 'pending_cents' => $pending,
- 'total_cents' => $totalAmount,
- 'withdrawn_cents' => 0,
- ] + $page->result($items, $total);
- }
- }
|