diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index b0002daf3d..b87ea25c7a 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -15,6 +15,7 @@ use App\Jobs\Cron\AutoBillCron; use App\Jobs\Cron\RecurringExpensesCron; use App\Jobs\Cron\RecurringInvoicesCron; use App\Jobs\Cron\SubscriptionCron; +use App\Jobs\Cron\UpdateCalculatedFields; use App\Jobs\Invoice\InvoiceCheckLateWebhook; use App\Jobs\Ninja\AdjustEmailQuota; use App\Jobs\Ninja\BankTransactionSync; @@ -47,14 +48,23 @@ class Kernel extends ConsoleKernel /* Check for the latest version of Invoice Ninja */ $schedule->job(new VersionCheck)->daily(); - /* Checks and cleans redundant files */ - $schedule->job(new DiskCleanup)->dailyAt('02:10')->withoutOverlapping()->name('disk-cleanup-job')->onOneServer(); + /* Returns the number of jobs in the queue */ + $schedule->job(new QueueSize)->everyFiveMinutes()->withoutOverlapping()->name('queue-size-job')->onOneServer(); /* Send reminders */ $schedule->job(new ReminderJob)->hourly()->withoutOverlapping()->name('reminder-job')->onOneServer(); - /* Returns the number of jobs in the queue */ - $schedule->job(new QueueSize)->everyFiveMinutes()->withoutOverlapping()->name('queue-size-job')->onOneServer(); + /* Sends recurring invoices*/ + $schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer(); + + /* Checks for scheduled tasks */ + $schedule->job(new TaskScheduler())->hourlyAt(10)->withoutOverlapping()->name('task-scheduler-job')->onOneServer(); + + /* Stale Invoice Cleanup*/ + $schedule->job(new CleanStaleInvoiceOrder)->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer(); + + /* Stale Invoice Cleanup*/ + $schedule->job(new UpdateCalculatedFields)->hourlyAt(40)->withoutOverlapping()->name('update-calculated-fields-job')->onOneServer(); /* Checks for large companies and marked them as is_large */ $schedule->job(new CompanySizeCheck)->dailyAt('23:20')->withoutOverlapping()->name('company-size-job')->onOneServer(); @@ -65,33 +75,26 @@ class Kernel extends ConsoleKernel /* Runs cleanup code for subscriptions */ $schedule->job(new SubscriptionCron)->dailyAt('00:01')->withoutOverlapping()->name('subscription-job')->onOneServer(); - /* Sends recurring invoices*/ - $schedule->job(new RecurringInvoicesCron)->hourly()->withoutOverlapping()->name('recurring-invoice-job')->onOneServer(); - - /* Stale Invoice Cleanup*/ - $schedule->job(new CleanStaleInvoiceOrder)->hourlyAt(30)->withoutOverlapping()->name('stale-invoice-job')->onOneServer(); - /* Sends recurring invoices*/ $schedule->job(new RecurringExpensesCron)->dailyAt('00:10')->withoutOverlapping()->name('recurring-expense-job')->onOneServer(); - /* Fires notifications for expired Quotes */ - $schedule->job(new QuoteCheckExpired)->dailyAt('05:10')->withoutOverlapping()->name('quote-expired-job')->onOneServer(); - - /* Fires webhooks for overdue Invoice */ - $schedule->job(new InvoiceCheckLateWebhook)->dailyAt('07:00')->withoutOverlapping()->name('invoice-overdue-job')->onOneServer(); - - /* Performs auto billing */ - $schedule->job(new AutoBillCron)->dailyAt('06:20')->withoutOverlapping()->name('auto-bill-job')->onOneServer(); - /* Checks the status of the scheduler */ $schedule->job(new SchedulerCheck)->dailyAt('01:10')->withoutOverlapping(); - /* Checks for scheduled tasks */ - $schedule->job(new TaskScheduler())->hourlyAt(10)->withoutOverlapping()->name('task-scheduler-job')->onOneServer(); + /* Checks and cleans redundant files */ + $schedule->job(new DiskCleanup)->dailyAt('02:10')->withoutOverlapping()->name('disk-cleanup-job')->onOneServer(); /* Performs system maintenance such as pruning the backup table */ $schedule->job(new SystemMaintenance)->sundays()->at('02:30')->withoutOverlapping()->name('system-maintenance-job')->onOneServer(); + /* Fires notifications for expired Quotes */ + $schedule->job(new QuoteCheckExpired)->dailyAt('05:10')->withoutOverlapping()->name('quote-expired-job')->onOneServer(); + + /* Performs auto billing */ + $schedule->job(new AutoBillCron)->dailyAt('06:20')->withoutOverlapping()->name('auto-bill-job')->onOneServer(); + + /* Fires webhooks for overdue Invoice */ + $schedule->job(new InvoiceCheckLateWebhook)->dailyAt('07:00')->withoutOverlapping()->name('invoice-overdue-job')->onOneServer(); if (Ninja::isSelfHost()) { $schedule->call(function () { @@ -106,9 +109,6 @@ class Kernel extends ConsoleKernel /* Pulls in bank transactions from third party services */ $schedule->job(new BankTransactionSync)->dailyAt('04:10')->withoutOverlapping()->name('bank-trans-sync-job')->onOneServer(); - //not used @deprecate - // $schedule->job(new SendFailedEmails)->daily()->withoutOverlapping(); - $schedule->command('ninja:check-data --database=db-ninja-01')->dailyAt('02:10')->withoutOverlapping()->name('check-data-db-1-job')->onOneServer(); $schedule->command('ninja:check-data --database=db-ninja-02')->dailyAt('02:20')->withoutOverlapping()->name('check-data-db-2-job')->onOneServer(); diff --git a/app/Jobs/Cron/UpdateCalculatedFields.php b/app/Jobs/Cron/UpdateCalculatedFields.php new file mode 100644 index 0000000000..7b7664e926 --- /dev/null +++ b/app/Jobs/Cron/UpdateCalculatedFields.php @@ -0,0 +1,96 @@ +where('updated_at', '>', now()->subHours(2)) + ->cursor() + ->each(function ($project) { + + $project->current_hours = $this->calculateDuration($project); + $project->save(); + }); + + + + } else { + //multiDB environment, need to + foreach (MultiDB::$dbs as $db) { + MultiDB::setDB($db); + + + Project::with('tasks')->where('updated_at', '>', now()->subHours(2)) + ->cursor() + ->each(function ($project) { + $project->current_hours = $this->calculateDuration($project); + $project->save(); + }); + + + } + } + } + + private function calculateDuration($project): int + { + $duration = 0; + + $project->tasks->each(function ($task) use (&$duration) { + + + foreach(json_decode($task->time_log) as $log){ + + $start_time = $log[0]; + $end_time = $log[1] == 0 ? time() : $log[1]; + + $duration += $end_time - $start_time; + + } + + return round(($duration/60/60), 0); + + }); + + + } +} + + + + diff --git a/app/Transformers/ProjectTransformer.php b/app/Transformers/ProjectTransformer.php index 8260ceb101..4f55fd7098 100644 --- a/app/Transformers/ProjectTransformer.php +++ b/app/Transformers/ProjectTransformer.php @@ -62,6 +62,7 @@ class ProjectTransformer extends EntityTransformer 'custom_value3' => (string) $project->custom_value3 ?: '', 'custom_value4' => (string) $project->custom_value4 ?: '', 'color' => (string) $project->color ?: '', + 'current_hours' => (int) $project->current_hours ?: 0, ]; } } diff --git a/database/migrations/2023_03_24_054758_add_client_is_exempt_from_taxes.php b/database/migrations/2023_03_24_054758_add_client_is_exempt_from_taxes.php index a12dd18424..2dfb7e5111 100644 --- a/database/migrations/2023_03_24_054758_add_client_is_exempt_from_taxes.php +++ b/database/migrations/2023_03_24_054758_add_client_is_exempt_from_taxes.php @@ -27,6 +27,11 @@ return new class extends Migration $table->dropColumn('tax_all_products'); }); + Schema::table('projects', function (Illuminate\Database\Schema\Blueprint $table) { + $table->unsignedInteger('current_hours')->nullable(); + }); + + Company::query() ->cursor() ->each(function ($company) {