barangay). */ public function rebuildDailyCollectionStats(\DateTimeInterface $date): int { $day = Carbon::parse($date)->toDateString(); $rows = DB::table('collection_logs') ->join('drop_off_points', 'collection_logs.drop_off_point_id', '=', 'drop_off_points.id') ->whereDate('collection_logs.scanned_at', $day) ->where('collection_logs.verification_status', 'valid') ->groupBy('drop_off_points.barangay_id') ->selectRaw(' drop_off_points.barangay_id as barangay_id, COUNT(*) as total_scans, COALESCE(SUM(collection_logs.weight_kg), 0) as total_weight_kg, COUNT(DISTINCT collection_logs.household_id) as unique_households ') ->get(); DailyCollectionStat::where('date', $day)->delete(); $count = 0; foreach ($rows as $r) { DailyCollectionStat::create([ 'date' => $day, 'barangay_id' => $r->barangay_id, 'total_scans' => (int) $r->total_scans, 'total_weight_kg' => (int) $r->total_weight_kg, 'unique_households' => (int) $r->unique_households, 'missed_pickups' => 0, // populated by trip-stop analysis below in future ]); $count++; } return $count; } /** * Recompute weekly_route_performance for the week containing $date. */ public function rebuildWeeklyRoutePerformance(\DateTimeInterface $date): int { $weekStart = Carbon::parse($date)->startOfWeek()->toDateString(); $weekEnd = Carbon::parse($date)->endOfWeek()->toDateString(); $rows = DB::table('trips') ->whereBetween('scheduled_date', [$weekStart, $weekEnd]) ->whereIn('status', ['completed', 'cancelled']) ->groupBy('route_id') ->selectRaw(' route_id, COUNT(*) as trips_count, SUM(CASE WHEN status = "completed" THEN 1 ELSE 0 END) as completed_count, AVG(CASE WHEN actual_end_time IS NOT NULL AND actual_start_time IS NOT NULL THEN TIMESTAMPDIFF(MINUTE, actual_start_time, actual_end_time) ELSE NULL END) as avg_minutes, SUM(CASE WHEN status = "completed" AND actual_start_time IS NOT NULL AND scheduled_start_time IS NOT NULL AND TIMESTAMPDIFF( MINUTE, TIMESTAMP(scheduled_date, scheduled_start_time), actual_start_time ) <= 15 THEN 1 ELSE 0 END) as on_time_count ') ->get(); WeeklyRoutePerformance::where('week_start_date', $weekStart)->delete(); $count = 0; foreach ($rows as $r) { WeeklyRoutePerformance::create([ 'week_start_date' => $weekStart, 'route_id' => $r->route_id, 'on_time_rate_percent' => $r->trips_count > 0 ? (int) round(($r->on_time_count / $r->trips_count) * 100) : 0, 'avg_trip_duration_minutes' => (int) round((float) ($r->avg_minutes ?? 0)), 'completion_rate_percent' => $r->trips_count > 0 ? (int) round(($r->completed_count / $r->trips_count) * 100) : 0, 'trips_count' => (int) $r->trips_count, ]); $count++; } return $count; } /** * Recompute monthly_store_sales for the month containing $date. */ public function rebuildMonthlyStoreSales(\DateTimeInterface $date): int { $monthStart = Carbon::parse($date)->startOfMonth()->toDateString(); $monthEnd = Carbon::parse($date)->endOfMonth()->toDateString(); $rows = DB::table('store_sales') ->whereBetween('sold_at', [$monthStart.' 00:00:00', $monthEnd.' 23:59:59']) ->groupBy('store_id') ->selectRaw(' store_id, SUM(quantity) as qty, SUM(retail_price_centavos) as retail, SUM(commission_centavos) as commission ') ->get(); MonthlyStoreSale::where('month_start_date', $monthStart)->delete(); $count = 0; foreach ($rows as $r) { MonthlyStoreSale::create([ 'month_start_date' => $monthStart, 'store_id' => $r->store_id, 'total_quantity_sold' => (int) $r->qty, 'total_retail_centavos' => (int) $r->retail, 'total_commission_centavos' => (int) $r->commission, ]); $count++; } return $count; } }