where('company_id', $this->scheduler->company_id) // ->where('is_deleted', 0); // if (count($this->scheduler->parameters['clients']) >= 1) { // $query->whereIn('client_id', $this->transformKeys($this->scheduler->parameters['clients'])); // } // if (!$this->scheduler->parameters['include_project_tasks']) { // $query->whereNull('project_id'); // } $query = Client::query() ->where('company_id', $this->scheduler->company_id) ->where('is_deleted', 0); if (count($this->scheduler->parameters['clients']) >= 1) { $query->whereIn('id', $this->transformKeys($this->scheduler->parameters['clients'])); } $query->whereHas('tasks', function ($sub_query){ $sub_query->whereNull('invoice_id') ->where('is_deleted', 0) ->whereBetween('calculated_start_date', $this->calculateStartAndEndDates()) ->when(!$this->scheduler->parameters['include_project_tasks'], function ($sub_query_two){ $sub_query_two->whereNull('project_id'); }); }); $invoice_repo = new InvoiceRepository(); $query->cursor() ->each(function (Client $client) use ($invoice_repo) { $line_items = $client->tasks()->whereNull('invoice_id') ->where('is_deleted', 0) ->whereBetween('calculated_start_date', $this->calculateStartAndEndDates()) ->when(!$this->scheduler->parameters['include_project_tasks'], function ($sub_query_two){ return $sub_query_two->whereNull('project_id'); }) ->get() ->filter(function (Task $task){ return $task->calcDuration(true) > 0 && !$task->isRunning(); }) ->map(function (Task $task, $key){ if ($key == 0 && $task->company->invoice_task_project) { $body = '
'.$task->project->name.'
' .$task->project?->public_notes ?? ''; //@phpstan-ignore-line $body .= '
'.$task->description().'
'; } elseif (!$task->company->invoice_task_hours && !$task->company->invoice_task_timelog && !$task->company->invoice_task_datelog && !$task->company->invoice_task_item_description) { $body = $task->description ?? ''; } else { $body = '
'.$task->description().'
'; } $item = new InvoiceItem(); $item->quantity = $task->getQuantity(); $item->cost = $task->getRate(); $item->product_key = ''; $item->notes = $body; $item->task_id = $task->hashed_id; $item->tax_id = (string) Product::PRODUCT_TYPE_SERVICE; $item->type_id = '2'; return $item; }) ->toArray(); if(count(array_values($line_items)) > 0){ $data = [ 'client_id' => $client->id, 'date' => now()->addSeconds($client->company->utc_offset())->format('Y-m-d'), 'line_items' => array_values($line_items), 'uses_inclusive_taxes' => $client->company->settings->inclusive_taxes ?? false, ]; $invoice = $invoice_repo->save($data, InvoiceFactory::create($client->company_id, $client->user_id)); if($this->scheduler->parameters['auto_send']){ nlog('sending email'); $invoice->service()->sendEmail(); } } }); $this->scheduler->calculateNextRun(); } /** * Start and end date of the statement * * @return array [$start_date, $end_date]; */ private function calculateStartAndEndDates(): array { return match ($this->scheduler->parameters['date_range']) { EmailStatement::LAST7 => [now()->startOfDay()->subDays(7)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST30 => [now()->startOfDay()->subDays(30)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::LAST365 => [now()->startOfDay()->subDays(365)->format('Y-m-d'), now()->startOfDay()->format('Y-m-d')], EmailStatement::THIS_MONTH => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')], EmailStatement::LAST_MONTH => [now()->startOfDay()->subMonthNoOverflow()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->subMonthNoOverflow()->lastOfMonth()->format('Y-m-d')], EmailStatement::THIS_QUARTER => [now()->startOfDay()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->endOfQuarter()->format('Y-m-d')], EmailStatement::LAST_QUARTER => [now()->startOfDay()->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d'), now()->startOfDay()->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d')], EmailStatement::THIS_YEAR => [now()->startOfDay()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->lastOfYear()->format('Y-m-d')], EmailStatement::LAST_YEAR => [now()->startOfDay()->subYearNoOverflow()->firstOfYear()->format('Y-m-d'), now()->startOfDay()->subYearNoOverflow()->lastOfYear()->format('Y-m-d')], EmailStatement::ALL_TIME => [ Task::query() ->where('company_id', $this->scheduler->company_id) ->where('is_deleted', 0) ->selectRaw('MIN(tasks.calculated_start_date) as start_date') ->pluck('start_date') ->first() ?: Carbon::now()->format('Y-m-d'), Carbon::now()->format('Y-m-d') ], EmailStatement::CUSTOM_RANGE => [$this->scheduler->parameters['start_date'], $this->scheduler->parameters['end_date']], default => [now()->startOfDay()->firstOfMonth()->format('Y-m-d'), now()->startOfDay()->lastOfMonth()->format('Y-m-d')], }; } }