Update Tiers functionality and enhance API documentation

- Changed the default value of the `$select` property in Tiers.php from `custid,custname` to `custid,name` to reflect valid column names.
- Updated the tiers.blade.php view to align the placeholder for the select field with the new default value.
- Enhanced the documentation for the `third_list` and `third_GetArtHistory` endpoints, detailing valid search columns, metadata, and response structures.
- Added new tests in TiersPageTest.php to verify the default select value, API parameter handling, and metadata storage.
- Overall, improved the user experience and API interaction for managing tiers.
This commit is contained in:
2026-02-23 11:58:14 +01:00
parent dfe20e79d7
commit c84e0c680a
9 changed files with 352 additions and 57 deletions

View File

@@ -22,7 +22,7 @@ class Tiers extends Page
public string $mode = 'read'; public string $mode = 'read';
public string $select = 'custid,custname'; public string $select = 'custid,name';
public string $search = ''; public string $search = '';

View File

@@ -1061,7 +1061,7 @@ Les tiers (clients, fournisseurs) sont les entités commerciales avec lesquelles
#### `third_list` -- Recherche de tiers #### `third_list` -- Recherche de tiers
Retourne une liste de tiers correspondant au filtre de recherche. Permet de trouver un client ou fournisseur par son nom, son identifiant ou d'autres critères. Retourne une liste de tiers correspondant au filtre de recherche. Permet de trouver un client ou fournisseur par son nom, son identifiant ou d'autres critères. L'API retourne un maximum fixe de **10 résultats** par appel, cette limite n'est pas configurable. La recherche s'effectue dans les colonnes `name`, `groupid` et `vat` (pas dans `custid`).
| | | | | |
|---|---| |---|---|
@@ -1072,16 +1072,81 @@ Retourne une liste de tiers correspondant au filtre de recherche. Permet de trou
| Paramètre | Type | Obligatoire | Description | | Paramètre | Type | Obligatoire | Description |
|-----------|------|:-----------:|-------------| |-----------|------|:-----------:|-------------|
| `search` | `string` | Oui | Filtre de recherche. **Ce paramètre est obligatoire** : un appel sans filtre retourne une erreur. | | `search` | `string` | Oui | Filtre de recherche textuel. Recherche dans les colonnes `name`, `groupid` et `vat` de la table `cust`. **Ce paramètre est obligatoire** : un appel sans `search` retourne une erreur HTTP 400 "Search terms are required". Un body vide provoque une erreur HTTP 500. **Attention** : la recherche ne porte PAS sur `custid`. Pour trouver un tiers par son identifiant, il faut chercher par son nom, son groupid ou son numéro de TVA. |
| `select` | `string` | Non | Colonnes à retourner, séparées par des virgules (colonnes de la table `cust`). | | `select` | `string` | Non | Liste des colonnes à retourner, séparées par des virgules. Insensible à la casse. Si omis, les colonnes par défaut sont `custid,name`. L'API ignore silencieusement les noms de colonnes invalides sans émettre d'erreur. Voir le tableau des colonnes valides ci-dessous. |
| `results` | `int` | Non | **Sans effet.** Ce paramètre est accepté mais n'influence pas le nombre de résultats. L'API retourne toujours un maximum de 10 résultats (testé avec 3, 10, 20). | | `results` | `int` | Non | **Sans effet.** Ce paramètre est accepté par l'API mais n'influence pas le nombre de résultats retournés. L'API retourne toujours un maximum de 10 résultats, quelle que soit la valeur de `results` (testé avec 3, 5, 10, 20, en int et en string). |
**Colonnes valides pour `select`** (testées individuellement) :
| Colonne | Type | Description | Exemple |
|---------|------|-------------|---------|
| `custid` | `string` | Identifiant unique du tiers | `"0100002174"` |
| `name` | `string` | Nom principal du tiers | `"ESI SPRL"` |
| `name2` | `string` | Nom secondaire / complément | `"BOX7"` |
| `vat` | `string` | Numéro de TVA | `"0431.066.713"` |
| `email` | `string` | Adresse email | `"jre@esi-informatique.com"` |
| `groupid` | `string` | Identifiant de groupe | `"ESI01"` |
| `website` | `string` | Site web | `""` |
| `memo` | `string` | Mémo / remarques | `""` |
| `paydelay` | `string` | Code de délai de paiement | `""` |
| `paymode` | `string` | Mode de paiement | `""` |
| `bankname` | `string` | Nom de la banque | `""` |
| `iban` | `string` | Code IBAN | `"BE09348066192157"` |
| `bic` | `string` | Code BIC/SWIFT | `"BBRUBEBB"` |
| `custtype` | `string` | Type de client | `"PRO"` |
| `discount` | `float` | Remise globale | `0` |
**Colonnes invalides** (ignorées silencieusement) : `custname`, `name1`, `addr1`, `addr2`, `zip`, `city`, `country`, `vatnum`, `phone1`, `phone`, `addr`, `address`, `tel`, `fax`, `web`, `note`, `lang`, `type`, `status`, `categ`, `bankaccount`, `maxdisc`.
**Attention** : la colonne `custname` n'existe PAS dans `third_list`. Le nom du tiers est dans la colonne `name`. C'est une différence importante par rapport à d'autres endpoints (comme `document_detail`) qui utilisent `thirdname`.
**Métadonnées retournées** :
| Clé | Type | Description |
|-----|------|-------------|
| `rowCount` | `int` | Nombre de résultats retournés (maximum 10). |
| `source` | `string` | Type de base de données (ex : `DBF`). |
| `executionTimeMs` | `int` | Temps d'exécution de la requête en millisecondes. |
| `searchColumns` | `string` | Colonnes utilisées pour la recherche (toujours `name,groupid,vat`). |
| `selectColumns` | `string` | Colonnes demandées dans le paramètre `select`. |
| `searchTerms` | `string` | Termes de recherche utilisés. |
**Exemple de requête** : **Exemple de requête** :
```json ```json
{ {
"search": "Dupont", "search": "ESI",
"select": "custid,custname,city" "select": "custid,name,vat,groupid"
}
```
**Exemple de réponse** :
```json
{
"data": [
{
"custid": "0100002174",
"name": "ESI SPRL",
"vat": "0431.066.713",
"groupid": "ESI01"
},
{
"custid": "0100002175",
"name": "E.I.S. SA",
"vat": "0435.063.806",
"groupid": "ESI02"
}
],
"metadata": {
"rowCount": 2,
"source": "DBF",
"executionTimeMs": 111,
"searchColumns": "name,groupid,vat",
"selectColumns": "custid,name,vat,groupid",
"searchTerms": "ESI"
},
"error": null
} }
``` ```
@@ -1089,7 +1154,7 @@ Retourne une liste de tiers correspondant au filtre de recherche. Permet de trou
#### `third_GetArtHistory` -- Historique des articles d'un tiers #### `third_GetArtHistory` -- Historique des articles d'un tiers
Retourne l'historique complet des articles présents dans les documents associés à un tiers. Permet d'analyser les achats ou ventes passés d'un client/fournisseur. Retourne l'historique complet des articles présents dans les documents associés à un tiers. Permet d'analyser les achats ou ventes passés d'un client/fournisseur. L'endpoint retourne **tous les articles** sans pagination ni limite (jusqu'à plusieurs milliers d'éléments). Les résultats sont triés par date décroissante (les plus récents en premier).
| | | | | |
|---|---| |---|---|
@@ -1100,16 +1165,80 @@ Retourne l'historique complet des articles présents dans les documents associé
| Paramètre | Type | Obligatoire | Description | | Paramètre | Type | Obligatoire | Description |
|-----------|------|:-----------:|-------------| |-----------|------|:-----------:|-------------|
| `thirdid` | `string` | Oui | Identifiant du tiers (champ `custid` de la table `cust`). | | `thirdid` | `string` | Oui | Identifiant du tiers (champ `custid` de la table `cust`). **La casse du nom de paramètre est importante** : `thirdid` en minuscules est obligatoire. `THIRDID` en majuscules provoque une erreur HTTP 400 "thirdid parameter is required.". Un appel sans ce paramètre retourne également une erreur HTTP 400. Si l'identifiant n'existe pas, l'API retourne un tableau vide sans erreur. |
**Paramètres ignorés** : les paramètres `select` et `results` sont acceptés par l'API mais n'ont aucun effet sur la réponse. L'endpoint retourne toujours l'ensemble complet des colonnes et tous les résultats.
**Structure de la réponse `data`** :
Chaque élément du tableau `data` contient :
| Champ | Type | Description |
|-------|------|-------------|
| `artid` | `string` | Identifiant de l'article. |
| `artname` | `string` | Nom de l'article (peut être tronqué à environ 80 caractères). |
| `jnl` | `string` | Code du journal dans lequel l'article a été utilisé (ex : `03VEN`, `09OFFRE`, `INV`). |
| `unitprice` | `float` | Prix unitaire de l'article dans ce document. |
| `qty` | `int` ou `float` | Quantité de l'article dans ce document. |
| `vatid` | `string` | Code de taux TVA (ex : `"21"`). |
| `vatpc` | `int` ou `float` | Pourcentage TVA (ex : `21`). |
| `s_credate` | `string` | Date de création du document (format `YYYY-MM-DD`). |
**Métadonnées retournées** :
| Clé | Type | Description |
|-----|------|-------------|
| `rowCount` | `int` | Nombre total de résultats retournés (peut atteindre plusieurs milliers). |
| `source` | `string` | Type de base de données (ex : `DBF`). |
**Exemple de requête** : **Exemple de requête** :
```json ```json
{ {
"thirdid": "CUST001" "thirdid": "0100002174"
} }
``` ```
**Exemple de réponse** :
```json
{
"data": [
{
"artid": "EP2-06658",
"artname": "Office Home and Business 2024 French Eur",
"jnl": "09OFFRE",
"unitprice": 220,
"qty": 1,
"vatid": "21",
"vatpc": 21,
"s_credate": "2025-06-03"
},
{
"artid": "MO ATELIER",
"artname": "FORFAIT PREPARATION PC / REMPLACEMENT DISQUE",
"jnl": "09OFFRE",
"unitprice": 65,
"qty": 1,
"vatid": "21",
"vatpc": 21,
"s_credate": "2025-06-03"
}
],
"metadata": {
"rowCount": 4468,
"source": "DBF"
},
"error": null
}
```
**Remarques** :
- Un même article peut apparaître plusieurs fois dans l'historique s'il figure dans plusieurs documents.
- Le champ `jnl` permet de distinguer le type de document (offre, facture, note de crédit, etc.).
- Le volume de données peut être conséquent (milliers d'éléments). L'application affiche les résultats dans un bloc JSON formaté.
--- ---
### 6.6 Divers ### 6.6 Divers
@@ -1356,6 +1485,12 @@ Tiers (cust)
17. **Modes de paiement** : les valeurs valides pour les modes de paiement sont obtenues via `codes_list` avec `code=PAYMODE`. Les codes courants sont : `CAS` (Cash), `VIR` (Virement), `BC` (Bancontact), `CBEF` (Cash BEF). 17. **Modes de paiement** : les valeurs valides pour les modes de paiement sont obtenues via `codes_list` avec `code=PAYMODE`. Les codes courants sont : `CAS` (Cash), `VIR` (Virement), `BC` (Bancontact), `CBEF` (Cash BEF).
18. **Colonnes `third_list` vs `column_list/cust`** : l'endpoint `third_list` n'accepte PAS toutes les colonnes de la table `cust` dans son paramètre `select`. Seul un sous-ensemble de colonnes est valide : `custid`, `name`, `name2`, `vat`, `email`, `groupid`, `website`, `memo`, `paydelay`, `paymode`, `bankname`, `iban`, `bic`, `custtype`, `discount`. Les colonnes `custname`, `name1`, `addr1`, `zip`, `city`, `country`, `phone1` (pourtant présentes dans `column_list/cust`) sont ignorées silencieusement. La colonne pour le nom du tiers est `name` (et non `custname`).
19. **Colonnes de recherche `third_list`** : la recherche textuelle de `third_list` porte sur les colonnes `name`, `groupid` et `vat`. Il n'est PAS possible de rechercher par `custid`. Pour retrouver un tiers spécifique par son identifiant, il faut utiliser une autre information (nom, numéro de TVA, groupid).
20. **`third_GetArtHistory` -- casse du paramètre** : le paramètre `thirdid` doit être en **minuscules**. `THIRDID` en majuscules provoque une erreur HTTP 400 "thirdid parameter is required.", comme si le paramètre n'avait pas été fourni. L'endpoint retourne l'intégralité de l'historique sans limite (potentiellement des milliers d'éléments).
--- ---
## 11. Ressources externes ## 11. Ressources externes

View File

@@ -6,35 +6,38 @@ Dernière mise à jour : 2026-02-23
Aucun travail en cours. Aucun travail en cours.
## Changements récents (2026-02-23, session investigation endpoints Documents) ## Changements récents (2026-02-23, session investigation endpoints Tiers)
- **Investigation complète des 9 endpoints Documents** : tests systématiques via appels API réels pour documenter chaque endpoint de la page Documents.php. Résultats principaux : - **Investigation complète des 2 endpoints Tiers** : tests systématiques via appels API réels pour documenter `third_list` et `third_GetArtHistory`.
- `document_list` : le paramètre `results` fonctionne (contrairement à `art_list` et `third_list`). Défaut ~108 résultats. `select` par défaut retourne uniquement `thirdid`. Body vide = erreur 400. - `third_list` : la recherche s'effectue sur les colonnes `name`, `groupid`, `vat` (pas `custid`). La colonne `custname` n'est PAS valide ; le nom est dans `name`. Colonnes par défaut : `custid,name`. Limite fixe de 10 résultats (paramètre `results` sans effet). Métadonnées détaillées : `rowCount`, `source`, `executionTimeMs`, `searchColumns`, `selectColumns`, `searchTerms`. Colonnes valides testées : `custid`, `name`, `name2`, `vat`, `email`, `groupid`, `website`, `memo`, `paydelay`, `paymode`, `bankname`, `iban`, `bic`, `custtype`, `discount`. Colonnes invalides : `custname`, `name1`, `addr1`, `zip`, `city`, `country`, `phone1`, etc.
- `document_detail` : structure de réponse riche documentée (en-tête du document au premier niveau + tableaux `detail[]` et `attach[]`). Métadonnées spécifiques : `detailRowCount`, `attachRowCount`, `totalExecutionTimeMs`. - `third_GetArtHistory` : seul paramètre `thirdid` (minuscules obligatoires, `THIRDID` ne fonctionne pas). Retourne l'historique complet sans pagination (4468 éléments pour le client de test). Structure : `artid`, `artname`, `jnl`, `unitprice`, `qty`, `vatid`, `vatpc`, `s_credate`. ID inexistant = tableau vide sans erreur.
- `Document_GetStatusList` : retourne `{code, desc}`. Statuts documentés pour 6 types de journaux (03VEN, 01COM, 02NEV, 04NCV, 11COMF, 09OFFRE). - **Correction `Tiers.php`** : valeur par défaut de `$select` changée de `custid,custname` (invalide) à `custid,name` (valide).
- `Document_GetUnitPriceAndVat` : `QTY` doit être string (int = HTTP 400). `DATE` doit être `YYYY-MM-DD` (autre format = HTTP 400). Réponse : `{unitprice, discount, vatid, vatpc}` en strings. - **Vue `tiers.blade.php`** : placeholder du champ select mis à jour.
- `Document_GetDueDate` : codes `paydelay` proviennent de `codes_list` avec `code=PAYDELAY` (10 codes documentés : 30, 30F, 45F, 50, 60, 60F, 75F, 90, 90F, 0F). `date` au format `YYYY-MM-DD`. Réponse : `{duedate: "YYYY-MM-DD"}`. - **Documentation enrichie** : sections `third_list` et `third_GetArtHistory` massivement enrichies (colonnes valides, métadonnées, exemples de réponse, structure `third_GetArtHistory`). 3 nouvelles remarques ajoutées (colonnes third_list vs column_list/cust, colonnes de recherche, casse du paramètre thirdid).
- `Document_GetAttachListThumbnail` : codes d'erreur 003 (document non trouvé), 004 (pas d'image). - **7 nouveaux tests Pest** ajoutés dans `TiersPageTest.php` (total : 15 tests) : valeur par défaut select, envoi des paramètres, stockage des métadonnées, clé thirdid en minuscules, erreur API third_GetArtHistory, ID inexistant, filtrage select vide.
- **Document_GetPDF est FONCTIONNEL** : le paramètre `LAYOUT` doit être une valeur numérique en string (ex: `"1"`). Les valeurs textuelles provoquent une erreur. Retourne le PDF en base64 dans `data.pdf`. - Total : 134 tests passent, 1 test pré-existant en échec (FilamentDashboardTest).
- `document_add` / `document_mod` : pas de logs antérieurs, documentation existante cohérente.
- **Documentation massivement mise à jour** : `documentation/documentation_api_logistics.md` enrichie avec exemples de réponses réelles, structures de données détaillées, codes paydelay, format de date YYYY-MM-DD, Document_GetPDF reclassé comme fonctionnel. Ajout de la section "8. Endpoints partiellement fonctionnels". Numérotation des sections mise à jour.
- **Page Documents.php modifiée** : ajout de la propriété `$results` (int, défaut 108), transmission du paramètre `results` en string à l'API via `searchDocuments()`.
- **Vue documents.blade.php modifiée** : ajout du champ `results` (input numérique) dans le formulaire `document_list`. Suppression du bandeau "non fonctionnel" de `Document_GetPDF`, mise à jour du placeholder LAYOUT ("Ex: 1"), mise à jour de la description.
- **1 nouveau test Pest** ajouté dans `DocumentsPageTest.php` : vérification que `results` est envoyé en string à l'API.
- **Modes de paiement documentés** : `codes_list` avec `code=PAYMODE` retourne CAS (Cash), VIR (Virement), BC (Bancontact), CBEF (Cash BEF).
- Total : 125 tests passent, 2 tests pré-existants en échec (FilamentDashboardTest).
## Décisions récentes ## Décisions récentes
- **Document_GetPDF fonctionnel** (2026-02-23) : L'endpoint a été reclassé de "non fonctionnel" à "partiellement fonctionnel". Le paramètre LAYOUT doit être une valeur numérique en string. Le bandeau d'avertissement a été retiré de la vue. - **Colonne `name` au lieu de `custname`** (2026-02-23) : La colonne `custname` n'existe pas dans l'endpoint `third_list`. Le nom du tiers est retourné dans la colonne `name`. La valeur par défaut de `$select` dans `Tiers.php` a été corrigée.
- **Format de date YYYY-MM-DD** (2026-02-23) : Confirmé par tests que tous les endpoints acceptant une date exigent strictement le format `YYYY-MM-DD`. Documenté dans la section "Remarques et points d'attention". - **Colonnes de recherche `third_list`** (2026-02-23) : Confirmé par tests que `third_list` recherche dans `name`, `groupid`, `vat`. Il est impossible de rechercher par `custid`.
- **Paramètre results sur document_list** (2026-02-23) : Le paramètre `results` fonctionne réellement sur `document_list` (contrairement à `art_list` et `third_list`). Ajouté dans le formulaire et le code PHP. - **Casse du paramètre `thirdid`** (2026-02-23) : `third_GetArtHistory` exige `thirdid` en minuscules. `THIRDID` provoque une erreur HTTP 400.
- **Document_GetPDF fonctionnel** (2026-02-23) : L'endpoint a été reclassé de "non fonctionnel" à "partiellement fonctionnel". Le paramètre LAYOUT doit être une valeur numérique en string.
- **Format de date YYYY-MM-DD** (2026-02-23) : Confirmé par tests que tous les endpoints acceptant une date exigent strictement le format `YYYY-MM-DD`.
- **Toggle Lecture/Ecriture** (2026-02-21) : Toutes les pages entité disposent d'un toggle. - **Toggle Lecture/Ecriture** (2026-02-21) : Toutes les pages entité disposent d'un toggle.
- **Endpoints Documents complétés** (2026-02-21) : 9 endpoints couverts.
- **Convention d'écriture avec accents** (2026-02-20) : Tous les contenus en français utilisent les accents. - **Convention d'écriture avec accents** (2026-02-20) : Tous les contenus en français utilisent les accents.
## Historique ## Historique
### 2026-02-23 (session investigation endpoints Documents)
- Investigation complète des 9 endpoints Documents.
- Document_GetPDF reclassé comme fonctionnel (LAYOUT numérique).
- Format de date YYYY-MM-DD confirmé et documenté.
- Codes paydelay et modes de paiement documentés.
- Paramètre `results` ajouté à document_list.
- 1 nouveau test Pest. Total à la fin de cette session : 125 tests.
### 2026-02-23 (session investigation art_list) ### 2026-02-23 (session investigation art_list)
- Investigation paramètre `results` : sans effet sur `art_list` (5 max) et `third_list` (10 max). - Investigation paramètre `results` : sans effet sur `art_list` (5 max) et `third_list` (10 max).
@@ -63,8 +66,8 @@ Aucun travail en cours.
## Prochaines étapes ## Prochaines étapes
- Corriger les 2 tests pré-existants `FilamentDashboardTest`. - Corriger le test pré-existant `FilamentDashboardTest`.
- Tester toutes les pages avec de vraies données API et vérifier le rendu visuel. - Tester toutes les pages avec de vraies données API et vérifier le rendu visuel.
- Éventuellement : pagination / tri côté client pour les grands tableaux. - Éventuellement : pagination / tri côté client pour les grands tableaux (notamment `third_GetArtHistory` qui peut retourner des milliers d'éléments).
- Éventuellement : page de consultation des logs API. - Éventuellement : page de consultation des logs API.
- Éventuellement : investiguer `custom_geninv_updatestock` (clarifier STKID, TOCHECK, MODE auprès du fournisseur). - Éventuellement : investiguer `custom_geninv_updatestock` (clarifier STKID, TOCHECK, MODE auprès du fournisseur).

View File

@@ -20,6 +20,7 @@ L'API Logistics (Flex/ESI Gescom) est un système de gestion commerciale accessi
- **Validation** : Les champs obligatoires sont validés avant chaque appel API avec des messages en français. Les pages distinguent "jamais recherché" de "recherché sans résultat" grace aux propriétés de tracking. - **Validation** : Les champs obligatoires sont validés avant chaque appel API avec des messages en français. Les pages distinguent "jamais recherché" de "recherché sans résultat" grace aux propriétés de tracking.
- **Cohérence visuelle** : Un système de design unifié (composants `x-logistics.*`) garantit une présentation homogène sur toutes les pages. - **Cohérence visuelle** : Un système de design unifié (composants `x-logistics.*`) garantit une présentation homogène sur toutes les pages.
- **Couverture complète des endpoints** : Les 19 endpoints disponibles dans le service sont tous accessibles depuis l'interface, dont 1 non fonctionnel (custom_geninv_updatestock, avec avertissement). L'endpoint Document_GetPDF, initialement considéré non fonctionnel, a été corrigé (LAYOUT doit être une valeur numérique). - **Couverture complète des endpoints** : Les 19 endpoints disponibles dans le service sont tous accessibles depuis l'interface, dont 1 non fonctionnel (custom_geninv_updatestock, avec avertissement). L'endpoint Document_GetPDF, initialement considéré non fonctionnel, a été corrigé (LAYOUT doit être une valeur numérique).
- **Investigation des paramètres** : Chaque endpoint a été testé systématiquement pour documenter les paramètres réels (obligatoires ou non, types, formats, colonnes valides, comportement des paramètres ignorés). Les résultats sont documentés dans `documentation/documentation_api_logistics.md`.
## Expérience utilisateur ## Expérience utilisateur
@@ -30,7 +31,7 @@ L'utilisateur accède au dashboard Filament sur `http://api-logistics.test/admin
3. **Articles** : Toggle Lecture/Ecriture. En lecture : formulaire de recherche (search, select, barcode) + vérification du stock d'un article par son ARTID. L'API retourne un maximum fixe de 5 résultats (non configurable). Le paramètre `barcode` est présent dans le formulaire mais son effet côté API n'est pas observable. En écriture : état vide (aucun endpoint d'écriture disponible). 3. **Articles** : Toggle Lecture/Ecriture. En lecture : formulaire de recherche (search, select, barcode) + vérification du stock d'un article par son ARTID. L'API retourne un maximum fixe de 5 résultats (non configurable). Le paramètre `barcode` est présent dans le formulaire mais son effet côté API n'est pas observable. En écriture : état vide (aucun endpoint d'écriture disponible).
4. **Documents** : Toggle Lecture/Ecriture. En lecture : 7 formulaires (document_list avec results, document_detail, Document_GetStatusList, Document_GetUnitPriceAndVat, Document_GetDueDate, Document_GetAttachListThumbnail, Document_GetPDF). En écriture : 2 formulaires (document_add, document_mod). Le formulaire Document_GetPDF est fonctionnel (LAYOUT numérique obligatoire, ex: "1"). 4. **Documents** : Toggle Lecture/Ecriture. En lecture : 7 formulaires (document_list avec results, document_detail, Document_GetStatusList, Document_GetUnitPriceAndVat, Document_GetDueDate, Document_GetAttachListThumbnail, Document_GetPDF). En écriture : 2 formulaires (document_add, document_mod). Le formulaire Document_GetPDF est fonctionnel (LAYOUT numérique obligatoire, ex: "1").
5. **Journaux** : Toggle Lecture/Ecriture. En lecture : recherche par type de journal (TYPE). En écriture : état vide. 5. **Journaux** : Toggle Lecture/Ecriture. En lecture : recherche par type de journal (TYPE). En écriture : état vide.
6. **Tiers** : Toggle Lecture/Ecriture. En lecture : recherche de tiers (search obligatoire) + historique des articles d'un tiers. En écriture : état vide. 6. **Tiers** : Toggle Lecture/Ecriture. En lecture : recherche de tiers (search obligatoire, recherche dans name/groupid/vat, colonnes par défaut custid/name, max 10 résultats) + historique des articles d'un tiers (thirdid en minuscules, retourne tout l'historique sans limite). En écriture : état vide.
7. **Divers** : Toggle Lecture/Ecriture. En lecture : getserialnumber (numéro de série), codes_list (données par code interne). En écriture : custom_geninv_updatestock (avec bandeau d'avertissement, endpoint non fonctionnel). 7. **Divers** : Toggle Lecture/Ecriture. En lecture : getserialnumber (numéro de série), codes_list (données par code interne). En écriture : custom_geninv_updatestock (avec bandeau d'avertissement, endpoint non fonctionnel).
### Toggle Lecture / Ecriture ### Toggle Lecture / Ecriture

View File

@@ -31,7 +31,6 @@ Dernière mise à jour : 2026-02-23
- [x] Page Documentation avec rendu markdown stylisé et export PDF - [x] Page Documentation avec rendu markdown stylisé et export PDF
- [x] Connectivité API fonctionnelle (serveur `tse-10-test.esi.local`) - [x] Connectivité API fonctionnelle (serveur `tse-10-test.esi.local`)
- [x] Convention d'écriture avec accents français appliquée - [x] Convention d'écriture avec accents français appliquée
- [x] 84 tests Pest passent (205 assertions)
- [x] `README.md` créé - [x] `README.md` créé
- [x] Formatage Pint validé - [x] Formatage Pint validé
- [x] CI GitHub Actions (lint + tests) - [x] CI GitHub Actions (lint + tests)
@@ -59,26 +58,36 @@ Dernière mise à jour : 2026-02-23
- [x] documents.blade.php : champ `results` ajouté, bandeau "non fonctionnel" retiré de GetPDF, placeholder LAYOUT mis à jour - [x] documents.blade.php : champ `results` ajouté, bandeau "non fonctionnel" retiré de GetPDF, placeholder LAYOUT mis à jour
- [x] Documentation API massivement enrichie (réponses réelles, structures détaillées, section endpoints partiellement fonctionnels) - [x] Documentation API massivement enrichie (réponses réelles, structures détaillées, section endpoints partiellement fonctionnels)
- [x] 1 nouveau test Pest (results envoyé en string à document_list) - [x] 1 nouveau test Pest (results envoyé en string à document_list)
- [x] Investigation complète des 2 endpoints Tiers (appels API réels)
- [x] `third_list` : colonnes de recherche confirmées (`name,groupid,vat`, pas `custid`), colonnes valides documentées (15 colonnes), colonne `custname` invalide
- [x] `third_GetArtHistory` : structure de réponse documentée (8 champs), casse `thirdid` obligatoire, retourne tout l'historique sans limite
- [x] Tiers.php : valeur par défaut `$select` corrigée de `custid,custname` à `custid,name`
- [x] tiers.blade.php : placeholder du champ select mis à jour
- [x] Documentation `third_list` et `third_GetArtHistory` massivement enrichie (colonnes valides, métadonnées, exemples de réponse, structure de réponse)
- [x] 3 nouvelles remarques dans la documentation (colonnes third_list vs column_list/cust, colonnes de recherche, casse thirdid)
- [x] 7 nouveaux tests Pest dans TiersPageTest (total : 15 tests)
## Ce qui reste à faire ## Ce qui reste à faire
- [ ] Corriger les 2 tests pré-existants `FilamentDashboardTest` - [ ] Corriger le test pré-existant `FilamentDashboardTest`
- [ ] Vérifier le rendu visuel de toutes les pages avec de vraies données API - [ ] Vérifier le rendu visuel de toutes les pages avec de vraies données API
- [ ] Éventuellement : pagination / tri côté client pour les grands tableaux - [ ] Éventuellement : pagination / tri côté client pour les grands tableaux
- [ ] Éventuellement : page de consultation des logs API - [ ] Éventuellement : page de consultation des logs API
## Problèmes connus ## Problèmes connus
- 2 tests `FilamentDashboardTest` échouent car le dashboard ne contient pas les sections attendues. Tests créés avant la refonte du dashboard. - 1 test `FilamentDashboardTest` échoue car le dashboard ne contient pas les sections attendues. Test créé avant la refonte du dashboard.
- L'erreur `SQLSTATE[HY000] [1049] Unknown database` peut apparaître lors de `composer update` si la base n'est pas encore créée (script `boost:update`). Sans impact une fois la base créée. - L'erreur `SQLSTATE[HY000] [1049] Unknown database` peut apparaître lors de `composer update` si la base n'est pas encore créée (script `boost:update`). Sans impact une fois la base créée.
- L'API retourne chaque colonne en double dans `column_list`. Le `TablesExplorer` déduplique côté client. - L'API retourne chaque colonne en double dans `column_list`. Le `TablesExplorer` déduplique côté client.
- Le paramètre `results` n'a aucun effet sur `art_list` (toujours 5 max) ni sur `third_list` (toujours 10 max). Limite fixe côté serveur. En revanche, `results` fonctionne sur `document_list` et `jnl_list`. - Le paramètre `results` n'a aucun effet sur `art_list` (toujours 5 max) ni sur `third_list` (toujours 10 max). Limite fixe côté serveur. En revanche, `results` fonctionne sur `document_list` et `jnl_list`.
- Le paramètre `barcode` n'a aucun effet observable sur `art_list`. Le paramètre `search` reste obligatoire même avec `barcode`. - Le paramètre `barcode` n'a aucun effet observable sur `art_list`. Le paramètre `search` reste obligatoire même avec `barcode`.
- L'endpoint `custom_geninv_updatestock` reste non fonctionnel (paramètre STKID inconnu). - L'endpoint `custom_geninv_updatestock` reste non fonctionnel (paramètre STKID inconnu).
- La colonne `custname` n'existe pas dans `third_list`. Le nom du tiers est dans la colonne `name`. Beaucoup de colonnes de la table `cust` (visibles dans `column_list/cust`) ne sont pas acceptées par `third_list` dans le paramètre `select`.
- `third_GetArtHistory` retourne l'intégralité de l'historique sans pagination (potentiellement des milliers d'éléments), ce qui peut être lent pour certains tiers.
## Métriques ## Métriques
- Tests : 125 passent, 2 en échec pré-existants - Tests : 134 passent, 1 en échec pré-existant
- Pages Filament : 7 (Documentation, TablesExplorer, Articles, Documents, Journaux, Tiers, Divers) - Pages Filament : 7 (Documentation, TablesExplorer, Articles, Documents, Journaux, Tiers, Divers)
- Composants Blade design system : 10 - Composants Blade design system : 10
- Endpoints API couverts par LogisticsService : 19 - Endpoints API couverts par LogisticsService : 19

View File

@@ -204,7 +204,7 @@ tests/Feature/
JournauxPageTest.php # 6 tests page Journaux (toggle, validation, tracking, erreurs) JournauxPageTest.php # 6 tests page Journaux (toggle, validation, tracking, erreurs)
LogisticsServiceTest.php # 14 tests service API (mocks HTTP) LogisticsServiceTest.php # 14 tests service API (mocks HTTP)
TablesExplorerTest.php # 6 tests page TablesExplorer (Livewire) TablesExplorerTest.php # 6 tests page TablesExplorer (Livewire)
TiersPageTest.php # 8 tests page Tiers (toggle, validation, tracking, erreurs) TiersPageTest.php # 15 tests page Tiers (toggle, validation, tracking, erreurs, métadonnées, casse thirdid)
FilamentDashboardTest.php # Tests dashboard Filament (1 test en échec pré-existant) FilamentDashboardTest.php # Tests dashboard Filament (1 test en échec pré-existant)
DashboardTest.php # Tests dashboard DashboardTest.php # Tests dashboard
ExampleTest.php # Test d'exemple Laravel ExampleTest.php # Test d'exemple Laravel

View File

@@ -109,7 +109,7 @@ Réponse `column_list` : chaque colonne a `name`, `dataType` (C/N/T/D/L/M), `len
| `Document_GetAttachListThumbnail` | `documentGetAttachListThumbnail(string, string)` | Lecture | Miniatures annexes | JNL, NUMBER | | `Document_GetAttachListThumbnail` | `documentGetAttachListThumbnail(string, string)` | Lecture | Miniatures annexes | JNL, NUMBER |
| `Document_GetPDF` | `documentGetPdf(string, string, string)` | Lecture | Génération PDF | JNL, NUMBER, LAYOUT | | `Document_GetPDF` | `documentGetPdf(string, string, string)` | Lecture | Génération PDF | JNL, NUMBER, LAYOUT |
| `third_list` | `thirdList(array)` | Lecture | Liste des tiers (max 10 résultats, limite fixe serveur) | select, search (results sans effet) | | `third_list` | `thirdList(array)` | Lecture | Liste des tiers (max 10 résultats, limite fixe serveur) | select, search (results sans effet) |
| `third_GetArtHistory` | `thirdGetArtHistory(string)` | Lecture | Historique articles tiers | thirdid | | `third_GetArtHistory` | `thirdGetArtHistory(string)` | Lecture | Historique articles tiers | thirdid (minuscules obligatoires) |
| `getserialnumber` | `getSerialNumber()` | Lecture | Numéro de série | - | | `getserialnumber` | `getSerialNumber()` | Lecture | Numéro de série | - |
| `codes_list` | `codesList(array)` | Lecture | Données par code | code | | `codes_list` | `codesList(array)` | Lecture | Données par code | code |
| `document_add` | `documentAdd(array)` | Écriture | Ajout d'un document | ThirdId, Date, Artid[], Qty[], Saleprice[], JNL, ... | | `document_add` | `documentAdd(array)` | Écriture | Ajout d'un document | ThirdId, Date, Artid[], Qty[], Saleprice[], JNL, ... |
@@ -124,6 +124,18 @@ Réponse `column_list` : chaque colonne a `name`, `dataType` (C/N/T/D/L/M), `len
**Codes de délai de paiement** : Les valeurs valides pour `paydelay` (Document_GetDueDate) proviennent de `codes_list` avec `code=PAYDELAY`. Codes courants : `30`, `30F`, `45F`, `50`, `60`, `60F`, `75F`, `90`, `90F`, `0F`. Le suffixe `F` = fin de mois. **Codes de délai de paiement** : Les valeurs valides pour `paydelay` (Document_GetDueDate) proviennent de `codes_list` avec `code=PAYDELAY`. Codes courants : `30`, `30F`, `45F`, `50`, `60`, `60F`, `75F`, `90`, `90F`, `0F`. Le suffixe `F` = fin de mois.
**Particularités `third_list`** :
- Recherche dans `name`, `groupid`, `vat` (pas dans `custid`).
- Colonnes valides pour `select` : `custid`, `name`, `name2`, `vat`, `email`, `groupid`, `website`, `memo`, `paydelay`, `paymode`, `bankname`, `iban`, `bic`, `custtype`, `discount`.
- La colonne `custname` n'existe PAS. Le nom est dans `name`.
- Colonnes par défaut (sans select) : `custid`, `name`.
**Particularités `third_GetArtHistory`** :
- Paramètre `thirdid` en minuscules obligatoire (`THIRDID` = erreur).
- Retourne l'intégralité de l'historique sans limite (potentiellement des milliers d'éléments).
- Structure : `artid`, `artname`, `jnl`, `unitprice`, `qty`, `vatid`, `vatpc`, `s_credate`.
- ID inexistant = tableau vide sans erreur.
### Tables accessibles ### Tables accessibles
art (160 col.), attach (13), barcode (12), category (10), codes (50), cust (216), docdet (82), dochead (212), docpay (22), file (17), hist (50), incodes (24), jnl (155), pers (78), price (28), stk (20) art (160 col.), attach (13), barcode (12), category (10), codes (50), cust (216), docdet (82), dochead (212), docpay (22), file (17), hist (50), incodes (24), jnl (155), pers (78), price (28), stk (20)

View File

@@ -27,7 +27,7 @@
wire:model="select" wire:model="select"
label="Colonnes (select)" label="Colonnes (select)"
id="select" id="select"
placeholder="custid,custname" placeholder="custid,name"
/> />
<x-logistics.form-field <x-logistics.form-field
wire:model="results" wire:model="results"

View File

@@ -32,6 +32,11 @@ it('can switch between read and write modes', function () {
->assertSet('mode', 'read'); ->assertSet('mode', 'read');
}); });
it('has correct default select value', function () {
Livewire::test(Tiers::class)
->assertSet('select', 'custid,name');
});
it('shows validation error when search is empty', function () { it('shows validation error when search is empty', function () {
Http::fake(); Http::fake();
@@ -46,23 +51,48 @@ it('shows validation error when search is empty', function () {
it('searches tiers via third_list', function () { it('searches tiers via third_list', function () {
Http::fake([ Http::fake([
'*/third_list' => Http::response([ '*/third_list' => Http::response([
'data' => [['custid' => 'CUST001', 'custname' => 'Client Test']], 'data' => [['custid' => '0100002174', 'name' => 'ESI SPRL']],
'metadata' => ['rowcount' => 1, 'issuccess' => true], 'metadata' => ['rowCount' => 1, 'source' => 'DBF', 'executionTimeMs' => 112, 'searchColumns' => 'name,groupid,vat', 'selectColumns' => 'custid,name', 'searchTerms' => 'ESI'],
'error' => null,
]),
]);
Livewire::test(Tiers::class)
->set('search', 'ESI')
->set('select', 'custid,name')
->call('searchTiers')
->assertSet('hasSearched', true)
->assertSet('data', [['custid' => '0100002174', 'name' => 'ESI SPRL']])
->assertSet('errorMessage', null);
Http::assertSent(function ($request) {
return str_contains($request->url(), 'third_list')
&& $request->data()['search'] === 'ESI';
});
});
it('sends select and results parameters to third_list', function () {
Http::fake([
'*/third_list' => Http::response([
'data' => [['custid' => '0100002174', 'name' => 'ESI SPRL']],
'metadata' => ['rowCount' => 1, 'source' => 'DBF', 'executionTimeMs' => 100, 'searchColumns' => 'name,groupid,vat', 'selectColumns' => 'custid,name', 'searchTerms' => 'test'],
'error' => null, 'error' => null,
]), ]),
]); ]);
Livewire::test(Tiers::class) Livewire::test(Tiers::class)
->set('search', 'test') ->set('search', 'test')
->set('select', 'custid,custname') ->set('select', 'custid,name,vat')
->call('searchTiers') ->set('results', 20)
->assertSet('hasSearched', true) ->call('searchTiers');
->assertSet('data', [['custid' => 'CUST001', 'custname' => 'Client Test']])
->assertSet('errorMessage', null);
Http::assertSent(function ($request) { Http::assertSent(function ($request) {
$data = $request->data();
return str_contains($request->url(), 'third_list') return str_contains($request->url(), 'third_list')
&& $request->data()['search'] === 'test'; && $data['search'] === 'test'
&& $data['select'] === 'custid,name,vat'
&& $data['results'] === 20;
}); });
}); });
@@ -70,7 +100,7 @@ it('sets hasSearched even when no results', function () {
Http::fake([ Http::fake([
'*/third_list' => Http::response([ '*/third_list' => Http::response([
'data' => [], 'data' => [],
'metadata' => ['rowcount' => 0, 'issuccess' => true], 'metadata' => ['rowCount' => 0, 'source' => 'DBF', 'executionTimeMs' => 100, 'searchColumns' => 'name,groupid,vat', 'selectColumns' => 'custid,name', 'searchTerms' => 'nonexistent'],
'error' => null, 'error' => null,
]), ]),
]); ]);
@@ -82,6 +112,22 @@ it('sets hasSearched even when no results', function () {
->assertSet('data', []); ->assertSet('data', []);
}); });
it('stores metadata from third_list response', function () {
Http::fake([
'*/third_list' => Http::response([
'data' => [['custid' => '0100002174', 'name' => 'ESI SPRL']],
'metadata' => ['rowCount' => 1, 'source' => 'DBF', 'executionTimeMs' => 112, 'searchColumns' => 'name,groupid,vat', 'selectColumns' => 'custid,name', 'searchTerms' => 'ESI'],
'error' => null,
]),
]);
Livewire::test(Tiers::class)
->set('search', 'ESI')
->call('searchTiers')
->assertSet('metadata.rowCount', 1)
->assertSet('metadata.searchColumns', 'name,groupid,vat');
});
it('shows validation error when historyThirdId is empty', function () { it('shows validation error when historyThirdId is empty', function () {
Http::fake(); Http::fake();
@@ -96,8 +142,19 @@ it('shows validation error when historyThirdId is empty', function () {
it('gets art history for a third party', function () { it('gets art history for a third party', function () {
Http::fake([ Http::fake([
'*/third_GetArtHistory' => Http::response([ '*/third_GetArtHistory' => Http::response([
'data' => [['artid' => 'ART001', 'qty' => 5]], 'data' => [
'metadata' => ['rowcount' => 1, 'issuccess' => true], [
'artid' => 'ART001',
'artname' => 'Article Test',
'jnl' => '03VEN',
'unitprice' => 220,
'qty' => 1,
'vatid' => '21',
'vatpc' => 21,
's_credate' => '2025-06-03',
],
],
'metadata' => ['rowCount' => 1, 'source' => 'DBF'],
'error' => null, 'error' => null,
]), ]),
]); ]);
@@ -106,23 +163,101 @@ it('gets art history for a third party', function () {
->set('historyThirdId', 'CUST001') ->set('historyThirdId', 'CUST001')
->call('getArtHistory') ->call('getArtHistory')
->assertSet('hasHistory', true) ->assertSet('hasHistory', true)
->assertSet('historyData', [['artid' => 'ART001', 'qty' => 5]])
->assertSet('errorMessage', null); ->assertSet('errorMessage', null);
Http::assertSent(function ($request) {
return str_contains($request->url(), 'third_GetArtHistory')
&& $request->data()['thirdid'] === 'CUST001';
});
}); });
it('displays error message on API failure', function () { it('sends thirdid in lowercase key to third_GetArtHistory', function () {
Http::fake([
'*/third_GetArtHistory' => Http::response([
'data' => [],
'metadata' => ['rowCount' => 0, 'source' => 'DBF'],
'error' => null,
]),
]);
Livewire::test(Tiers::class)
->set('historyThirdId', '0100002174')
->call('getArtHistory');
Http::assertSent(function ($request) {
return str_contains($request->url(), 'third_GetArtHistory')
&& array_key_exists('thirdid', $request->data())
&& ! array_key_exists('THIRDID', $request->data());
});
});
it('displays error message on third_list API failure', function () {
Http::fake([ Http::fake([
'*/third_list' => Http::response([ '*/third_list' => Http::response([
'data' => null, 'data' => null,
'metadata' => ['rowcount' => 0, 'issuccess' => false], 'metadata' => ['rowcount' => 0, 'issuccess' => false],
'error' => 'Invalid API key', 'error' => 'Search terms are required. Please provide a search query.',
]), ]),
]); ]);
Livewire::test(Tiers::class) Livewire::test(Tiers::class)
->set('search', 'test') ->set('search', 'test')
->call('searchTiers') ->call('searchTiers')
->assertSet('hasSearched', true); ->assertSet('hasSearched', true)
->assertSet('data', []);
expect(true)->toBeTrue(); });
it('displays error message on third_GetArtHistory API failure', function () {
Http::fake([
'*/third_GetArtHistory' => Http::response([
'data' => null,
'metadata' => ['isSuccess' => false],
'error' => ['thirdid parameter is required.'],
], 400),
]);
Livewire::test(Tiers::class)
->set('historyThirdId', 'INVALID')
->call('getArtHistory')
->assertSet('hasHistory', true)
->assertSet('historyData', []);
});
it('handles third_GetArtHistory returning empty data for unknown thirdid', function () {
Http::fake([
'*/third_GetArtHistory' => Http::response([
'data' => [],
'metadata' => ['rowCount' => 0, 'source' => 'DBF'],
'error' => null,
]),
]);
Livewire::test(Tiers::class)
->set('historyThirdId', 'XXXXXX')
->call('getArtHistory')
->assertSet('hasHistory', true)
->assertSet('historyData', [])
->assertSet('errorMessage', null);
});
it('filters out empty select parameter', function () {
Http::fake([
'*/third_list' => Http::response([
'data' => [['custid' => '0100002174', 'name' => 'ESI SPRL']],
'metadata' => ['rowCount' => 1, 'source' => 'DBF', 'executionTimeMs' => 100, 'searchColumns' => 'name,groupid,vat', 'selectColumns' => 'custid,name', 'searchTerms' => 'test'],
'error' => null,
]),
]);
Livewire::test(Tiers::class)
->set('search', 'test')
->set('select', '')
->call('searchTiers');
Http::assertSent(function ($request) {
$data = $request->data();
return str_contains($request->url(), 'third_list')
&& ! array_key_exists('select', $data);
});
}); });