From e0ccd5f627c121da354632674c0e4d2b36e624d9 Mon Sep 17 00:00:00 2001 From: kevin Date: Thu, 8 Jan 2026 17:18:49 +0300 Subject: [PATCH] Feat: migration client table, modification groupe client, child dans client --- .../Http/Controllers/Api/ClientController.php | 108 ++++++++++ .../Api/InterventionController.php | 70 ++++++- .../app/Http/Requests/StoreClientRequest.php | 5 +- .../app/Http/Requests/UpdateClientRequest.php | 2 + .../Http/Resources/Client/ClientResource.php | 3 + thanasoft-back/app/Models/Client.php | 13 ++ .../app/Repositories/ProductRepository.php | 11 + .../ProductRepositoryInterface.php | 2 + .../app/Repositories/QuoteRepository.php | 5 + ...945_add_parent_fields_to_clients_table.php | 30 +++ thanasoft-back/routes/api.php | 7 + .../Organism/CRM/ClientDetailPresentation.vue | 13 +- .../CRM/client/AddChildClientModal.vue | 110 ++++++++++ .../CRM/client/ClientDetailContent.vue | 6 + .../CRM/client/ClientDetailSidebar.vue | 10 + .../InterventionPresentation.vue | 146 ++++++++++++- .../molecules/Quote/QuoteLinesTable.vue | 5 +- .../molecules/Quote/QuoteSummary.vue | 11 +- .../molecules/client/ClientChildrenTab.vue | 198 ++++++++++++++++++ .../molecules/client/ClientSearchInput.vue | 131 ++++++++++++ .../molecules/client/ClientTabNavigation.vue | 15 ++ .../molecules/form/NewClientForm.vue | 92 ++++---- .../Interventions/InterventionsTemplate.vue | 5 +- thanasoft-front/src/services/client.ts | 42 ++++ thanasoft-front/src/stores/clientStore.ts | 72 +++++++ .../src/views/pages/CRM/ClientDetails.vue | 7 + .../pages/Interventions/Interventions.vue | 23 +- 27 files changed, 1076 insertions(+), 66 deletions(-) create mode 100644 thanasoft-back/database/migrations/2026_01_08_115945_add_parent_fields_to_clients_table.php create mode 100644 thanasoft-front/src/components/Organism/CRM/client/AddChildClientModal.vue create mode 100644 thanasoft-front/src/components/molecules/client/ClientChildrenTab.vue create mode 100644 thanasoft-front/src/components/molecules/client/ClientSearchInput.vue diff --git a/thanasoft-back/app/Http/Controllers/Api/ClientController.php b/thanasoft-back/app/Http/Controllers/Api/ClientController.php index 807165a..4e7986c 100644 --- a/thanasoft-back/app/Http/Controllers/Api/ClientController.php +++ b/thanasoft-back/app/Http/Controllers/Api/ClientController.php @@ -207,4 +207,112 @@ class ClientController extends Controller ], 500); } } + /** + * Change client status (active/inactive). + */ + public function changeStatus(Request $request, string $id): ClientResource|JsonResponse + { + try { + $isActive = $request->input('is_active'); + $updated = $this->clientRepository->update($id, ['is_active' => $isActive]); + + if (!$updated) { + return response()->json([ + 'message' => 'Client non trouvé ou échec de la mise à jour.', + ], 404); + } + + $client = $this->clientRepository->find($id); + return new ClientResource($client); + } catch (\Exception $e) { + Log::error('Error changing client status: ' . $e->getMessage(), [ + 'exception' => $e, + 'client_id' => $id, + ]); + return response()->json(['message' => 'Erreur serveur'], 500); + } + } + + /** + * Get children clients. + */ + public function getChildren(string $id): AnonymousResourceCollection|JsonResponse + { + try { + $client = $this->clientRepository->find($id); + if (!$client) { + return response()->json(['message' => 'Client not found'], 404); + } + + // Assuming the relationship is defined in the model as 'children' + $children = $client->children; + return ClientResource::collection($children); + + } catch (\Exception $e) { + Log::error('Error fetching children: ' . $e->getMessage(), [ + 'exception' => $e, + 'client_id' => $id, + ]); + return response()->json(['message' => 'Erreur serveur'], 500); + } + } + + /** + * Add a child client. + */ + public function addChild(string $id, string $childId): JsonResponse + { + try { + $parent = $this->clientRepository->find($id); + $child = $this->clientRepository->find($childId); + + if (!$parent || !$child) { + return response()->json(['message' => 'Parent or Child not found'], 404); + } + + // Update child's parent_id + $this->clientRepository->update($childId, ['parent_id' => $id]); + + return response()->json(['message' => 'Child added successfully'], 200); + + } catch (\Exception $e) { + Log::error('Error adding child: ' . $e->getMessage(), [ + 'exception' => $e, + 'parent_id' => $id, + 'child_id' => $childId + ]); + return response()->json(['message' => 'Erreur serveur'], 500); + } + } + + /** + * Remove a child client. + */ + public function removeChild(string $id, string $childId): JsonResponse + { + try { + $child = $this->clientRepository->find($childId); + + if (!$child) { + return response()->json(['message' => 'Child not found'], 404); + } + + if ($child->parent_id != $id) { + return response()->json(['message' => 'Client is not a child of this parent'], 400); + } + + // Remove parent_id + $this->clientRepository->update($childId, ['parent_id' => null]); + + return response()->json(['message' => 'Child removed successfully'], 200); + + } catch (\Exception $e) { + Log::error('Error removing child: ' . $e->getMessage(), [ + 'exception' => $e, + 'parent_id' => $id, + 'child_id' => $childId + ]); + return response()->json(['message' => 'Erreur serveur'], 500); + } + } } diff --git a/thanasoft-back/app/Http/Controllers/Api/InterventionController.php b/thanasoft-back/app/Http/Controllers/Api/InterventionController.php index 1eb5fa7..fb64272 100644 --- a/thanasoft-back/app/Http/Controllers/Api/InterventionController.php +++ b/thanasoft-back/app/Http/Controllers/Api/InterventionController.php @@ -13,6 +13,8 @@ use App\Repositories\InterventionPractitionerRepositoryInterface; use App\Repositories\ClientRepositoryInterface; use App\Repositories\ContactRepositoryInterface; use App\Repositories\DeceasedRepositoryInterface; +use App\Repositories\QuoteRepositoryInterface; +use App\Repositories\ProductRepositoryInterface; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; @@ -46,6 +48,16 @@ class InterventionController extends Controller */ protected $deceasedRepository; + /** + * @var QuoteRepositoryInterface + */ + protected $quoteRepository; + + /** + * @var ProductRepositoryInterface + */ + protected $productRepository; + /** * InterventionController constructor. * @@ -54,19 +66,25 @@ class InterventionController extends Controller * @param ClientRepositoryInterface $clientRepository * @param ContactRepositoryInterface $contactRepository * @param DeceasedRepositoryInterface $deceasedRepository + * @param QuoteRepositoryInterface $quoteRepository + * @param ProductRepositoryInterface $productRepository */ public function __construct( InterventionRepositoryInterface $interventionRepository, InterventionPractitionerRepositoryInterface $interventionPractitionerRepository, ClientRepositoryInterface $clientRepository, ContactRepositoryInterface $contactRepository, - DeceasedRepositoryInterface $deceasedRepository + DeceasedRepositoryInterface $deceasedRepository, + QuoteRepositoryInterface $quoteRepository, + ProductRepositoryInterface $productRepository ) { $this->interventionRepository = $interventionRepository; $this->interventionPractitionerRepository = $interventionPractitionerRepository; $this->clientRepository = $clientRepository; $this->contactRepository = $contactRepository; $this->deceasedRepository = $deceasedRepository; + $this->quoteRepository = $quoteRepository; + $this->productRepository = $productRepository; } /** @@ -182,6 +200,56 @@ class InterventionController extends Controller ]); $intervention = $this->interventionRepository->create($interventionData); + // Step 5b: Create a Quote for this intervention + try { + $interventionProduct = $this->productRepository->findInterventionProduct(); + + if ($interventionProduct) { + // Calculate totals + $quantity = 1; + // Ideally fetch TVA rate from product, default to 20% if not set + // Assuming product has tva_rate relationship or simple logic + $tvaRateValue = 20; + + $unitPrice = $interventionProduct->prix_unitaire; + $totalHt = $unitPrice * $quantity; + $totalTva = $totalHt * ($tvaRateValue / 100); + $totalTtc = $totalHt + $totalTva; + + $quoteData = [ + 'client_id' => $client->id, + 'status' => 'brouillon', + 'quote_date' => now()->toDateString(), + 'currency' => 'EUR', + 'valid_until' => now()->addDays(30)->toDateString(), + 'total_ht' => $totalHt, + 'total_tva' => $totalTva, + 'total_ttc' => $totalTtc, + 'lines' => [ + [ + 'product_id' => $interventionProduct->id, + 'description' => 'Intervention: ' . ($intervention->type ?? 'Standard'), + 'units_qty' => $quantity, + 'unit_price' => $unitPrice, + 'discount_pct' => 0, + 'total_ht' => $totalHt, + // 'tva_rate_id' => ... if needed + ] + ] + ]; + + $this->quoteRepository->create($quoteData); + Log::info('Quote auto-created for intervention', ['intervention_id' => $intervention->id]); + } else { + Log::warning('No intervention product found, skipping auto-quote creation', ['intervention_id' => $intervention->id]); + } + + } catch (\Exception $e) { + Log::error('Failed to auto-create quote for intervention: ' . $e->getMessage()); + // Silently fail for the quote part to not block intervention creation + } + + // Step 6: Handle document uploads (if any) $documents = $validated['documents'] ?? []; if (!empty($documents)) { diff --git a/thanasoft-back/app/Http/Requests/StoreClientRequest.php b/thanasoft-back/app/Http/Requests/StoreClientRequest.php index 618388b..31ec8f4 100644 --- a/thanasoft-back/app/Http/Requests/StoreClientRequest.php +++ b/thanasoft-back/app/Http/Requests/StoreClientRequest.php @@ -28,7 +28,7 @@ class StoreClientRequest extends FormRequest 'siret' => 'nullable|string|max:20', 'email' => 'nullable|email|max:191', 'phone' => 'nullable|string|max:50', - 'billing_address_line1' => 'nullable|string|max:255', + 'billing_address_line1' => 'required|string|max:255', 'billing_address_line2' => 'nullable|string|max:255', 'billing_postal_code' => 'nullable|string|max:20', 'billing_city' => 'nullable|string|max:191', @@ -36,6 +36,8 @@ class StoreClientRequest extends FormRequest 'group_id' => 'nullable|exists:client_groups,id', 'notes' => 'nullable|string', 'is_active' => 'boolean', + 'is_parent' => 'boolean|nullable', + 'parent_id' => 'nullable|exists:clients,id', 'default_tva_rate_id' => 'nullable|exists:tva_rates,id', ]; } @@ -56,6 +58,7 @@ class StoreClientRequest extends FormRequest 'email.email' => 'L\'adresse email doit être valide.', 'email.max' => 'L\'adresse email ne peut pas dépasser 191 caractères.', 'phone.max' => 'Le téléphone ne peut pas dépasser 50 caractères.', + 'billing_address_line1.required' => 'L\'adresse facturation est obligatoire.', 'billing_address_line1.max' => 'L\'adresse ne peut pas dépasser 255 caractères.', 'billing_address_line2.max' => 'Le complément d\'adresse ne peut pas dépasser 255 caractères.', 'billing_postal_code.max' => 'Le code postal ne peut pas dépasser 20 caractères.', diff --git a/thanasoft-back/app/Http/Requests/UpdateClientRequest.php b/thanasoft-back/app/Http/Requests/UpdateClientRequest.php index f44cead..ff77fc7 100644 --- a/thanasoft-back/app/Http/Requests/UpdateClientRequest.php +++ b/thanasoft-back/app/Http/Requests/UpdateClientRequest.php @@ -36,6 +36,8 @@ class UpdateClientRequest extends FormRequest 'group_id' => 'nullable|exists:client_groups,id', 'notes' => 'nullable|string', 'is_active' => 'boolean', + 'is_parent' => 'boolean|nullable', + 'parent_id' => 'nullable|exists:clients,id', 'default_tva_rate_id' => 'nullable|exists:tva_rates,id', ]; } diff --git a/thanasoft-back/app/Http/Resources/Client/ClientResource.php b/thanasoft-back/app/Http/Resources/Client/ClientResource.php index a0b904f..5cb6095 100644 --- a/thanasoft-back/app/Http/Resources/Client/ClientResource.php +++ b/thanasoft-back/app/Http/Resources/Client/ClientResource.php @@ -36,6 +36,8 @@ class ClientResource extends JsonResource 'group_id' => $this->group_id, 'notes' => $this->notes, 'is_active' => $this->is_active, + 'is_parent' => $this->is_parent, + 'parent_id' => $this->parent_id, // 'default_tva_rate_id' => $this->default_tva_rate_id, 'created_at' => $this->created_at?->format('Y-m-d H:i:s'), 'updated_at' => $this->updated_at?->format('Y-m-d H:i:s'), @@ -50,6 +52,7 @@ class ClientResource extends JsonResource // Relations // 'company' => new CompanyResource($this->whenLoaded('company')), 'group' => new ClientGroupResource($this->whenLoaded('group')), + 'parent' => new ClientResource($this->whenLoaded('parent')), // 'default_tva_rate' => new TvaRateResource($this->whenLoaded('defaultTvaRate')), 'contacts' => ContactResource::collection($this->whenLoaded('contacts')), 'locations' => ClientLocationResource::collection($this->whenLoaded('locations')), diff --git a/thanasoft-back/app/Models/Client.php b/thanasoft-back/app/Models/Client.php index 1d01112..36ef240 100644 --- a/thanasoft-back/app/Models/Client.php +++ b/thanasoft-back/app/Models/Client.php @@ -21,6 +21,8 @@ class Client extends Model 'group_id', 'notes', 'is_active', + 'is_parent', + 'parent_id', // 'default_tva_rate_id', 'client_category_id', 'user_id', @@ -28,8 +30,19 @@ class Client extends Model protected $casts = [ 'is_active' => 'boolean', + 'is_parent' => 'boolean', ]; + public function parent(): BelongsTo + { + return $this->belongsTo(Client::class, 'parent_id'); + } + + public function children() + { + return $this->hasMany(Client::class, 'parent_id'); + } + public function user(): BelongsTo { return $this->belongsTo(User::class); diff --git a/thanasoft-back/app/Repositories/ProductRepository.php b/thanasoft-back/app/Repositories/ProductRepository.php index 1a07c12..53fc3b5 100644 --- a/thanasoft-back/app/Repositories/ProductRepository.php +++ b/thanasoft-back/app/Repositories/ProductRepository.php @@ -140,4 +140,15 @@ class ProductRepository extends BaseRepository implements ProductRepositoryInter 'total_value' => $totalValue, ]; } + /** + * Find a default intervention product (where category has intervention=true) + */ + public function findInterventionProduct(): ?Product + { + return $this->model->newQuery() + ->whereHas('category', function ($query) { + $query->where('intervention', true); + }) + ->first(); + } } diff --git a/thanasoft-back/app/Repositories/ProductRepositoryInterface.php b/thanasoft-back/app/Repositories/ProductRepositoryInterface.php index 0f8b152..961e047 100644 --- a/thanasoft-back/app/Repositories/ProductRepositoryInterface.php +++ b/thanasoft-back/app/Repositories/ProductRepositoryInterface.php @@ -17,4 +17,6 @@ interface ProductRepositoryInterface extends BaseRepositoryInterface public function getByCategory(int $categoryId, int $perPage = 15): LengthAwarePaginator; public function getProductsByFournisseur(int $fournisseurId): LengthAwarePaginator; + + public function findInterventionProduct(): ?\App\Models\Product; } diff --git a/thanasoft-back/app/Repositories/QuoteRepository.php b/thanasoft-back/app/Repositories/QuoteRepository.php index fa23a43..91633b4 100644 --- a/thanasoft-back/app/Repositories/QuoteRepository.php +++ b/thanasoft-back/app/Repositories/QuoteRepository.php @@ -18,6 +18,11 @@ class QuoteRepository extends BaseRepository implements QuoteRepositoryInterface } + public function all(array $columns = ['*']): \Illuminate\Support\Collection + { + return $this->model->with(['client', 'lines.product'])->get($columns); + } + public function create(array $data): Quote { return DB::transaction(function () use ($data) { diff --git a/thanasoft-back/database/migrations/2026_01_08_115945_add_parent_fields_to_clients_table.php b/thanasoft-back/database/migrations/2026_01_08_115945_add_parent_fields_to_clients_table.php new file mode 100644 index 0000000..bc20a3a --- /dev/null +++ b/thanasoft-back/database/migrations/2026_01_08_115945_add_parent_fields_to_clients_table.php @@ -0,0 +1,30 @@ +boolean('is_parent')->nullable()->default(false); + $table->foreignId('parent_id')->nullable()->constrained('clients')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('clients', function (Blueprint $table) { + $table->dropForeign(['parent_id']); + $table->dropColumn(['is_parent', 'parent_id']); + }); + } +}; diff --git a/thanasoft-back/routes/api.php b/thanasoft-back/routes/api.php index 09c7428..7960317 100644 --- a/thanasoft-back/routes/api.php +++ b/thanasoft-back/routes/api.php @@ -53,9 +53,16 @@ Route::middleware('auth:sanctum')->group(function () { Route::apiResource('clients', ClientController::class); Route::apiResource('client-groups', ClientGroupController::class); + Route::apiResource('client-locations', ClientLocationController::class); Route::apiResource('client-locations', ClientLocationController::class); Route::get('clients/{clientId}/locations', [ClientLocationController::class, 'getLocationsByClient']); + // Client Parent/Child routes + Route::get('clients/{id}/children', [ClientController::class, 'getChildren']); + Route::post('clients/{id}/children/{childId}', [ClientController::class, 'addChild']); + Route::delete('clients/{id}/children/{childId}', [ClientController::class, 'removeChild']); + Route::patch('clients/{id}/status', [ClientController::class, 'changeStatus']); + // Contact management Route::apiResource('contacts', ContactController::class); Route::get('clients/{clientId}/contacts', [ContactController::class, 'getContactsByClient']); diff --git a/thanasoft-front/src/components/Organism/CRM/ClientDetailPresentation.vue b/thanasoft-front/src/components/Organism/CRM/ClientDetailPresentation.vue index de43c67..22eb71d 100644 --- a/thanasoft-front/src/components/Organism/CRM/ClientDetailPresentation.vue +++ b/thanasoft-front/src/components/Organism/CRM/ClientDetailPresentation.vue @@ -25,10 +25,12 @@ :client-type="client.type_label || 'Client'" :contacts-count="contacts.length" :locations-count="locations.length" + :children-count="children ? children.length : 0" :is-active="client.is_active" + :is-parent="client.is_parent" :active-tab="activeTab" @edit-avatar="triggerFileInput" - @change-tab="activeTab = $event" + @change-tab="$emit('change-tab', $event)" /> @@ -62,6 +67,7 @@ import ClientContactsTab from "@/components/molecules/client/ClientContactsTab.v import ClientAddressTab from "@/components/molecules/client/ClientAddressTab.vue"; import ClientLocationsTab from "@/components/molecules/client/ClientLocationsTab.vue"; import ClientNotesTab from "@/components/molecules/client/ClientNotesTab.vue"; +import ClientChildrenTab from "@/components/molecules/client/ClientChildrenTab.vue"; import { defineProps, defineEmits } from "vue"; import ClientActivityTab from "@/components/molecules/client/ClientActivityTab.vue"; diff --git a/thanasoft-front/src/components/Organism/CRM/client/ClientDetailSidebar.vue b/thanasoft-front/src/components/Organism/CRM/client/ClientDetailSidebar.vue index 241bfc8..f1e5f96 100644 --- a/thanasoft-front/src/components/Organism/CRM/client/ClientDetailSidebar.vue +++ b/thanasoft-front/src/components/Organism/CRM/client/ClientDetailSidebar.vue @@ -19,6 +19,8 @@ :active-tab="activeTab" :contacts-count="contactsCount" :locations-count="locationsCount" + :children-count="childrenCount" + :is-parent="isParent" @change-tab="$emit('change-tab', $event)" /> @@ -58,6 +60,14 @@ defineProps({ type: Boolean, default: true, }, + isParent: { + type: Boolean, + default: false, + }, + childrenCount: { + type: Number, + default: 0, + }, activeTab: { type: String, required: true, diff --git a/thanasoft-front/src/components/Organism/Interventions/InterventionPresentation.vue b/thanasoft-front/src/components/Organism/Interventions/InterventionPresentation.vue index 35eae48..833304e 100644 --- a/thanasoft-front/src/components/Organism/Interventions/InterventionPresentation.vue +++ b/thanasoft-front/src/components/Organism/Interventions/InterventionPresentation.vue @@ -1,13 +1,56 @@ diff --git a/thanasoft-front/src/components/molecules/Quote/QuoteLinesTable.vue b/thanasoft-front/src/components/molecules/Quote/QuoteLinesTable.vue index fc312ee..5cd4d98 100644 --- a/thanasoft-front/src/components/molecules/Quote/QuoteLinesTable.vue +++ b/thanasoft-front/src/components/molecules/Quote/QuoteLinesTable.vue @@ -92,9 +92,12 @@ const props = defineProps({ }); const formatCurrency = (value) => { + const numberValue = typeof value === 'string' ? parseFloat(value) : value; + if (isNaN(numberValue)) return '0,00 €'; + return new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR", - }).format(value); + }).format(numberValue); }; diff --git a/thanasoft-front/src/components/molecules/Quote/QuoteSummary.vue b/thanasoft-front/src/components/molecules/Quote/QuoteSummary.vue index 76c79d7..4ce6462 100644 --- a/thanasoft-front/src/components/molecules/Quote/QuoteSummary.vue +++ b/thanasoft-front/src/components/molecules/Quote/QuoteSummary.vue @@ -26,15 +26,18 @@ import { defineProps } from "vue"; const props = defineProps({ - ht: Number, - tva: Number, - ttc: Number, + ht: [Number, String], + tva: [Number, String], + ttc: [Number, String], }); const formatCurrency = (value) => { + const numberValue = typeof value === 'string' ? parseFloat(value) : value; + if (isNaN(numberValue)) return '0,00 €'; + return new Intl.NumberFormat("fr-FR", { style: "currency", currency: "EUR", - }).format(value); + }).format(numberValue); }; diff --git a/thanasoft-front/src/components/molecules/client/ClientChildrenTab.vue b/thanasoft-front/src/components/molecules/client/ClientChildrenTab.vue new file mode 100644 index 0000000..5b29680 --- /dev/null +++ b/thanasoft-front/src/components/molecules/client/ClientChildrenTab.vue @@ -0,0 +1,198 @@ + + + diff --git a/thanasoft-front/src/components/molecules/client/ClientSearchInput.vue b/thanasoft-front/src/components/molecules/client/ClientSearchInput.vue new file mode 100644 index 0000000..c265a32 --- /dev/null +++ b/thanasoft-front/src/components/molecules/client/ClientSearchInput.vue @@ -0,0 +1,131 @@ + + + diff --git a/thanasoft-front/src/components/molecules/client/ClientTabNavigation.vue b/thanasoft-front/src/components/molecules/client/ClientTabNavigation.vue index 0e8e3a3..ef36e2d 100644 --- a/thanasoft-front/src/components/molecules/client/ClientTabNavigation.vue +++ b/thanasoft-front/src/components/molecules/client/ClientTabNavigation.vue @@ -45,6 +45,13 @@ :is-active="activeTab === 'notes'" @click="$emit('change-tab', 'notes')" /> + @@ -65,6 +72,14 @@ defineProps({ type: Number, default: 0, }, + childrenCount: { + type: Number, + default: 0, + }, + isParent: { + type: Boolean, + default: false, + }, }); defineEmits(["change-tab"]); diff --git a/thanasoft-front/src/components/molecules/form/NewClientForm.vue b/thanasoft-front/src/components/molecules/form/NewClientForm.vue index 480e660..f419804 100644 --- a/thanasoft-front/src/components/molecules/form/NewClientForm.vue +++ b/thanasoft-front/src/components/molecules/form/NewClientForm.vue @@ -9,9 +9,9 @@
+
+ {{ errorMessage("client_category_id") }} +
@@ -32,15 +38,14 @@ >Nom du client *
- {{ fieldErrors.name }} + {{ errorMessage("name") }}
@@ -50,31 +55,29 @@
- {{ fieldErrors.vat_number }} + {{ errorMessage("vat_number") }}
- {{ fieldErrors.siret }} + {{ errorMessage("siret") }}
@@ -84,30 +87,28 @@
- {{ fieldErrors.email }} + {{ errorMessage("email") }}
- {{ fieldErrors.phone }} + {{ errorMessage("phone") }}
@@ -117,19 +118,18 @@
- {{ fieldErrors.billing_address_line1 }} + {{ errorMessage("billing_address_line1") }}
@@ -138,19 +138,18 @@
- {{ fieldErrors.billing_address_line2 }} + {{ errorMessage("billing_address_line2") }}
@@ -159,40 +158,37 @@
- {{ fieldErrors.billing_postal_code }} + {{ errorMessage("billing_postal_code") }}
- {{ fieldErrors.billing_city }} + {{ errorMessage("billing_city") }}
- {{ fieldErrors.billing_country_code }} + {{ errorMessage("billing_country_code") }}
@@ -215,13 +211,16 @@
+
+ {{ errorMessage("notes") }} +
@@ -401,6 +400,13 @@ const clearErrors = () => { errors.value = []; fieldErrors.value = {}; }; + +const errorMessage = (field) => { + if (fieldErrors.value[field] && Array.isArray(fieldErrors.value[field])) { + return fieldErrors.value[field][0]; + } + return fieldErrors.value[field]; +};