Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
Kernel
0.00% covered (danger)
0.00%
0 / 57
0.00% covered (danger)
0.00%
0 / 3
72
0.00% covered (danger)
0.00%
0 / 1
 schedule
0.00% covered (danger)
0.00%
0 / 45
0.00% covered (danger)
0.00%
0 / 1
12
 commands
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 isWorkingDayOfMonth
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
20
1<?php
2
3namespace App\Console;
4
5use Carbon\Carbon;
6use Illuminate\Console\Scheduling\Schedule;
7use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
8
9class Kernel extends ConsoleKernel
10{
11    /**
12     * Define the application's command schedule.
13     *
14     * @return void
15     */
16    protected function schedule(Schedule $schedule)
17    {
18        // FIRE-1025 / FIRE-977 follow-up: every command below uses
19        // `withoutOverlapping($timeoutMinutes)` so a long-running invocation
20        // never piles a second instance on top of itself. See
21        // routes/console.php for the same protection (mirrored intentionally
22        // — the system cron on master currently dispatches individual artisan
23        // commands directly, but Laravel's scheduler also reads this file
24        // when it's re-enabled).
25
26        // $schedule->command('inspire')->hourly();
27        $schedule->command('presupuestos:sincronizar')->dailyAt('03:00')->withoutOverlapping(60);
28        $schedule->command('quotations:sync')
29            ->everyFiveMinutes()
30            ->weekdays() // from monday to friday
31            ->withoutOverlapping(15);
32
33        $schedule->command('ifex-quotations:sync')
34            ->everyFiveMinutes()
35            ->weekdays() // from monday to friday
36            ->withoutOverlapping(15);
37
38        $schedule->command('quotations:sync')
39            ->dailyAt('22:00')
40            ->weekends() // saturday and sunday
41            ->withoutOverlapping(60);
42
43        $schedule->command('quotations:sync-work')->weeklyOn(6, '03:00')->withoutOverlapping(120);
44
45        $schedule->command('update:commercial-numbers')
46            ->everyMinute()
47            ->when(function () {
48                return now()->minute % 3 == 0;
49            })
50            ->withoutOverlapping(5);
51
52        $schedule->command('invoices:send-reminder')->dailyAt('08:00')->withoutOverlapping(60);
53
54        $schedule->command('invoices:call-center')->dailyAt('18:00')->withoutOverlapping(60);
55
56        $schedule->command('quotations:sync-missing')->dailyAt('06:01')->withoutOverlapping(60);
57
58        // FIRE-977 schedule lives in routes/console.php (Laravel 11+ convention)
59
60        $schedule->command('clear:email-processing')->everyTenMinutes()->withoutOverlapping(15);
61
62        // FIRE-864 — backfill stuck "processed" emails from SendGrid Activity
63        // API. Runs hourly so the cleanup Jorge asked for happens continuously
64        // instead of only when the webhook delivers events. Limit of 200 rows
65        // keeps the API usage bounded.
66        $schedule->command('email:backfill-status --limit=200')->hourly()->withoutOverlapping(50);
67
68        $schedule->command('finance:import-drive')->weeklyOn(6, '04:00')->withoutOverlapping(60);
69
70        // Weekly finance report — every Saturday at 04:00 (madrugada) — shows MTD
71        $schedule->command('finance:send-report --type=weekly')->weeklyOn(6, '04:00')->withoutOverlapping(60);
72
73        // Monthly finance report — on working day +5 of each month (closed previous month + YTD)
74        $schedule->command('finance:send-report --type=monthly')
75            ->dailyAt('06:00')
76            ->when(fn () => $this->isWorkingDayOfMonth(5))
77            ->withoutOverlapping(60);
78
79        // FIRE-1025 follow-up to FIRE-1001: once-daily janitor for legacy
80        // `acceptance_date = '0000-00-00 00:00:00'` rows. Replaces the 5
81        // in-line sweepers in PresupuestosService.php that were issuing
82        // the same UPDATE at the end of every G3W sync iteration and
83        // deadlocking on `idx_acceptance_date` under concurrency.
84        $schedule->command('quotations:cleanup-zero-dates')->dailyAt('04:30')->withoutOverlapping(30);
85
86        $schedule->command('administrators-invoices:sync')
87            ->dailyAt('11:00')
88            ->withoutOverlapping(60)
89            ->when(function () {
90                $today = Carbon::today();
91
92                if ($today->isWeekend()) {
93                    return false;
94                }
95
96                $firstDayOfMonth = Carbon::parse($today->year.'-'.$today->month.'-01');
97
98                $firstWorkDayOfMonth = $firstDayOfMonth;
99                while ($firstWorkDayOfMonth->isWeekend()) {
100                    $firstWorkDayOfMonth->addDay();
101                }
102
103                return $today->toDateString() === $firstWorkDayOfMonth->toDateString();
104            });
105    }
106
107    /**
108     * Register the commands for the application.
109     *
110     * @return void
111     */
112    protected function commands()
113    {
114        $this->load(__DIR__.'/Commands');
115
116        require base_path('routes/console.php');
117    }
118
119    /**
120     * True if today is the Nth working day (Mon-Fri) of the current month.
121     * Used for scheduling the monthly finance report on "WD+5".
122     */
123    private function isWorkingDayOfMonth(int $n): bool
124    {
125        $today = Carbon::today();
126        if ($today->isWeekend()) {
127            return false;
128        }
129        $current = $today->copy()->startOfMonth();
130        $workingDays = 0;
131        while ($current->lte($today)) {
132            if (! $current->isWeekend()) {
133                $workingDays++;
134            }
135            $current->addDay();
136        }
137        return $workingDays === $n;
138    }
139}