Refactor error handling and enhance API interactions across Filament pages

- Introduced `ApiErrorTranslator` to normalize and translate API error messages, providing clearer feedback in French.
- Updated all Filament pages (Articles, Documents, Divers, Journaux, Tiers, TablesExplorer) to utilize the new error translation mechanism, improving user experience during API interactions.
- Added validation for required fields before API calls, ensuring users receive immediate feedback when mandatory inputs are missing.
- Implemented tracking properties to distinguish between "never searched" and "searched without results," enhancing the user interface.
- Removed the obsolete `$results` property from the Articles page and added a new `$barcode` property to align with API requirements.
- Updated documentation to reflect changes in API behavior and error handling, including new metadata returned by the `art_list` endpoint.
- Added new tests to verify the functionality of the barcode handling and validation logic.
This commit is contained in:
2026-02-23 10:15:17 +01:00
parent 7df94b64fa
commit bb1bbc2904
29 changed files with 1075 additions and 157 deletions

View File

@@ -2,6 +2,6 @@
@if ($message)
<div class="rounded-lg bg-danger-50 p-4 text-sm text-danger-600 dark:bg-danger-400/10 dark:text-danger-400">
{{ $message }}
{!! nl2br(e($message)) !!}
</div>
@endif

View File

@@ -1,7 +1,12 @@
@props(['data'])
@props(['data', 'searched' => false])
@if (! empty($data))
<div class="overflow-x-auto">
<pre class="rounded-lg border border-gray-200 bg-gray-50 p-4 text-xs font-mono leading-relaxed text-gray-700 dark:border-white/10 dark:bg-gray-800 dark:text-gray-300">{{ json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE) }}</pre>
</div>
@elseif ($searched)
<x-logistics.empty-state
icon="heroicon-o-magnifying-glass"
title="Aucune donnée n'a été trouvée pour votre demande."
/>
@endif

View File

@@ -27,15 +27,13 @@
wire:model="select"
label="Colonnes (select)"
id="select"
placeholder="artid,artname"
placeholder="artid,name1"
/>
<x-logistics.form-field
wire:model="results"
label="Nombre de résultats (results)"
id="results"
type="number"
min="1"
max="100"
wire:model="barcode"
label="Code-barres (barcode)"
id="barcode"
placeholder="Ex: 5411068700323"
/>
</div>
@@ -55,17 +53,25 @@
<x-logistics.card>
<x-logistics.section-header title="Résultats art_list">
<x-slot:actions>
@if ($metadata)
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
</span>
@endif
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ count($data) }} résultat(s)
</span>
</x-slot:actions>
</x-logistics.section-header>
<div class="p-6">
<x-logistics.data-table :data="$data" />
</div>
</x-logistics.card>
@elseif ($hasSearched && ! $errorMessage)
<x-logistics.card>
<x-logistics.section-header title="Résultats art_list" />
<div class="p-6">
<x-logistics.empty-state
icon="heroicon-o-magnifying-glass"
title="Aucune donnée n'a été trouvée pour votre demande."
/>
</div>
</x-logistics.card>
@endif
{{-- art_getstk --}}
@@ -92,7 +98,7 @@
</div>
<div wire:loading.remove wire:target="getStock" class="mt-4">
<x-logistics.json-block :data="$stockData" />
<x-logistics.json-block :data="$stockData" :searched="$hasCheckedStock" />
</div>
</div>
</x-logistics.card>

View File

@@ -27,7 +27,7 @@
</div>
<div wire:loading.remove wire:target="getSerialNumber" class="mt-4">
<x-logistics.json-block :data="$serialData" />
<x-logistics.json-block :data="$serialData" :searched="$hasSerial" />
</div>
</div>
</x-logistics.card>
@@ -56,7 +56,7 @@
</div>
<div wire:loading.remove wire:target="searchCodes" class="mt-4">
<x-logistics.json-block :data="$codesData" />
<x-logistics.json-block :data="$codesData" :searched="$hasCodes" />
</div>
</div>
</x-logistics.card>
@@ -118,7 +118,7 @@
</div>
<div wire:loading.remove wire:target="updateStock" class="mt-4">
<x-logistics.json-block :data="$updateStockResult" />
<x-logistics.json-block :data="$updateStockResult" :searched="$hasUpdatedStock" />
</div>
</div>
</x-logistics.card>

View File

@@ -51,17 +51,25 @@
<x-logistics.card>
<x-logistics.section-header title="Résultats document_list">
<x-slot:actions>
@if ($metadata)
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
</span>
@endif
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ count($data) }} résultat(s)
</span>
</x-slot:actions>
</x-logistics.section-header>
<div class="p-6">
<x-logistics.data-table :data="$data" />
</div>
</x-logistics.card>
@elseif ($hasSearchedDocs && ! $errorMessage)
<x-logistics.card>
<x-logistics.section-header title="Résultats document_list" />
<div class="p-6">
<x-logistics.empty-state
icon="heroicon-o-magnifying-glass"
title="Aucune donnée n'a été trouvée pour votre demande."
/>
</div>
</x-logistics.card>
@endif
{{-- document_detail --}}
@@ -94,7 +102,7 @@
</div>
<div wire:loading.remove wire:target="getDocumentDetail" class="mt-4">
<x-logistics.json-block :data="$detailData" />
<x-logistics.json-block :data="$detailData" :searched="$hasDetail" />
</div>
</div>
</x-logistics.card>
@@ -123,7 +131,7 @@
</div>
<div wire:loading.remove wire:target="getStatusList" class="mt-4">
<x-logistics.json-block :data="$statusData" />
<x-logistics.json-block :data="$statusData" :searched="$hasStatus" />
</div>
</div>
</x-logistics.card>
@@ -176,7 +184,7 @@
</div>
<div wire:loading.remove wire:target="getUnitPriceAndVat" class="mt-4">
<x-logistics.json-block :data="$priceData" />
<x-logistics.json-block :data="$priceData" :searched="$hasPrice" />
</div>
</div>
</x-logistics.card>
@@ -211,7 +219,7 @@
</div>
<div wire:loading.remove wire:target="getDueDate" class="mt-4">
<x-logistics.json-block :data="$dueDateData" />
<x-logistics.json-block :data="$dueDateData" :searched="$hasDueDate" />
</div>
</div>
</x-logistics.card>
@@ -246,7 +254,7 @@
</div>
<div wire:loading.remove wire:target="getAttachListThumbnail" class="mt-4">
<x-logistics.json-block :data="$attachData" />
<x-logistics.json-block :data="$attachData" :searched="$hasAttach" />
</div>
</div>
</x-logistics.card>
@@ -290,7 +298,7 @@
</div>
<div wire:loading.remove wire:target="getPdf" class="mt-4">
<x-logistics.json-block :data="$pdfData" />
<x-logistics.json-block :data="$pdfData" :searched="$hasPdf" />
</div>
</div>
</x-logistics.card>
@@ -371,7 +379,7 @@
</div>
<div wire:loading.remove wire:target="addDocument" class="mt-4">
<x-logistics.json-block :data="$addResult" />
<x-logistics.json-block :data="$addResult" :searched="$hasAdded" />
</div>
</div>
</x-logistics.card>
@@ -430,7 +438,7 @@
</div>
<div wire:loading.remove wire:target="modDocument" class="mt-4">
<x-logistics.json-block :data="$modResult" />
<x-logistics.json-block :data="$modResult" :searched="$hasModified" />
</div>
</div>
</x-logistics.card>

View File

@@ -19,7 +19,7 @@
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
<x-logistics.form-field
wire:model="type"
label="Type de journal (TYPE)"
label="Type de journal (TYPE, obligatoire)"
id="type"
placeholder="Ex: V"
/>
@@ -55,17 +55,25 @@
<x-logistics.card>
<x-logistics.section-header title="Résultats jnl_list">
<x-slot:actions>
@if ($metadata)
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
</span>
@endif
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ count($data) }} résultat(s)
</span>
</x-slot:actions>
</x-logistics.section-header>
<div class="p-6">
<x-logistics.data-table :data="$data" />
</div>
</x-logistics.card>
@elseif ($hasSearched && ! $errorMessage)
<x-logistics.card>
<x-logistics.section-header title="Résultats jnl_list" />
<div class="p-6">
<x-logistics.empty-state
icon="heroicon-o-magnifying-glass"
title="Aucune donnée n'a été trouvée pour votre demande."
/>
</div>
</x-logistics.card>
@endif
@else
<x-logistics.card>

View File

@@ -55,17 +55,25 @@
<x-logistics.card>
<x-logistics.section-header title="Résultats third_list">
<x-slot:actions>
@if ($metadata)
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ $metadata['rowcount'] ?? 0 }} résultat(s)
</span>
@endif
<span class="rounded-full bg-gray-100 px-2.5 py-0.5 text-xs font-medium tabular-nums text-gray-600 dark:bg-white/10 dark:text-gray-300">
{{ count($data) }} résultat(s)
</span>
</x-slot:actions>
</x-logistics.section-header>
<div class="p-6">
<x-logistics.data-table :data="$data" />
</div>
</x-logistics.card>
@elseif ($hasSearched && ! $errorMessage)
<x-logistics.card>
<x-logistics.section-header title="Résultats third_list" />
<div class="p-6">
<x-logistics.empty-state
icon="heroicon-o-magnifying-glass"
title="Aucune donnée n'a été trouvée pour votre demande."
/>
</div>
</x-logistics.card>
@endif
{{-- third_GetArtHistory --}}
@@ -92,7 +100,7 @@
</div>
<div wire:loading.remove wire:target="getArtHistory" class="mt-4">
<x-logistics.json-block :data="$historyData" />
<x-logistics.json-block :data="$historyData" :searched="$hasHistory" />
</div>
</div>
</x-logistics.card>