| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687 |
- <?php
- namespace App\Services\Agent;
- use App\Models\Agent\Agent;
- use App\Models\Agent\AgentDailyStat;
- use App\Models\Agent\AgentProfitEntry;
- use App\Models\Agent\AgentRebateRecord;
- use Carbon\Carbon;
- use Illuminate\Support\Facades\DB;
- /**
- * 合营分成每日入账:把结算日不晚于 $date、尚未入账的实时分成按代理和分类汇总成 AgentRebateRecord,
- * 再正负入账到代理余额。settlement_date 是入账批次日期;补结算的旧注单会进入下一次批次。
- */
- class AgentCommissionService
- {
- public function __construct(private AgentWalletService $wallets)
- {
- }
- public function settle(string $date, bool $credit = true): array
- {
- $day = Carbon::parse($date)->toDateString();
- $created = 0;
- $credited = 0;
- $agentIds = AgentProfitEntry::query()->where('status', AgentProfitEntry::STATUS_COUNTED)
- ->whereNull('rebate_record_id')->where('settle_date', '<=', $day)
- ->distinct()->orderBy('agent_id')->pluck('agent_id');
- foreach ($agentIds as $agentId) {
- $result = DB::transaction(function () use ($agentId, $day, $credit) {
- $agent = Agent::query()->lockForUpdate()->findOrFail($agentId);
- $entries = AgentProfitEntry::query()->where('agent_id', $agent->id)
- ->where('status', AgentProfitEntry::STATUS_COUNTED)->whereNull('rebate_record_id')
- ->where('settle_date', '<=', $day)->orderBy('id')->lockForUpdate()->get();
- $created = $credited = 0;
- foreach ($entries->groupBy('category') as $category => $rows) {
- [$gameType] = AgentRebateRecord::CATEGORIES[$category] ?? [0];
- $record = AgentRebateRecord::query()->lockForUpdate()->firstOrNew([
- 'settlement_date' => $day, 'agent_id' => $agent->id,
- 'platform' => (string) $category, 'game_type' => $gameType,
- ]);
- if ($record->exists && $record->profit_status === AgentRebateRecord::STATUS_CREDITED) {
- continue; // 同一批次已入账,新增的补结算注单留到下一批次。
- }
- $created += $record->exists ? 0 : 1;
- $sum = fn (string $field) => $rows->reduce(fn ($carry, $row) => bcadd($carry, (string) $row->{$field}, 4), '0.0000');
- $record->fill([
- 'order_no' => $record->order_no ?: $this->orderNo($day, (int) $agent->id, (string) $category),
- 'bet_count' => $rows->where('revision', 0)->count(), 'entry_count' => $rows->count(),
- 'bet_amount' => $sum('bet_amount'), 'valid_bet_amount' => $sum('effective_amount'),
- 'win_loss' => $sum('net_profit'), 'profit_rate' => (string) $rows->last()->rate,
- 'profit_commission' => $sum('share_amount'),
- 'profit_status' => AgentRebateRecord::STATUS_PENDING,
- 'snapshot' => ['entry_ids' => [$rows->first()->id, $rows->last()->id],
- 'rates' => $rows->pluck('rate')->map(fn ($rate) => (string) $rate)->unique()->values()->all()],
- ]);
- $record->save();
- if (!$credit) continue;
- $this->wallets->creditProfitShare($agent, (string) $record->profit_commission,
- 'rebate:' . $record->id . ':profit', (int) $record->id,
- $day . ' ' . AgentRebateRecord::categoryName((string) $category) . '合营分成');
- $record->profit_status = AgentRebateRecord::STATUS_CREDITED;
- $record->credited_at = now();
- $record->save();
- AgentProfitEntry::query()->whereIn('id', $rows->pluck('id')->all())->update(['rebate_record_id' => $record->id]);
- ++$credited;
- }
- AgentDailyStat::query()->where('stat_date', $day)->where('agent_id', $agent->id)->update([
- 'commission_amount' => AgentRebateRecord::query()->where('settlement_date', $day)
- ->where('agent_id', $agent->id)->where('profit_status', AgentRebateRecord::STATUS_CREDITED)
- ->sum('profit_commission'),
- ]);
- return compact('created', 'credited');
- }, 3);
- $created += $result['created'];
- $credited += $result['credited'];
- }
- return compact('created', 'credited');
- }
- private function orderNo(string $day, int $agentId, string $category): string
- {
- return 'AR' . str_replace('-', '', $day) . str_pad((string) $agentId, 8, '0', STR_PAD_LEFT)
- . strtoupper(substr(hash('sha256', $category), 0, 6));
- }
- }
|