option('date') ? Carbon::parse($this->option('date'))->toDateString() : Carbon::yesterday()->toDateString(); $this->line("Aggregating funnel progress for {$date} …"); $rows = DB::table('analytics_funnel_progress') ->selectRaw(" DATE(started_at) AS summary_date, module, COUNT(*) AS starts, SUM(IF(highest_step >= 0, 1, 0)) AS step_0_reached, SUM(IF(highest_step >= 1, 1, 0)) AS step_1_reached, SUM(IF(highest_step >= 2, 1, 0)) AS step_2_reached, SUM(IF(highest_step >= 3, 1, 0)) AS step_3_reached, SUM(IF(highest_step >= 4, 1, 0)) AS step_4_reached, SUM(IF(highest_step >= 5, 1, 0)) AS step_5_reached, SUM(IF(highest_step >= 6, 1, 0)) AS step_6_reached, SUM(submitted) AS submissions, SUM(abandoned) AS abandonments ") ->whereDate('started_at', $date) ->groupByRaw('DATE(started_at), module') ->get(); if ($rows->isEmpty()) { $this->line(" No funnel_progress rows for {$date} — nothing to write."); return self::SUCCESS; } $now = Carbon::now()->toDateTimeString(); $upsertRows = $rows->map(fn (object $r) => [ 'id' => $this->ids->generate(), 'summary_date' => $r->summary_date, 'module' => $r->module, 'starts' => (int) $r->starts, 'step_0_reached' => (int) $r->step_0_reached, 'step_1_reached' => (int) $r->step_1_reached, 'step_2_reached' => (int) $r->step_2_reached, 'step_3_reached' => (int) $r->step_3_reached, 'step_4_reached' => (int) $r->step_4_reached, 'step_5_reached' => (int) $r->step_5_reached, 'step_6_reached' => (int) $r->step_6_reached, 'submissions' => (int) $r->submissions, 'abandonments' => (int) $r->abandonments, 'created_at' => $now, 'updated_at' => $now, ])->all(); DB::table('analytics_daily_funnels')->upsert( $upsertRows, ['summary_date', 'module'], [ 'starts', 'step_0_reached', 'step_1_reached', 'step_2_reached', 'step_3_reached', 'step_4_reached', 'step_5_reached', 'step_6_reached', 'submissions', 'abandonments', 'updated_at', ], ); $this->info(" Done. {$rows->count()} module(s) written for {$date}."); return self::SUCCESS; } }