| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879 |
- <?php
- namespace App\Console\Commands;
- use App\Services\MemberDailyReportService;
- use Carbon\Carbon;
- use Illuminate\Console\Command;
- use Illuminate\Support\Facades\DB;
- use Illuminate\Support\Facades\Schema;
- class MemberDailyReport extends Command
- {
- protected $signature = 'report:member-daily
- {date? : 结束日期 Y-m-d,默认今天}
- {--days=1 : 从 date 往前共重算几天(最多 31,定时任务用)}
- {--from= : 补算历史:从这天(Y-m-d)重算到 date,不限天数}
- {--all : 补算全部历史:从最早有数据的一天重算到 date}';
- protected $description = '生成会员每日盈亏报表(补算历史用 --from 或 --all)';
- public function handle(MemberDailyReportService $reports): int
- {
- $end = $this->date((string) ($this->argument('date') ?: now()->toDateString()));
- if (!$end) return self::FAILURE;
- if ($this->option('all')) {
- $start = $this->earliestDate();
- if ($start === null) {
- $this->info('没有任何会员数据,无需补算');
- return self::SUCCESS;
- }
- $start = Carbon::parse($start)->startOfDay();
- } elseif ($this->option('from')) {
- $start = $this->date((string) $this->option('from'));
- if (!$start) return self::FAILURE;
- } else {
- $start = $end->copy()->subDays(max(1, min(31, (int) $this->option('days'))) - 1);
- }
- if ($start->gt($end)) {
- $this->error('开始日期不能晚于结束日期');
- return self::FAILURE;
- }
- $total = (int) $start->diffInDays($end) + 1;
- if ($total > 1) $this->info("重算 {$start->toDateString()} ~ {$end->toDateString()},共 {$total} 天");
- $rows = 0;
- // 从最近的一天往前算:补算过程中最新的数据先可用
- for ($day = $end->copy(), $i = 1; $day->gte($start); $day->subDay(), ++$i) {
- $count = $reports->refresh($day->toDateString());
- $rows += $count;
- $this->info(($total > 1 ? "[{$i}/{$total}] " : '') . $day->toDateString() . ':' . $count . ' 行');
- }
- if ($total > 1) $this->info("完成,共写入 {$rows} 行");
- return self::SUCCESS;
- }
- private function date(string $value): ?Carbon
- {
- $parsed = Carbon::createFromFormat('!Y-m-d', $value);
- if (!$parsed || $parsed->format('Y-m-d') !== $value) {
- $this->error('日期必须是有效的 Y-m-d:' . $value);
- return null;
- }
- return $parsed;
- }
- /** 最早有会员数据的日期:会员注册、充值、提现、三方充提、资金流水、已结算注单中最早的一天。 */
- private function earliestDate(): ?string
- {
- $dates = [];
- foreach ([['users', 'created_at'], ['recharges', 'created_at'], ['withdraws', 'created_at'], ['payment_orders', 'created_at'],
- ['balance_logs', 'created_at'], ['share_bet_facts', 'settled_at']] as [$table, $column]) {
- if (!Schema::hasTable($table)) continue;
- $min = DB::table($table)->min($column);
- if ($min !== null && $min !== '') $dates[] = substr((string) $min, 0, 10);
- }
- return $dates === [] ? null : min($dates);
- }
- }
|