From a78dcc54a1f87276bc80583914503fb433bc61f0 Mon Sep 17 00:00:00 2001 From: Alexis Gousseau Date: Mon, 14 Aug 2023 14:24:51 +0200 Subject: [PATCH 1/5] fix button archived tickets - issue #35 --- resources/views/bo/pages/tickets/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/bo/pages/tickets/index.blade.php b/resources/views/bo/pages/tickets/index.blade.php index 41550c1..e0154ae 100644 --- a/resources/views/bo/pages/tickets/index.blade.php +++ b/resources/views/bo/pages/tickets/index.blade.php @@ -22,7 +22,7 @@ $userPr = Auth::user()->sites ?? collect([]); @endcan   {{ __('ticket') }} - @if(session('tickets.st') == \App\Enums\Tickets\TicketStatusEnum::archived) + @if(session('tickets.st') == \App\Enums\Tickets\TicketStatusEnum::archived->value) @else From 2c9540c283d1de18044205524b0fde4b0883d469 Mon Sep 17 00:00:00 2001 From: Noah Lancien Date: Mon, 14 Aug 2023 16:06:55 +0200 Subject: [PATCH 2/5] Used sync instead of detach/attach for sites and users update --- app/Http/Controllers/Bo/SiteController.php | 2 +- app/Http/Controllers/Bo/UserController.php | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/Http/Controllers/Bo/SiteController.php b/app/Http/Controllers/Bo/SiteController.php index 49aca29..f19c2da 100644 --- a/app/Http/Controllers/Bo/SiteController.php +++ b/app/Http/Controllers/Bo/SiteController.php @@ -129,7 +129,7 @@ class SiteController extends Controller { return DB::transaction(function () use ($request, $site) { $site->fill($request->validated()); - $site->users()->attach(collect($request->validated('users'))->pluck('id')); + $site->users()->sync(collect($request->validated('users'))->pluck('id')); if ($site->saveOrFail()) { return redirect() ->route('bo.sites.edit', $site) diff --git a/app/Http/Controllers/Bo/UserController.php b/app/Http/Controllers/Bo/UserController.php index 1b2bb1d..b5e0cd4 100644 --- a/app/Http/Controllers/Bo/UserController.php +++ b/app/Http/Controllers/Bo/UserController.php @@ -120,10 +120,7 @@ class UserController extends Controller { return DB::transaction(function () use ($request, $user) { $user->fill($request->safe()->except(['sites'])); - $user->sites()->detach(); - if (collect($request->validated('sites'))->pluck('id')) { - $user->sites()->attach(collect($request->validated('sites'))->pluck('id')); - } + $user->sites()->sync(collect($request->validated('sites'))->pluck('id')); if ($user->saveOrFail()) { return redirect() ->route('bo.users.edit', $user) From 53eff1b7a2af5b23307348bd6a58d57eea60e715 Mon Sep 17 00:00:00 2001 From: Alexis Gousseau Date: Mon, 14 Aug 2023 14:15:13 +0000 Subject: [PATCH 3/5] add last_activity field on ticket - issue #23 --- app/Http/Controllers/Bo/TicketController.php | 2 +- app/Models/Message.php | 4 +- app/Models/Ticket.php | 6 ++- ...142748_add_last_activity_tickets_table.php | 43 +++++++++++++++++++ .../views/bo/modules/pagination.blade.php | 2 +- .../views/bo/pages/tickets/index.blade.php | 2 +- 6 files changed, 53 insertions(+), 6 deletions(-) create mode 100644 database/migrations/2023_08_14_142748_add_last_activity_tickets_table.php diff --git a/app/Http/Controllers/Bo/TicketController.php b/app/Http/Controllers/Bo/TicketController.php index 506918c..63412cc 100644 --- a/app/Http/Controllers/Bo/TicketController.php +++ b/app/Http/Controllers/Bo/TicketController.php @@ -541,7 +541,7 @@ class TicketController extends Controller Session::get('tickets.sort_way') ); } else { - $tickets->orderBy('id', 'DESC'); + $tickets->orderBy('last_activity', 'DESC'); } return $tickets; } diff --git a/app/Models/Message.php b/app/Models/Message.php index ae3887c..41daedd 100644 --- a/app/Models/Message.php +++ b/app/Models/Message.php @@ -51,7 +51,9 @@ class Message extends Model $q->withTrashed(); }]); /** @var \App\Models\Ticket $ticket */ - $ticket = $message->ticket; + $ticket = $message->ticket; + $ticket->last_activity = $message->updated_at; + $ticket->saveQuietly(); if ($message->user) { $ticket->load(['user' => function ($q) { $q->withTrashed(); diff --git a/app/Models/Ticket.php b/app/Models/Ticket.php index ba3b00a..899e558 100644 --- a/app/Models/Ticket.php +++ b/app/Models/Ticket.php @@ -33,7 +33,8 @@ class Ticket extends Model 'type', 'status', 'text', - 'is_internal' + 'is_internal', + 'last_activity', ]; /** @@ -44,7 +45,8 @@ class Ticket extends Model protected $casts = [ 'is_internal' => 'bool', 'type' => TicketTypeEnum::class, - 'status' => TicketStatusEnum::class + 'status' => TicketStatusEnum::class, + 'last_activity' => 'timestamp', ]; /** diff --git a/database/migrations/2023_08_14_142748_add_last_activity_tickets_table.php b/database/migrations/2023_08_14_142748_add_last_activity_tickets_table.php new file mode 100644 index 0000000..e4b1128 --- /dev/null +++ b/database/migrations/2023_08_14_142748_add_last_activity_tickets_table.php @@ -0,0 +1,43 @@ +timestamp('last_activity') + ->default(Carbon::now()) + ->comment('Last activity on the ticket.') + ->after('is_internal'); + }); + Ticket::get()->map(function (object $ticket) { + $lastMessage = $ticket->messages->whereNotNull('user_id')->sortByDesc('updated_at')->first(); + $ticket->last_activity = + $lastMessage->updated_at ?? $ticket->updated_at; + $ticket->saveQuietly(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down(): void + { + Schema::table('tickets', function (Blueprint $table) { + $table->dropColumn('last_activity'); + }); + } +}; diff --git a/resources/views/bo/modules/pagination.blade.php b/resources/views/bo/modules/pagination.blade.php index 9326c83..687ca1b 100644 --- a/resources/views/bo/modules/pagination.blade.php +++ b/resources/views/bo/modules/pagination.blade.php @@ -31,7 +31,7 @@ @foreach (\App\Enums\ItemsPerPaginationEnum::toArray() as $itemsPerPaginationEnum)
  • {{ $itemsPerPaginationEnum->value }} diff --git a/resources/views/bo/pages/tickets/index.blade.php b/resources/views/bo/pages/tickets/index.blade.php index e0154ae..172473f 100644 --- a/resources/views/bo/pages/tickets/index.blade.php +++ b/resources/views/bo/pages/tickets/index.blade.php @@ -172,7 +172,7 @@ $userPr = Auth::user()->sites ?? collect([]); @foreach ($ticket->labels as $label) - {{ $label->name }} + {{ $label->name }} @endforeach From 4f7f12de59d2ec2ad0eda6289f1d09cc48b2c345 Mon Sep 17 00:00:00 2001 From: Alexis Gousseau Date: Mon, 14 Aug 2023 17:48:26 +0000 Subject: [PATCH 4/5] add status on invoices - issue #19 --- app/Enums/Invoices/InvoiceStatusEnum.php | 25 ++++ .../{Invoice => Invoices}/TaskTypeEnum.php | 2 +- app/Http/Controllers/Bo/InvoiceController.php | 16 ++- .../Bo/Invoices/StoreInvoiceRequest.php | 5 +- .../Bo/Invoices/UpdateInvoiceRequest.php | 39 +++-- app/Models/Company.php | 22 +++ app/Models/Invoice.php | 41 +++++- app/Models/Site.php | 22 +++ database/factories/InvoiceFactory.php | 96 ++++++++++--- ...022_08_23_085833_create_invoices_table.php | 2 +- ...08_14_100506_add_status_invoices_table.php | 37 +++++ .../ts/bo/components/CkEditorComponent.vue | 18 +-- resources/ts/utilities/fontawesome.ts | 4 + .../views/bo/pages/invoices/create.blade.php | 2 +- .../views/bo/pages/invoices/edit.blade.php | 8 +- .../bo/pages/invoices/form-inputs.blade.php | 136 +++++++++++------- .../views/bo/pages/invoices/index.blade.php | 30 +++- .../views/bo/pages/invoices/show.blade.php | 2 +- .../views/bo/partials/inputs/date.blade.php | 15 ++ .../breadcrumbs/breadcrumb-layout.blade.php | 2 +- resources/views/layout/nav.blade.php | 2 +- routes/breadcrumbs-bo.php | 3 +- 22 files changed, 419 insertions(+), 110 deletions(-) create mode 100644 app/Enums/Invoices/InvoiceStatusEnum.php rename app/Enums/{Invoice => Invoices}/TaskTypeEnum.php (97%) create mode 100644 database/migrations/2023_08_14_100506_add_status_invoices_table.php create mode 100644 resources/views/bo/partials/inputs/date.blade.php diff --git a/app/Enums/Invoices/InvoiceStatusEnum.php b/app/Enums/Invoices/InvoiceStatusEnum.php new file mode 100644 index 0000000..f9e0163 --- /dev/null +++ b/app/Enums/Invoices/InvoiceStatusEnum.php @@ -0,0 +1,25 @@ +name => "Ouvert (nouveaux ou en cours)", + self::refused->name => "Refusé (par le client ou aucune réponse de sa part)", + self::canceled->name => "Annulé (supprimé)", + self::archived->name => "Archivé (validé et envoyé à la comptabilité)", + ]; +} diff --git a/app/Enums/Invoice/TaskTypeEnum.php b/app/Enums/Invoices/TaskTypeEnum.php similarity index 97% rename from app/Enums/Invoice/TaskTypeEnum.php rename to app/Enums/Invoices/TaskTypeEnum.php index 1420f20..2b6c0b7 100644 --- a/app/Enums/Invoice/TaskTypeEnum.php +++ b/app/Enums/Invoices/TaskTypeEnum.php @@ -1,6 +1,6 @@ status); + $invoiceModels = $invoiceModels->when($status, function ($query) use ($status) { + $query->where('status', $status); + }); /** @var string $search Search field */ $search = $request->search; @@ -46,7 +51,7 @@ class InvoiceController extends Controller /** Custom pagination */ $invoiceModels = $this->customPaginate($invoiceModels, $request->pagination); - return view('bo.pages.invoices.index', compact('invoiceModels', 'search', 'searchFields')); + return view('bo.pages.invoices.index', compact('invoiceModels', 'search', 'searchFields', 'status')); } /** @@ -79,6 +84,7 @@ class InvoiceController extends Controller 'packageModels' => $packageModels, 'siteModels' => $siteModels, 'companyModels' => $companyModels, + 'invoiceStatusArray' => $invoice->getInvoiceStatusArray($invoice), ]); } @@ -130,6 +136,7 @@ class InvoiceController extends Controller 'packageModels' => $packageModels, 'siteModels' => $siteModels, 'companyModels' => $companyModels, + 'invoiceStatusArray' => $invoice->getInvoiceStatusArray($invoice), ]); } @@ -143,12 +150,7 @@ class InvoiceController extends Controller public function update(UpdateInvoiceRequest $request, Invoice $invoice): \Illuminate\Http\RedirectResponse { return DB::transaction(function () use ($request, $invoice) { - if (isset($invoice->signed_date)) { - $fields = $request->safe()->only('signed_date', 'sent_client_date', 'sent_accounting_date'); - } else { - $fields = $request->validated(); - } - $invoice->fill($fields); + $invoice->fill(($invoice->status->value === InvoiceStatusEnum::opened->value) ? $request->validated() : []); if ($invoice->saveOrFail()) { return redirect() ->route('bo.invoices.edit', $invoice) diff --git a/app/Http/Requests/Bo/Invoices/StoreInvoiceRequest.php b/app/Http/Requests/Bo/Invoices/StoreInvoiceRequest.php index 824a742..d20ddd9 100644 --- a/app/Http/Requests/Bo/Invoices/StoreInvoiceRequest.php +++ b/app/Http/Requests/Bo/Invoices/StoreInvoiceRequest.php @@ -2,7 +2,7 @@ namespace App\Http\Requests\Bo\Invoices; -use App\Enums\Invoice\TaskTypeEnum; +use App\Enums\Invoices\TaskTypeEnum; use App\Models\Invoice; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Facades\Gate; @@ -90,7 +90,8 @@ class StoreInvoiceRequest extends FormRequest 'invoiced_to_id' => trans('Entité à facturer'), 'signed_date' => trans('Date de signature du Devis'), 'sent_client_date' => trans('Date d\'envoi du Devis au client'), - 'sent_accounting_date' => trans('Date d\'envoi du Devis à la compta'), + 'sent_accounting_date' => trans('Date d\'envoi du Devis à la comptabilité'), + 'status' => trans('État du devis'), ]; } } diff --git a/app/Http/Requests/Bo/Invoices/UpdateInvoiceRequest.php b/app/Http/Requests/Bo/Invoices/UpdateInvoiceRequest.php index bef04c2..338d9eb 100644 --- a/app/Http/Requests/Bo/Invoices/UpdateInvoiceRequest.php +++ b/app/Http/Requests/Bo/Invoices/UpdateInvoiceRequest.php @@ -2,6 +2,9 @@ namespace App\Http\Requests\Bo\Invoices; +use App\Enums\Invoices\InvoiceStatusEnum; +use Illuminate\Validation\Rules\Enum; + class UpdateInvoiceRequest extends StoreInvoiceRequest { /** @@ -12,14 +15,34 @@ class UpdateInvoiceRequest extends StoreInvoiceRequest public function rules() { $rules = []; - if (!$this->route('invoice')->signed_date) { - $rules = array_merge($rules, parent::rules()); - } - $rules = array_merge($rules, [ - 'signed_date' => 'sometimes|nullable|date', - 'sent_client_date' => 'sometimes|nullable|date', - 'sent_accounting_date' => 'sometimes|nullable|date', - ]); + $model = $this->route('invoice'); + if ($model->status->value === InvoiceStatusEnum::opened->value) { + if (!$model->sent_client_date) { + $rules = array_merge($rules, parent::rules()); + } + $rules = array_merge($rules, [ + 'sent_client_date' => 'required_with:signed_date,sent_accounting_date|sometimes|nullable|date', + 'signed_date' => 'required_with:sent_accounting_date|sometimes|nullable|date', + 'sent_accounting_date' => 'sometimes|nullable|date', + 'status' => [ + 'required', + new Enum(InvoiceStatusEnum::class), + //phpcs:disable Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed + function ($attribute, $value, $fail) use ($model) { + if ( + (intval($value) === InvoiceStatusEnum::archived->value) && + (is_null($model->sent_client_date) || + is_null($model->signed_date) || + is_null($model->sent_accounting_date)) + ) { + $fail(__('Le status :status doit être assigné lorsque les 3 dates sont saisies', [ + 'status' => InvoiceStatusEnum::archived->label() + ])); + } + }, + ], + ]); + } //end if return $rules; } } diff --git a/app/Models/Company.php b/app/Models/Company.php index 06b583b..63cd49d 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Casts\Attribute; /** * @property string $name @@ -21,6 +22,15 @@ class Company extends Model 'name' ]; + /** + * The accessors to append to the model's array form. + * + * @var array + */ + protected $appends = [ + 'value' + ]; + /** * HasMany Invoices * @@ -30,4 +40,16 @@ class Company extends Model { return $this->hasMany(Invoice::class); } + + /** + * Return value attribute for belongsto search component + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute + */ + protected function value(): Attribute + { + return new Attribute( + get: fn () => $this->id, + ); + } } diff --git a/app/Models/Invoice.php b/app/Models/Invoice.php index 90abab3..44c5ca3 100644 --- a/app/Models/Invoice.php +++ b/app/Models/Invoice.php @@ -2,7 +2,8 @@ namespace App\Models; -use App\Enums\Invoice\TaskTypeEnum; +use App\Enums\Invoices\TaskTypeEnum; +use App\Enums\Invoices\InvoiceStatusEnum; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Support\Carbon; @@ -26,6 +27,7 @@ use Mccarlosen\LaravelMpdf\LaravelMpdf; * @property Site $site_id * @property Company $company_id * @property Company $invoiced_to_id + * @property InvoiceStatusEnum $status */ class Invoice extends Model { @@ -51,7 +53,8 @@ class Invoice extends Model 'sent_accounting_date', 'site_id', 'company_id', - 'invoiced_to_id' + 'invoiced_to_id', + 'status', ]; /** @@ -64,6 +67,7 @@ class Invoice extends Model 'signed_date' => 'date', 'sent_client_date' => 'date', 'sent_accounting_date' => 'date', + 'status' => InvoiceStatusEnum::class, ]; /** @@ -92,6 +96,7 @@ class Invoice extends Model ->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) @@ -215,4 +220,36 @@ class Invoice extends Model ); 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'], + ]); + } } diff --git a/app/Models/Site.php b/app/Models/Site.php index 89c2581..3e005af 100644 --- a/app/Models/Site.php +++ b/app/Models/Site.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Casts\Attribute; /** * @property string $name @@ -22,6 +23,15 @@ class Site extends Model 'name', ]; + /** + * The accessors to append to the model's array form. + * + * @var array + */ + protected $appends = [ + 'value' + ]; + // * RELATIONSHIPS /** @@ -64,4 +74,16 @@ class Site extends Model { return $this->belongsTo(Project::class); } + + /** + * Return value attribute for belongsto search component + * + * @return \Illuminate\Database\Eloquent\Casts\Attribute + */ + protected function value(): Attribute + { + return new Attribute( + get: fn () => $this->id, + ); + } } diff --git a/database/factories/InvoiceFactory.php b/database/factories/InvoiceFactory.php index 88673c3..d41b89c 100644 --- a/database/factories/InvoiceFactory.php +++ b/database/factories/InvoiceFactory.php @@ -2,7 +2,8 @@ namespace Database\Factories; -use App\Enums\Invoice\TaskTypeEnum; +use App\Enums\Invoices\TaskTypeEnum; +use App\Enums\Invoices\InvoiceStatusEnum; use App\Models\Invoice; use App\Models\Package; use Illuminate\Database\Eloquent\Factories\Factory; @@ -16,18 +17,58 @@ class InvoiceFactory extends Factory */ protected $model = Invoice::class; + /** + * A JSON object, each line has to be contructed using these + * fields description, days, type Invoice\TaskType, amount. + * + * @var array + */ + protected $tasks = []; + + /** + * The total calculated using all tasks. + * + * @var float + */ + protected $total = 0; + + /** + * The total days calculated using all tasks. + * + * @var float + */ + protected $totalDays = 0; + + /** + * The date of the signing. + * + * @var boolean + */ + protected $signedDateBoolean = 0; + + /** + * The date of the shipping to the client. + * + * @var boolean + */ + protected $sentClientDateBoolean = 0; + + /** + * The date of the shipping to the accounting. + * + * @var boolean + */ + protected $sentAccountingDateBoolean = 0; + /** * Define the model's default state. * - * @return array + * @return void */ - public function definition() + private function customData(): void { \mt_srand(); - $lines = \mt_rand(2, 9); - $tasks = []; - $total = 0; - $totalDays = 0; + $lines = \mt_rand(2, 9); for ($i = 0; $i < $lines; $i++) { $days = 0.125 * $this->faker->numberBetween(1, 4); $type = \collect(TaskTypeEnum::cases())->random(); @@ -47,37 +88,54 @@ class InvoiceFactory extends Factory $amount = $days * $this->faker->randomFloat(null, 150, 650); break; } - $totalDays += $days; - $total += $amount; - /** @var \App\Enums\Invoice\TaskTypeEnum */ - $taskType = \collect(TaskTypeEnum::cases())->random(); - $tasks[] = \array_merge(Invoice::getTaskStructure(), [ + $this->totalDays += $days; + $this->total += $amount; + /** @var \App\Enums\Invoices\TaskTypeEnum */ + $this->tasks[] = \array_merge(Invoice::getTaskStructure(), [ 'desc' => $this->faker->words(9, true), 'days' => $days, - 'type' => $taskType->value, + 'type' => \collect(TaskTypeEnum::cases())->random()->value, 'amount' => $amount, 'package' => 1 ]); + /** Dates */ + $this->signedDateBoolean = $this->faker->boolean(25); + $this->sentClientDateBoolean = $this->faker->boolean(25); + $this->sentAccountingDateBoolean = $this->faker->boolean(25); } //end for + } + /** + * Define the model's default state. + * + * @return array + */ + public function definition() + { + $this->customData(); return [ 'firstname' => $this->faker->firstName, 'lastname' => $this->faker->lastName, 'object' => $this->faker->words(3, true), // * constructed object - 'tasks' => $tasks, + 'tasks' => $this->tasks, // * constructed object result - 'total' => $total, + 'total' => $this->total, // * constructed object result - 'total_days' => $totalDays, + 'total_days' => $this->totalDays, 'comment' => $this->faker->text(\rand(20, 40)), 'show_days' => $this->faker->boolean(75), - 'signed_date' => $this->faker->boolean(25) ? + 'signed_date' => + $this->signedDateBoolean ? $this->faker->dateTimeBetween('-1 year', '+1 year') : null, - 'sent_client_date' => $this->faker->boolean(25) ? + 'sent_client_date' => + $this->signedDateBoolean && $this->sentClientDateBoolean ? $this->faker->dateTimeBetween('-1 year', '+1 year') : null, - 'sent_accounting_date' => $this->faker->boolean(25) ? + 'sent_accounting_date' => + $this->signedDateBoolean && $this->sentClientDateBoolean && $this->sentAccountingDateBoolean ? $this->faker->dateTimeBetween('-1 year', '+1 year') : null, + 'status' => $this->signedDateBoolean && $this->sentClientDateBoolean && $this->sentAccountingDateBoolean ? + InvoiceStatusEnum::archived : InvoiceStatusEnum::opened, ]; } } diff --git a/database/migrations/2022_08_23_085833_create_invoices_table.php b/database/migrations/2022_08_23_085833_create_invoices_table.php index a0db936..c079c23 100644 --- a/database/migrations/2022_08_23_085833_create_invoices_table.php +++ b/database/migrations/2022_08_23_085833_create_invoices_table.php @@ -34,7 +34,7 @@ class CreateInvoicesTable extends Migration $table->text('tasks') ->comment( // phpcs:ignore Generic.Files.LineLength.TooLong - 'A JSON object, each line has to be contructed using these fields description, days, type Invoice\TaskTypeEnum, amount' + 'A JSON object, each line has to be contructed using these fields description, days, type Invoices\TaskTypeEnum, amount' ); $table->unsignedFloat('total')->comment('The total calculated using all tasks'); diff --git a/database/migrations/2023_08_14_100506_add_status_invoices_table.php b/database/migrations/2023_08_14_100506_add_status_invoices_table.php new file mode 100644 index 0000000..4b8d827 --- /dev/null +++ b/database/migrations/2023_08_14_100506_add_status_invoices_table.php @@ -0,0 +1,37 @@ +unsignedTinyInteger('status') + ->default(InvoiceStatusEnum::opened->value) + ->comment('Status of the invoice.') + ->after('invoiced_to_id'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down(): void + { + Schema::table('invoices', function (Blueprint $table) { + $table->dropColumn('status'); + }); + } +}; diff --git a/resources/ts/bo/components/CkEditorComponent.vue b/resources/ts/bo/components/CkEditorComponent.vue index 529910a..dc84daf 100644 --- a/resources/ts/bo/components/CkEditorComponent.vue +++ b/resources/ts/bo/components/CkEditorComponent.vue @@ -28,15 +28,6 @@ export default defineComponent({ throw new Error("this component requires json"); } }, - mounted() { - const json = String(this.$attrs.json ?? "{}"), - data = JSON.parse(json); - this.name = data.name; - this.internalText = data.text ? String(data.text) : ""; - this.internalId = data.id ? data.id : ""; - this.internalRequired = Boolean(data.required); - this.makeSuperBuild(); - }, data(): { name: string; internalText: string; @@ -57,6 +48,15 @@ export default defineComponent({ chars: 0, }; }, + mounted() { + const json = String(this.$attrs.json ?? "{}"), + data = JSON.parse(json); + this.name = data.name; + this.internalText = data.text ? String(data.text) : ""; + this.internalId = data.id ? data.id : ""; + this.internalRequired = Boolean(data.required); + this.makeSuperBuild(); + }, watch: { dbtext() { if (this.internalText != this.dbtext) { diff --git a/resources/ts/utilities/fontawesome.ts b/resources/ts/utilities/fontawesome.ts index 9e6b5d1..35cf7a7 100644 --- a/resources/ts/utilities/fontawesome.ts +++ b/resources/ts/utilities/fontawesome.ts @@ -8,7 +8,9 @@ import { faArrowRightLong, faArrowUp, faBan, + faBox, faBoxArchive, + faBoxOpen, faChevronLeft, faChevronRight, faClipboard, @@ -43,7 +45,9 @@ import { config.autoReplaceSvg = false; library.add(faTags); library.add(faSquarePlus); +library.add(faBox); library.add(faBoxArchive); +library.add(faBoxOpen); library.add(faEraser); library.add(faSignHanging); library.add(faDiagramProject); diff --git a/resources/views/bo/pages/invoices/create.blade.php b/resources/views/bo/pages/invoices/create.blade.php index 113c923..5293e1f 100644 --- a/resources/views/bo/pages/invoices/create.blade.php +++ b/resources/views/bo/pages/invoices/create.blade.php @@ -7,7 +7,7 @@ @section('content')
    -
    - + @if($invoiceModel->status->value === \App\Enums\Invoices\InvoiceStatusEnum::opened->value) + @endif
    +@if($invoiceModel->status->value === \App\Enums\Invoices\InvoiceStatusEnum::opened->value)
    @csrf @method('PUT') @@ -53,4 +56,7 @@
    +@else +@include('bo.pages.invoices.form-inputs') +@endif @endsection diff --git a/resources/views/bo/pages/invoices/form-inputs.blade.php b/resources/views/bo/pages/invoices/form-inputs.blade.php index b3e5c3f..731db72 100644 --- a/resources/views/bo/pages/invoices/form-inputs.blade.php +++ b/resources/views/bo/pages/invoices/form-inputs.blade.php @@ -1,41 +1,30 @@
    + {{-- DATES/STATUS --}} @if (request()->routeIs('bo.invoices.edit')) + @if($invoiceModel->status !== \App\Enums\Invoices\InvoiceStatusEnum::opened || $invoiceModel->signed_date) +
    + +
    + @endif {{-- DATES STATUS --}}
    - {{ __('Dates') }} + {{ __('État') }}
    - @if($invoiceModel->signed_date) -
    - -
    - @endif - {{-- SIGNED_DATE --}} -
    - @if(!$invoiceModel->signed_date) - @include('bo.partials.inputs.timestamp-datetime', [ - 'id' => 'invoiceSigneddate', - 'label' => __('Date d\'envoi du :model', [ - 'model' => __('models.classes.invoices'), - ]), - 'name' => 'signed_date', - 'defaultValue' => false, - 'required' => true, - 'model' => $invoiceModel ?? null, - 'helper' => __('Doît être une date réelle et existante.'), - ]) - @else -

    {{ __('Envoyé le :date', ['date' => $invoiceModel->signed_date]) }}

    - @endif -
    {{-- SENT_CLIENT_DATE --}}
    - @if(!$invoiceModel->sent_client_date) - @include('bo.partials.inputs.timestamp-datetime', [ + @if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened AND !$invoiceModel->sent_client_date ) + @include('bo.partials.inputs.date', [ 'id' => 'invoiceSentclientdate', - 'label' => __('Date de signature du :model (client)', [ + 'label' => __('Date d\'envoi du :model', [ 'model' => __('models.classes.invoices'), ]), 'name' => 'sent_client_date', @@ -44,16 +33,38 @@ 'model' => $invoiceModel ?? null, 'helper' => __('Doît être une date réelle et existante.'), ]) - @else -

    {{ __('Signé le :date (client)', ['date' => $invoiceModel->sent_client_date]) }}

    + @elseif ($invoiceModel->sent_client_date) +

    + {{ __('Envoyé le :date', ['date' => \Carbon\Carbon::parse($invoiceModel->sent_client_date)->format('d/m/Y')]) ?? "xxx" }} +

    + @endif +
    + {{-- SIGNED_DATE --}} +
    + @if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened AND !$invoiceModel->signed_date) + @include('bo.partials.inputs.date', [ + 'id' => 'invoiceSigneddate', + 'label' => __('Date de signature du :model (client)', [ + 'model' => __('models.classes.invoices'), + ]), + 'name' => 'signed_date', + 'defaultValue' => false, + 'required' => true, + 'model' => $invoiceModel ?? null, + 'helper' => __('Doît être une date réelle et existante.'), + ]) + @elseif ($invoiceModel->signed_date) +

    + {{ __('Signé le :date (client)', ['date' => \Carbon\Carbon::parse($invoiceModel->signed_date)->format('d/m/Y') ?? "xxx"]) }} +

    @endif
    {{-- SENT_ACCOUNTING_DATE --}}
    - @if(!$invoiceModel->sent_accounting_date) - @include('bo.partials.inputs.timestamp-datetime', [ + @if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened AND !$invoiceModel->sent_accounting_date) + @include('bo.partials.inputs.date', [ 'id' => 'invoiceSentaccountingdate', - 'label' => __('Date d\'envoi du :model à la compta', [ + 'label' => __('Date d\'envoi du :model à la comptabilité', [ 'model' => __('models.classes.invoices'), ]), 'name' => 'sent_accounting_date', @@ -62,17 +73,40 @@ 'model' => $invoiceModel ?? null, 'helper' => __('Doît être une date réelle et existante.'), ]) - @else -

    {{ __('Envoyé à la compta le :date', ['date' => $invoiceModel->sent_accounting_date]) }}

    + @elseif ($invoiceModel->sent_accounting_date) +

    + {{ __('Envoyé à la comptabilité le :date', ['date' => \Carbon\Carbon::parse($invoiceModel->sent_accounting_date)->format('d/m/Y') ?? "xxx"]) }} +

    @endif
    + {{-- STATUS --}} + @if ($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened) +
    + @include('bo.partials.inputs.tinyint-enum', [ + 'id' => 'invoiceStatus', + 'label' => __('crud.minicrud.associated', [ + 'entity' => 'État', + ]), + 'name' => 'status', + 'model' => $invoiceModel ?? null, + 'required' => true, + 'associatedModels' => $invoiceStatusArray, + 'helper' => __('crud.minicrud.select', [ + 'entity' => 'État', + ]), + ]) + @else +
    +

    {{ $invoiceModel->status->label() }}

    + @endif +
    @endif {{-- USER ASSOCIATED --}}
    -
    signed_date) disabled @endif> +
    sent_client_date) disabled @endif> {{ __('Informations sur la personne associée') }}
    {{-- FIRSTNAME --}} @@ -126,7 +160,7 @@
    {{-- OBJECT --}}
    -
    signed_date) disabled @endif> +
    sent_client_date) disabled @endif> {{ Str::ucfirst(__('validation.attributes.object')) }}
    @@ -156,7 +190,7 @@
    {{-- TASKS --}}
    -
    signed_date) disabled @endif> +
    sent_client_date) disabled @endif> {{ __('validation.attributes.tasks') }}
    @@ -164,7 +198,7 @@ $data = [ 'companies' => $companyModels, 'packages' => $packageModels, - 'taskTypeEnums' => collect(\App\Enums\Invoice\TaskTypeEnum::toArray())->values(), + 'taskTypeEnums' => collect(\App\Enums\Invoices\TaskTypeEnum::toArray())->values(), 'taskRowModel' => $taskRowModel, 'tasks' => $invoiceModel->tasks ?? [] ]; @@ -176,10 +210,13 @@
    {{-- COMMENT --}}
    -
    signed_date) disabled @endif> +
    {{ Str::ucfirst(__('validation.attributes.comment')) }}
    + @if($invoiceModel->sent_client_date) + + @else @include('bo.partials.inputs.text-html', [ 'id' => 'invoiceComment', 'label' => __('Commentaire du :model', [ @@ -187,18 +224,19 @@ ]), 'name' => 'comment', 'model' => $invoiceModel, - 'required' => true, + 'required' => false, 'helper' => __('crud.minicrud.text_warning', [ 'number' => 15 ]), ]) + @endif
    {{-- SITE_ID --}}
    -
    signed_date) disabled @endif> +
    sent_client_date) disabled @endif> {{ Str::singular(trans('models.classes.sites')) }}
    @@ -212,7 +250,7 @@ 'routeName' => 'invoices.json-paginate', 'modelRelated' => $siteModels ?? [], 'modelSelected' => $invoiceModel->site ?? [], - 'readonly' => ($invoiceModel->signed_date) ? true : false, + 'readonly' => ($invoiceModel->sent_client_date) ? true : false, 'placeholder' => __('Rechercher une :model', [ 'model' => Str::singular(trans('models.classes.sites')), ]), @@ -227,7 +265,7 @@
    {{-- COMPANY_ID --}}
    -
    signed_date) disabled @endif> +
    sent_client_date) disabled @endif> {{ Str::singular(trans('models.classes.companies')) }}
    @@ -241,7 +279,7 @@ 'routeName' => 'invoices.json-paginate', 'modelRelated' => $companyModels ?? [], 'modelSelected' => $invoiceModel->company ?? [], - 'readonly' => ($invoiceModel->signed_date) ? true : false, + 'readonly' => ($invoiceModel->sent_client_date) ? true : false, 'placeholder' => __('Rechercher une :model', [ 'model' => Str::singular(trans('models.classes.companies')), ]), @@ -268,7 +306,7 @@ 'routeName' => 'invoices.json-paginate', 'modelRelated' => $companyModels ?? [], 'modelSelected' => $invoiceModel->companyInvoiced ?? [], - 'readonly' => ($invoiceModel->signed_date) ? true : false, + 'readonly' => ($invoiceModel->sent_client_date) ? true : false, 'placeholder' => __('Rechercher une :model', [ 'model' => Str::singular(trans('models.classes.companies')), ]), @@ -283,7 +321,7 @@
    {{-- SHOW DAYS --}}
    -
    signed_date) disabled @endif> +
    sent_client_date) disabled @endif> {{ __('Visibilité') }}
    @@ -302,6 +340,7 @@
    +@if($invoiceModel->status === \App\Enums\Invoices\InvoiceStatusEnum::opened) @push('scripts') @endpush +@endif diff --git a/resources/views/bo/pages/invoices/index.blade.php b/resources/views/bo/pages/invoices/index.blade.php index f15ce37..1881c1e 100644 --- a/resources/views/bo/pages/invoices/index.blade.php +++ b/resources/views/bo/pages/invoices/index.blade.php @@ -6,13 +6,29 @@ @section('content')
    @include('breadcrumbs.breadcrumb-body') - - - +
    +
    + + @push('scripts') + + @endpush + + + +
    +
    @include('bo.modules.search-bar') diff --git a/resources/views/bo/pages/invoices/show.blade.php b/resources/views/bo/pages/invoices/show.blade.php index 69c0280..29a322b 100644 --- a/resources/views/bo/pages/invoices/show.blade.php +++ b/resources/views/bo/pages/invoices/show.blade.php @@ -7,7 +7,7 @@ @section('content')
    - + {{ $label }} + + +@include('modules.input-error', [ + 'inputName' => $name, + 'helperId' => "{$id}Help", + 'helper' => $helper +]) diff --git a/resources/views/breadcrumbs/breadcrumb-layout.blade.php b/resources/views/breadcrumbs/breadcrumb-layout.blade.php index 2cba069..e9ff09d 100644 --- a/resources/views/breadcrumbs/breadcrumb-layout.blade.php +++ b/resources/views/breadcrumbs/breadcrumb-layout.blade.php @@ -1,5 +1,5 @@ @if (count($breadcrumbs)) -
    + {{-- GITLAB_PROJECT_ID --}} +
    +
    + {{ Str::ucfirst(__('validation.attributes.gitlab_project_id')) }} +
    +
    + @include('bo.partials.inputs.int-number', [ + 'id' => 'siteGitlabProject', + 'label' => __(':field du :model', [ + 'field' => Str::ucfirst(__('validation.attributes.gitlab_project_id')), + 'model' => Str::singular(__('models.classes.sites')), + ]), + 'name' => 'gitlab_project_id', + 'required' => true, + 'model' => $siteModel ?? null, + 'helper' => __('validation.integer', [ + 'attribute' => __(':field du :model', [ + 'field' => Str::ucfirst(__('validation.attributes.gitlab_project_id')), + 'model' => Str::singular(__('models.classes.sites')), + ]), + ]), + 'step' => 1, + 'min' => 1 + ]) +
    +
    +
    +
    @push('scripts') diff --git a/resources/views/bo/pages/tickets/show.blade.php b/resources/views/bo/pages/tickets/show.blade.php index f448edd..8fa0819 100644 --- a/resources/views/bo/pages/tickets/show.blade.php +++ b/resources/views/bo/pages/tickets/show.blade.php @@ -256,4 +256,18 @@ @endif +@can('createGitlabIssue', $ticket) + + @csrf + + +@else + @if (!\is_null($ticket->gitlab_issue)) +
    +

    + {{ __("Lien vers l'issue Gitlab : ")}} + {{ __("Ouvrir") }} +

    + @endif +@endcan @endsection diff --git a/routes/web-bo.php b/routes/web-bo.php index 9d83548..241f6fd 100644 --- a/routes/web-bo.php +++ b/routes/web-bo.php @@ -90,7 +90,10 @@ Route::middleware('admin-secure') // * TICKETS Route::get('/tickets/json/paginate', [TicketController::class, 'jsonPaginate']) - ->name('tickets.json-paginate'); + ->name('tickets.json-paginate'); + Route::post('/ticket/{ticket}/create-issue', [TicketController::class, 'createGitlabIssue']) + ->middleware('can:createGitlabIssue,ticket') + ->name('ticket.create-issue'); // * SCHEDULE Route::prefix('/schedule')