From 8074ac4f4861177b038143bb9ccfa6f1306bc162 Mon Sep 17 00:00:00 2001 From: nyavokevin Date: Thu, 5 Mar 2026 17:00:32 +0300 Subject: [PATCH] FIX: Creation demande, client on clique show --- .../Controllers/Api/ClientGroupController.php | 42 + .../Requests/AssignClientsToGroupRequest.php | 42 + thanasoft-back/app/Models/ClientGroup.php | 13 + thanasoft-back/app/Models/PriceList.php | 36 + thanasoft-back/app/Models/Product.php | 11 + ..._03_04_140000_create_price_lists_table.php | 31 + ...d_price_list_id_to_client_groups_table.php | 33 + ...140200_create_product_price_list_table.php | 32 + thanasoft-back/routes/api.php | 1 + .../Agenda/InterventionMultiStepModal.vue | 1914 +++++++++-------- .../Organism/CRM/FournisseurPresentation.vue | 2 - .../ClientGroupListPresentation.vue | 28 +- .../Commande/CommandeDetailPresentation.vue | 3 +- .../Planning/PlanningNewRequestModal.vue | 26 +- .../Stock/ReceptionDetailPresentation.vue | 46 +- .../Planning/PlanningCreationTypeSelector.vue | 24 +- .../molecules/Planning/PlanningEventForm.vue | 9 +- .../molecules/Planning/PlanningKanban.vue | 776 +++++-- .../Planning/PlanningLeaveRequestForm.vue | 33 +- .../molecules/Planning/PlanningWeekGrid.vue | 682 +++++- .../Tables/ClientGroup/ClientGroupTable.vue | 353 ++- thanasoft-front/src/views/pages/Planning.vue | 287 ++- 22 files changed, 2982 insertions(+), 1442 deletions(-) create mode 100644 thanasoft-back/app/Http/Requests/AssignClientsToGroupRequest.php create mode 100644 thanasoft-back/app/Models/PriceList.php create mode 100644 thanasoft-back/database/migrations/2026_03_04_140000_create_price_lists_table.php create mode 100644 thanasoft-back/database/migrations/2026_03_04_140100_add_price_list_id_to_client_groups_table.php create mode 100644 thanasoft-back/database/migrations/2026_03_04_140200_create_product_price_list_table.php diff --git a/thanasoft-back/app/Http/Controllers/Api/ClientGroupController.php b/thanasoft-back/app/Http/Controllers/Api/ClientGroupController.php index 8f34a93..14dde48 100644 --- a/thanasoft-back/app/Http/Controllers/Api/ClientGroupController.php +++ b/thanasoft-back/app/Http/Controllers/Api/ClientGroupController.php @@ -5,9 +5,11 @@ declare(strict_types=1); namespace App\Http\Controllers\Api; use App\Http\Controllers\Controller; +use App\Http\Requests\AssignClientsToGroupRequest; use App\Http\Requests\StoreClientGroupRequest; use App\Http\Requests\UpdateClientGroupRequest; use App\Http\Resources\Client\ClientGroupResource; +use App\Models\Client; use App\Repositories\ClientGroupRepositoryInterface; use Illuminate\Http\JsonResponse; use Illuminate\Http\Resources\Json\AnonymousResourceCollection; @@ -153,4 +155,44 @@ class ClientGroupController extends Controller ], 500); } } + + /** + * Assign many clients to one client group. + */ + public function assignClients(AssignClientsToGroupRequest $request, string $id): JsonResponse + { + try { + $clientGroup = $this->clientGroupRepository->find($id); + + if (!$clientGroup) { + return response()->json([ + 'message' => 'Groupe de clients non trouvé.', + ], 404); + } + + $clientIds = $request->validated('client_ids'); + + $updatedCount = Client::query() + ->whereIn('id', $clientIds) + ->update(['group_id' => $clientGroup->id]); + + return response()->json([ + 'message' => 'Clients assignés au groupe avec succès.', + 'assigned_count' => $updatedCount, + 'group' => new ClientGroupResource($clientGroup), + ]); + } catch (\Exception $e) { + Log::error('Error assigning clients to group: ' . $e->getMessage(), [ + 'exception' => $e, + 'trace' => $e->getTraceAsString(), + 'client_group_id' => $id, + 'data' => $request->validated(), + ]); + + return response()->json([ + 'message' => 'Une erreur est survenue lors de l’assignation des clients au groupe.', + 'error' => config('app.debug') ? $e->getMessage() : null, + ], 500); + } + } } diff --git a/thanasoft-back/app/Http/Requests/AssignClientsToGroupRequest.php b/thanasoft-back/app/Http/Requests/AssignClientsToGroupRequest.php new file mode 100644 index 0000000..f8fc207 --- /dev/null +++ b/thanasoft-back/app/Http/Requests/AssignClientsToGroupRequest.php @@ -0,0 +1,42 @@ +|string> + */ + public function rules(): array + { + return [ + 'client_ids' => 'required|array|min:1', + 'client_ids.*' => 'integer|distinct|exists:clients,id', + ]; + } + + public function messages(): array + { + return [ + 'client_ids.required' => 'La liste des clients est obligatoire.', + 'client_ids.array' => 'La liste des clients doit être un tableau.', + 'client_ids.min' => 'Veuillez sélectionner au moins un client.', + 'client_ids.*.integer' => 'Chaque ID client doit être un entier.', + 'client_ids.*.distinct' => 'Un client ne peut pas être envoyé plusieurs fois.', + 'client_ids.*.exists' => 'Un ou plusieurs clients sélectionnés sont introuvables.', + ]; + } +} + diff --git a/thanasoft-back/app/Models/ClientGroup.php b/thanasoft-back/app/Models/ClientGroup.php index 3cc69a8..c45b017 100644 --- a/thanasoft-back/app/Models/ClientGroup.php +++ b/thanasoft-back/app/Models/ClientGroup.php @@ -3,11 +3,24 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\HasMany; class ClientGroup extends Model { protected $fillable = [ 'name', 'description', + 'price_list_id', ]; + + public function priceList(): BelongsTo + { + return $this->belongsTo(PriceList::class, 'price_list_id'); + } + + public function clients(): HasMany + { + return $this->hasMany(Client::class, 'group_id'); + } } diff --git a/thanasoft-back/app/Models/PriceList.php b/thanasoft-back/app/Models/PriceList.php new file mode 100644 index 0000000..735d341 --- /dev/null +++ b/thanasoft-back/app/Models/PriceList.php @@ -0,0 +1,36 @@ + 'date', + 'valid_to' => 'date', + 'is_default' => 'boolean', + ]; + + public function clientGroups(): HasMany + { + return $this->hasMany(ClientGroup::class, 'price_list_id'); + } + + public function products(): BelongsToMany + { + return $this->belongsToMany(Product::class, 'product_price_list') + ->withPivot('price') + ->withTimestamps(); + } +} + diff --git a/thanasoft-back/app/Models/Product.php b/thanasoft-back/app/Models/Product.php index 0f46b60..758c50e 100644 --- a/thanasoft-back/app/Models/Product.php +++ b/thanasoft-back/app/Models/Product.php @@ -4,6 +4,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\BelongsToMany; use Illuminate\Support\Facades\Storage; class Product extends Model @@ -131,6 +132,16 @@ class Product extends Model return $this->hasMany(GoodsReceiptLine::class); } + /** + * Price lists attached to this product with custom price. + */ + public function priceLists(): BelongsToMany + { + return $this->belongsToMany(PriceList::class, 'product_price_list') + ->withPivot('price') + ->withTimestamps(); + } + /** * Boot the model */ diff --git a/thanasoft-back/database/migrations/2026_03_04_140000_create_price_lists_table.php b/thanasoft-back/database/migrations/2026_03_04_140000_create_price_lists_table.php new file mode 100644 index 0000000..d8c5065 --- /dev/null +++ b/thanasoft-back/database/migrations/2026_03_04_140000_create_price_lists_table.php @@ -0,0 +1,31 @@ +id(); + $table->string('name', 191); + $table->date('valid_from')->nullable(); + $table->date('valid_to')->nullable(); + $table->boolean('is_default')->default(false); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('price_lists'); + } +}; + diff --git a/thanasoft-back/database/migrations/2026_03_04_140100_add_price_list_id_to_client_groups_table.php b/thanasoft-back/database/migrations/2026_03_04_140100_add_price_list_id_to_client_groups_table.php new file mode 100644 index 0000000..09fdd35 --- /dev/null +++ b/thanasoft-back/database/migrations/2026_03_04_140100_add_price_list_id_to_client_groups_table.php @@ -0,0 +1,33 @@ +foreignId('price_list_id') + ->nullable() + ->after('description') + ->constrained('price_lists') + ->nullOnDelete(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('client_groups', function (Blueprint $table) { + $table->dropForeign(['price_list_id']); + $table->dropColumn('price_list_id'); + }); + } +}; + diff --git a/thanasoft-back/database/migrations/2026_03_04_140200_create_product_price_list_table.php b/thanasoft-back/database/migrations/2026_03_04_140200_create_product_price_list_table.php new file mode 100644 index 0000000..859cc1c --- /dev/null +++ b/thanasoft-back/database/migrations/2026_03_04_140200_create_product_price_list_table.php @@ -0,0 +1,32 @@ +id(); + $table->foreignId('product_id')->constrained('products')->cascadeOnDelete(); + $table->foreignId('price_list_id')->constrained('price_lists')->cascadeOnDelete(); + $table->decimal('price', 10, 2); + $table->timestamps(); + + $table->unique(['product_id', 'price_list_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('product_price_list'); + } +}; + diff --git a/thanasoft-back/routes/api.php b/thanasoft-back/routes/api.php index 57a96b1..f9af2fa 100644 --- a/thanasoft-back/routes/api.php +++ b/thanasoft-back/routes/api.php @@ -55,6 +55,7 @@ Route::middleware('auth:sanctum')->group(function () { Route::get('/clients/searchBy', [ClientController::class, 'searchBy']); Route::apiResource('clients', ClientController::class); + Route::post('client-groups/{id}/assign-clients', [ClientGroupController::class, 'assignClients']); Route::apiResource('client-groups', ClientGroupController::class); Route::apiResource('client-locations', ClientLocationController::class); diff --git a/thanasoft-front/src/components/Organism/Agenda/InterventionMultiStepModal.vue b/thanasoft-front/src/components/Organism/Agenda/InterventionMultiStepModal.vue index a4c7370..2093973 100644 --- a/thanasoft-front/src/components/Organism/Agenda/InterventionMultiStepModal.vue +++ b/thanasoft-front/src/components/Organism/Agenda/InterventionMultiStepModal.vue @@ -7,576 +7,440 @@ aria-labelledby="interventionModalLabel" aria-hidden="true" > -