$tasks A JSON object, each line has to be contructed using these fields description, days, type Invoices\TaskTypeEnum, amount * @property float $total The total calculated using all tasks * @property float $total_days The total days calculated using all tasks * @property string|null $comment Any comment joined to the invoice * @property int $show_days Show days on the printed invoice * @property Carbon|null $signed_date The date the invoice was signed * @property Carbon|null $sent_client_date The date the invoice was send to the client * @property Carbon|null $sent_accounting_date The date the invoice was send to the client * @property int $site_id * @property int $company_id * @property int $invoiced_to_id * @property InvoiceStatusEnum $status Status of the invoice. * @property Carbon|null $created_at * @property Carbon|null $updated_at * @property Carbon|null $deleted_at * @property-read \App\Models\Company $company * @property-read \App\Models\Company $companyInvoiced * @property-read \App\Models\Site|null $site * @method static \Database\Factories\InvoiceFactory factory($count = null, $state = []) * @method static \Illuminate\Database\Eloquent\Builder|Invoice onlyTrashed() * @method static \Illuminate\Database\Eloquent\Builder|Invoice withTrashed(bool $withTrashed = true) * @method static \Illuminate\Database\Eloquent\Builder|Invoice withoutTrashed() * @mixin \Eloquent */ class Invoice extends Model { use HasFactory; use SoftDeletes; /** * The attributes that are fillable. * * @var array */ protected $fillable = [ 'ref', 'firstname', 'lastname', 'object', 'tasks', 'total', 'total_days', 'comment', 'show_days', 'signed_date', 'sent_client_date', 'sent_accounting_date', 'site_id', 'company_id', 'invoiced_to_id', 'status', ]; /** * The attributes that should be cast. * * @var array */ protected $casts = [ 'tasks' => 'array', 'signed_date' => 'date', 'sent_client_date' => 'date', 'sent_accounting_date' => 'date', 'status' => InvoiceStatusEnum::class, ]; /** * Perform any actions required after the model boots. * * @return void */ protected static function booted() { static::creating(function (self $model) { $model->ref = \sprintf( '%s_%s_%s', Carbon::now()->isoFormat('YYYY-MM'), Str::padLeft((Invoice::whereYear('created_at', Carbon::now()->isoFormat('YYYY')) ->whereMonth('created_at', Carbon::now()->isoFormat('MM')) ->count() + 1) ?: 1, 4, '0'), Str::substr(Str::upper(Str::slug(Auth::user()->name)), 0, 1) ); $model->total_days = collect($model->tasks) /** @var null|float $previous */ ->reduce(function ($previous, array $task) { return \floatval($task['days']) + \floatval($previous); }); $model->total = collect($model->tasks) /** @var null|float $previous */ ->reduce(function ($previous, array $task) { return \floatval($task['amount']) + \floatval($previous); }); $model->status = InvoiceStatusEnum::opened; }); static::updating(function (self $model) { $model->total_days = collect($model->tasks) /** @var null|float $previous */ ->reduce(function ($previous, array $task) { return \floatval($task['days']) + \floatval($previous); }); $model->total = collect($model->tasks) /** @var null|float $previous */ ->reduce(function ($previous, array $task) { return \floatval($task['amount']) + \floatval($previous); }); if($model->sent_accounting_date && $model->status !== InvoiceStatusEnum::archived->value) { $model->status = InvoiceStatusEnum::archived; } }); static::deleting(function () { throw new \Error('Action impossible'); }); } // * RELATIONSHIPS /** * BelongsTo Site * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function site() { return $this->BelongsTo(Site::class); } /** * BelongsTo Company * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function company() { return $this->BelongsTo(Company::class); } /** * BelongsTo Company * * @return \Illuminate\Database\Eloquent\Relations\BelongsTo */ public function companyInvoiced() { return $this->BelongsTo(Company::class, 'invoiced_to_id'); } // * METHODS /** * Get the tasks line structure skel * * @return array */ public static function getTaskStructure(): array { return [ // * string 'desc' => '', // * usigned float 'days' => 0, // * Invoice\TaskTypeEnum value 'type' => TaskTypeEnum::web, // * usigned float 'amount' => 0, // * package ID if task type package or null 'package' => null ]; } /** * Generate Invoice * * @return LaravelMpdf */ public function generateInvoice(): LaravelMpdf { /** @var \Illuminate\Database\Eloquent\Collection<\App\Models\Package> */ $packages = Package::get()->keyBy('id')->all(); /** @var \Mccarlosen\LaravelMpdf\LaravelMpdfWrapper */ $mpdf = app('laravel-mpdf'); /** @var \Mccarlosen\LaravelMpdf\LaravelMpdf */ $pdf = $mpdf->loadView( 'bo.pages.documents.invoice', $this->toArray(), [ 'site' => $this->site, 'company' => $this->company, 'companyInvoiced' => $this->companyInvoiced, 'packages' => $packages, ], [ 'mode' => '', 'format' => 'A4', 'default_font_size' => '12', 'default_font' => 'sans-serif', 'margin_left' => 0, 'margin_right' => 0, 'margin_top' => 0, 'margin_bottom' => 0, 'margin_header' => 0, 'margin_footer' => 0, 'orientation' => 'P', 'title' => __('Devis Équipe Web :ref', ['ref' => $this->ref]), 'author' => 'Equipe Web', 'watermark' => '', 'show_watermark' => false, 'watermark_font' => 'sans-serif', 'display_mode' => 'fullpage', 'watermark_text_alpha' => 0.1, 'custom_font_dir' => '', 'custom_font_data' => [], 'auto_language_detection' => false, 'temp_dir' => ini_get('upload_tmp_dir') ? ini_get('upload_tmp_dir') : sys_get_temp_dir(), 'pdfa' => false, 'pdfaauto' => false, ] ); return $pdf; } /** * Get the invoice status array depending to the dates entered. * * @param \App\Models\Invoice $invoice * @return array */ public static function getInvoiceStatusArray(Invoice $invoice): array { $invoiceStatusArray = []; if ($invoice->signed_date && $invoice->sent_client_date && $invoice->sent_accounting_date) { return array_merge($invoiceStatusArray, [ InvoiceStatusEnum::toArray()['opened'], InvoiceStatusEnum::toArray()['archived'], ]); } if ($invoice->signed_date) { return array_merge($invoiceStatusArray, [ InvoiceStatusEnum::toArray()['opened'] ]); } if ($invoice->sent_client_date) { return array_merge($invoiceStatusArray, [ InvoiceStatusEnum::toArray()['opened'], InvoiceStatusEnum::toArray()['refused'], ]); } return array_merge($invoiceStatusArray, [ InvoiceStatusEnum::toArray()['opened'], InvoiceStatusEnum::toArray()['canceled'], ]); } }