Implement CRUD functionality for Articles and Tiers with enhanced API documentation
- Introduced new endpoints for creating and modifying articles (`art_add`, `art_mod`) and tiers (`third_add`, `third_mod`), allowing users to manage these entities effectively. - Updated the Articles and Tiers pages to include forms for adding and modifying records, complete with parameter tables for clear guidance on required inputs. - Enhanced the API documentation to include detailed descriptions, examples, and metadata for the new endpoints, improving usability and understanding for developers. - Created a new rule for writing conventions with French accents to ensure consistency across the project. - Updated existing documentation to reflect structural changes and added a summary table for CRUD operations. - Added tests to verify the functionality of the new features and ensure robust error handling.
This commit is contained in:
46
.cursor/rules/accents.mdc
Normal file
46
.cursor/rules/accents.mdc
Normal file
@@ -0,0 +1,46 @@
|
||||
---
|
||||
description: Convention d'écriture avec accents français
|
||||
globs:
|
||||
alwaysApply: true
|
||||
---
|
||||
|
||||
# Convention d'écriture avec accents français
|
||||
|
||||
Tous les contenus rédigés en français dans le projet doivent utiliser les accents et caractères spéciaux appropriés.
|
||||
|
||||
## Règles
|
||||
|
||||
1. **Messages d'erreur** : utiliser les accents dans tous les messages affichés à l'utilisateur.
|
||||
- Correct : `Le champ délai de paiement est obligatoire.`
|
||||
- Incorrect : `Le champ delai de paiement est obligatoire.`
|
||||
|
||||
2. **Labels et placeholders** : les libellés de formulaires, titres de sections, placeholders et textes d'aide doivent inclure les accents.
|
||||
- Correct : `Identifiant de l'article`, `Récupération de données`, `Général`
|
||||
- Incorrect : `Identifiant de l'article`, `Recuperation de donnees`, `General`
|
||||
|
||||
3. **Documentation** : le fichier `documentation/documentation_api_logistics.md` et les fichiers `memory-bank/*.md` doivent utiliser les accents.
|
||||
|
||||
4. **Commentaires PHP et PHPDoc** : les commentaires rédigés en français dans le code PHP doivent utiliser les accents.
|
||||
|
||||
5. **Vues Blade** : tous les textes visibles dans les fichiers `resources/views/**/*.blade.php` doivent utiliser les accents.
|
||||
|
||||
6. **Tests** : les descriptions de tests Pest (`it('...')`) et les messages d'assertion peuvent rester en anglais (convention Pest). Les messages d'erreur vérifiés dans les assertions doivent correspondre exactement aux messages du code source (avec accents si le code source en contient).
|
||||
|
||||
## Caractères courants
|
||||
|
||||
| Sans accent | Avec accent |
|
||||
|-------------|-------------|
|
||||
| recuperation | récupération |
|
||||
| element | élément |
|
||||
| cle | clé |
|
||||
| numero | numéro |
|
||||
| general | général |
|
||||
| reponse | réponse |
|
||||
| requete | requête |
|
||||
| metadonnees | métadonnées |
|
||||
| parametres | paramètres |
|
||||
| entite | entité |
|
||||
| echéance | échéance |
|
||||
| creé | créé |
|
||||
| modifié | modifié |
|
||||
| supprimé | supprimé |
|
||||
@@ -1,70 +1,72 @@
|
||||
# Update Documentation
|
||||
|
||||
Quand l'utilisateur dit **"update documentation"**, tu DOIS mettre a jour le fichier `documentation/documentation_api_logistics.md` en suivant cette procedure.
|
||||
Quand l'utilisateur dit **"update documentation"**, tu DOIS mettre à jour le fichier `documentation/documentation_api_logistics.md` en suivant cette procédure.
|
||||
|
||||
## Procedure de mise a jour
|
||||
## Procédure de mise à jour
|
||||
|
||||
1. **Lire les sources suivantes** (dans cet ordre) :
|
||||
- `app/Services/LogisticsService.php` : toutes les methodes publiques = endpoints disponibles. Les PHPDoc `@param` contiennent les parametres attendus.
|
||||
- `config/logistics.php` : configuration de connexion (variables d'environnement, valeurs par defaut).
|
||||
- `app/Services/LogisticsService.php` : toutes les méthodes publiques = endpoints disponibles. Les PHPDoc `@param` contiennent les paramètres attendus.
|
||||
- `config/logistics.php` : configuration de connexion (variables d'environnement, valeurs par défaut).
|
||||
- `.env` : valeurs actuelles des variables de configuration.
|
||||
- `documentation/documentation_api_logistics.md` : documentation existante a mettre a jour.
|
||||
- `documentation/documentation_api_logistics.md` : documentation existante à mettre à jour.
|
||||
- `memory-bank/techContext.md` : contexte technique (tables, types de colonnes, endpoints connus).
|
||||
|
||||
2. **Identifier les changements** :
|
||||
- Nouvelles methodes dans `LogisticsService` = nouveaux endpoints a documenter.
|
||||
- Methodes supprimees = endpoints a retirer.
|
||||
- Parametres modifies (PHPDoc `@param`) = mise a jour des tableaux de parametres.
|
||||
- Nouvelles variables d'environnement dans `config/logistics.php` = mise a jour de la section pre-requis.
|
||||
- Nouvelles méthodes dans `LogisticsService` = nouveaux endpoints à documenter.
|
||||
- Méthodes supprimées = endpoints à retirer.
|
||||
- Paramètres modifiés (PHPDoc `@param`) = mise à jour des tableaux de paramètres.
|
||||
- Nouvelles variables d'environnement dans `config/logistics.php` = mise à jour de la section pré-requis.
|
||||
|
||||
3. **Mettre a jour le fichier** en preservant strictement cette structure :
|
||||
3. **Mettre à jour le fichier** en préservant strictement cette structure :
|
||||
|
||||
```
|
||||
# Documentation API Logistics (Flex/ESI Gescom)
|
||||
Derniere mise a jour : <date du jour>
|
||||
Dernière mise à jour : <date du jour>
|
||||
|
||||
## Table des matieres
|
||||
## 1. Pre-requis
|
||||
## 2. Comment effectuer des requetes
|
||||
## 3. Structure de reponse
|
||||
## 4. Tables et colonnes disponibles
|
||||
## 5. Recuperation de donnees
|
||||
### 5.1 Structure de la base de donnees (tables_list, column_list)
|
||||
### 5.2 Articles (art_list, art_getstk)
|
||||
### 5.3 Journaux (jnl_list)
|
||||
### 5.4 Documents (document_list, document_detail, Document_GetStatusList, Document_GetUnitPriceAndVat, Document_GetDueDate, Document_GetAttachListThumbnail)
|
||||
### 5.5 Tiers (third_list, third_GetArtHistory)
|
||||
### 5.6 Divers (getserialnumber, codes_list)
|
||||
## 6. Envoi de donnees
|
||||
### 6.1 Ajout d'un document (document_add)
|
||||
### 6.2 Modification d'un document (document_mod)
|
||||
## 7. Endpoints non fonctionnels
|
||||
## 8. Relations entre entites
|
||||
## Table des matières
|
||||
## 1. Pré-requis
|
||||
## 2. Environnements d'utilisation
|
||||
## 3. Comment effectuer des requêtes
|
||||
## 4. Structure de réponse
|
||||
## 5. Tables et colonnes disponibles
|
||||
## 6. Récupération de données
|
||||
### 6.1 Structure de la base de données (tables_list, column_list)
|
||||
### 6.2 Articles (art_list, art_getstk)
|
||||
### 6.3 Journaux (jnl_list)
|
||||
### 6.4 Documents (document_list, document_detail, Document_GetStatusList, Document_GetUnitPriceAndVat, Document_GetDueDate, Document_GetAttachListThumbnail, Document_GetPDF)
|
||||
### 6.5 Tiers (third_list, third_GetArtHistory)
|
||||
### 6.6 Divers (getserialnumber, codes_list)
|
||||
## 7. Envoi de données
|
||||
### 7.1 Documents (document_add, document_mod)
|
||||
### 7.2 Articles (art_add, art_mod)
|
||||
### 7.3 Tiers (third_add, third_mod)
|
||||
### 7.4 Divers (custom_geninv_updatestock)
|
||||
## 8. Relations entre entités
|
||||
## 9. Remarques et points d'attention
|
||||
## 10. Ressources externes
|
||||
```
|
||||
|
||||
4. **Pour chaque endpoint, documenter** :
|
||||
- Description fonctionnelle (a quoi il sert).
|
||||
- Description fonctionnelle (à quoi il sert).
|
||||
- URL au format `POST /{dossier}/{endpoint}`.
|
||||
- Methode service correspondante (`LogisticsService::methode()`).
|
||||
- Tableau des parametres : nom, type, obligatoire (Oui/Non), description detaillee.
|
||||
- Exemple de requete (body JSON).
|
||||
- Exemple de reponse si disponible.
|
||||
- Méthode service correspondante (`LogisticsService::méthode()`).
|
||||
- Tableau des paramètres : nom, type, obligatoire (Oui/Non), description détaillée.
|
||||
- Métadonnées retournées (tableau).
|
||||
- Exemple de requête (body JSON).
|
||||
- Exemple de réponse succès et erreur.
|
||||
|
||||
5. **Classer les endpoints** :
|
||||
- Section 5 (Recuperation) : endpoints qui lisent des donnees (toutes les methodes sauf `documentAdd` et `documentMod`).
|
||||
- Section 6 (Envoi) : endpoints qui creent ou modifient des donnees (`documentAdd`, `documentMod`).
|
||||
- Section 7 : endpoints identifies mais non fonctionnels.
|
||||
- Section 6 (Récupération) : endpoints qui lisent des données.
|
||||
- Section 7 (Envoi) : endpoints qui créent ou modifient des données (`documentAdd`, `documentMod`, `artAdd`, `artMod`, `thirdAdd`, `thirdMod`, `customGeninvUpdatestock`).
|
||||
|
||||
6. **Mettre a jour la date** en haut du fichier (`Derniere mise a jour : <date du jour>`).
|
||||
6. **Mettre à jour la date** en haut du fichier (`Dernière mise à jour : <date du jour>`).
|
||||
|
||||
## Regles
|
||||
## Règles
|
||||
|
||||
- Ne jamais supprimer d'information existante sans raison (endpoint supprime du service).
|
||||
- Ne jamais divulguer ou ecrire des informations sensibles (cles d'API, mots de passe, identifiants de connexion, tokens, secrets ou toute autre donnee confidentielle). Utiliser des valeurs fictives ou des placeholders (ex. `votre-cle-api`, `********`, `{API_KEY}`) dans les exemples.
|
||||
- Ne jamais supprimer d'information existante sans raison (endpoint supprimé du service).
|
||||
- Ne jamais divulguer ou écrire des informations sensibles (clés d'API, mots de passe, identifiants de connexion, tokens, secrets ou toute autre donnée confidentielle). Utiliser des valeurs fictives ou des placeholders (ex. `votre-cle-api`, `********`, `{API_KEY}`) dans les exemples.
|
||||
- Ton factuel et concis, sans emojis.
|
||||
- Toujours inclure les chemins de fichiers exacts dans les references.
|
||||
- Les exemples de requete doivent utiliser des valeurs realistes mais ne contenant aucune donnee sensible.
|
||||
- La table des matieres doit refleter les sections du document.
|
||||
- Les endpoints non fonctionnels restent documentes avec le statut "Non fonctionnel" et la description du probleme.
|
||||
- Toujours inclure les chemins de fichiers exacts dans les références.
|
||||
- Les exemples de requête doivent utiliser des valeurs réalistes mais ne contenant aucune donnée sensible.
|
||||
- La table des matières doit refléter les sections du document.
|
||||
- Utiliser les accents français dans tout le contenu.
|
||||
|
||||
@@ -30,10 +30,28 @@ class Articles extends Page
|
||||
|
||||
public string $stockArticleId = '';
|
||||
|
||||
// art_add
|
||||
public string $addArtId = '';
|
||||
|
||||
public string $addName = '';
|
||||
|
||||
public string $addSalePrice = '';
|
||||
|
||||
// art_mod
|
||||
public string $modArtId = '';
|
||||
|
||||
public string $modName = '';
|
||||
|
||||
public string $modSalePrice = '';
|
||||
|
||||
public array $data = [];
|
||||
|
||||
public array $stockData = [];
|
||||
|
||||
public array $addResult = [];
|
||||
|
||||
public array $modResult = [];
|
||||
|
||||
public ?array $metadata = null;
|
||||
|
||||
public ?string $errorMessage = null;
|
||||
@@ -42,6 +60,10 @@ class Articles extends Page
|
||||
|
||||
public bool $hasCheckedStock = false;
|
||||
|
||||
public bool $hasAdded = false;
|
||||
|
||||
public bool $hasModified = false;
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, type: string, required: string, description: string}>
|
||||
*/
|
||||
@@ -93,6 +115,104 @@ class Articles extends Page
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, type: string, required: string, description: string}>
|
||||
*/
|
||||
public function paramTableArtAdd(): array
|
||||
{
|
||||
return [
|
||||
['name' => 'ARTID', 'type' => 'string', 'required' => 'Oui', 'description' => "Identifiant unique de l'article à créer. Doit être unique dans la table art."],
|
||||
['name' => 'NAME1', 'type' => 'string', 'required' => 'Non', 'description' => "Nom / libellé de l'article."],
|
||||
['name' => 'SALEPRICE', 'type' => 'string', 'required' => 'Non', 'description' => 'Prix de vente unitaire (format string, ex : "99.99").'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, type: string, required: string, description: string}>
|
||||
*/
|
||||
public function paramTableArtMod(): array
|
||||
{
|
||||
return [
|
||||
['name' => 'ARTID', 'type' => 'string', 'required' => 'Oui', 'description' => "Identifiant de l'article à modifier. Doit exister dans la table art."],
|
||||
['name' => 'NAME1', 'type' => 'string', 'required' => 'Non', 'description' => "Nouveau nom / libellé de l'article."],
|
||||
['name' => 'SALEPRICE', 'type' => 'string', 'required' => 'Non', 'description' => 'Nouveau prix de vente unitaire (format string).'],
|
||||
];
|
||||
}
|
||||
|
||||
public function addArticle(): void
|
||||
{
|
||||
$this->errorMessage = null;
|
||||
|
||||
if (blank($this->addArtId)) {
|
||||
$this->errorMessage = 'Le champ identifiant article (ARTID) est obligatoire.';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->hasAdded = true;
|
||||
|
||||
try {
|
||||
$service = app(LogisticsService::class);
|
||||
|
||||
$params = ['ARTID' => $this->addArtId];
|
||||
|
||||
if (filled($this->addName)) {
|
||||
$params['NAME1'] = $this->addName;
|
||||
}
|
||||
if (filled($this->addSalePrice)) {
|
||||
$params['SALEPRICE'] = $this->addSalePrice;
|
||||
}
|
||||
|
||||
$response = $service->artAdd($params);
|
||||
|
||||
$this->addResult = $response['data'] ?? [];
|
||||
$this->errorMessage = ApiErrorTranslator::translate($response['error'] ?? null);
|
||||
} catch (LogisticsApiException $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->addResult = [];
|
||||
} catch (\Throwable $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->addResult = [];
|
||||
}
|
||||
}
|
||||
|
||||
public function modArticle(): void
|
||||
{
|
||||
$this->errorMessage = null;
|
||||
|
||||
if (blank($this->modArtId)) {
|
||||
$this->errorMessage = 'Le champ identifiant article (ARTID) est obligatoire.';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->hasModified = true;
|
||||
|
||||
try {
|
||||
$service = app(LogisticsService::class);
|
||||
|
||||
$params = ['ARTID' => $this->modArtId];
|
||||
|
||||
if (filled($this->modName)) {
|
||||
$params['NAME1'] = $this->modName;
|
||||
}
|
||||
if (filled($this->modSalePrice)) {
|
||||
$params['SALEPRICE'] = $this->modSalePrice;
|
||||
}
|
||||
|
||||
$response = $service->artMod($params);
|
||||
|
||||
$this->modResult = $response['data'] ?? [];
|
||||
$this->errorMessage = ApiErrorTranslator::translate($response['error'] ?? null);
|
||||
} catch (LogisticsApiException $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->modResult = [];
|
||||
} catch (\Throwable $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->modResult = [];
|
||||
}
|
||||
}
|
||||
|
||||
public function getStock(): void
|
||||
{
|
||||
$this->errorMessage = null;
|
||||
|
||||
@@ -30,10 +30,30 @@ class Tiers extends Page
|
||||
|
||||
public string $historyThirdId = '';
|
||||
|
||||
// third_add
|
||||
public string $addName = '';
|
||||
|
||||
public string $addVat = '';
|
||||
|
||||
public string $addEmail = '';
|
||||
|
||||
// third_mod
|
||||
public string $modCustId = '';
|
||||
|
||||
public string $modName = '';
|
||||
|
||||
public string $modVat = '';
|
||||
|
||||
public string $modEmail = '';
|
||||
|
||||
public array $data = [];
|
||||
|
||||
public array $historyData = [];
|
||||
|
||||
public array $addResult = [];
|
||||
|
||||
public array $modResult = [];
|
||||
|
||||
public ?array $metadata = null;
|
||||
|
||||
public ?string $errorMessage = null;
|
||||
@@ -42,6 +62,10 @@ class Tiers extends Page
|
||||
|
||||
public bool $hasHistory = false;
|
||||
|
||||
public bool $hasAdded = false;
|
||||
|
||||
public bool $hasModified = false;
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, type: string, required: string, description: string}>
|
||||
*/
|
||||
@@ -64,6 +88,104 @@ class Tiers extends Page
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, type: string, required: string, description: string}>
|
||||
*/
|
||||
public function paramTableThirdAdd(): array
|
||||
{
|
||||
return [
|
||||
['name' => 'NAME', 'type' => 'string', 'required' => 'Non', 'description' => 'Nom du tiers (raison sociale ou nom complet).'],
|
||||
['name' => 'VAT', 'type' => 'string', 'required' => 'Non', 'description' => 'Numéro de TVA (ex : BE0123456789).'],
|
||||
['name' => 'EMAIL', 'type' => 'string', 'required' => 'Non', 'description' => 'Adresse e-mail du tiers.'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, array{name: string, type: string, required: string, description: string}>
|
||||
*/
|
||||
public function paramTableThirdMod(): array
|
||||
{
|
||||
return [
|
||||
['name' => 'CUSTID', 'type' => 'string', 'required' => 'Oui', 'description' => 'Identifiant du tiers à modifier (champ custid de la table cust). Doit exister.'],
|
||||
['name' => 'NAME', 'type' => 'string', 'required' => 'Non', 'description' => 'Nouveau nom du tiers.'],
|
||||
['name' => 'VAT', 'type' => 'string', 'required' => 'Non', 'description' => 'Nouveau numéro de TVA.'],
|
||||
['name' => 'EMAIL', 'type' => 'string', 'required' => 'Non', 'description' => 'Nouvelle adresse e-mail.'],
|
||||
];
|
||||
}
|
||||
|
||||
public function addTiers(): void
|
||||
{
|
||||
$this->errorMessage = null;
|
||||
$this->hasAdded = true;
|
||||
|
||||
try {
|
||||
$service = app(LogisticsService::class);
|
||||
|
||||
$params = [];
|
||||
|
||||
if (filled($this->addName)) {
|
||||
$params['NAME'] = $this->addName;
|
||||
}
|
||||
if (filled($this->addVat)) {
|
||||
$params['VAT'] = $this->addVat;
|
||||
}
|
||||
if (filled($this->addEmail)) {
|
||||
$params['EMAIL'] = $this->addEmail;
|
||||
}
|
||||
|
||||
$response = $service->thirdAdd($params);
|
||||
|
||||
$this->addResult = $response['data'] ?? [];
|
||||
$this->errorMessage = ApiErrorTranslator::translate($response['error'] ?? null);
|
||||
} catch (LogisticsApiException $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->addResult = [];
|
||||
} catch (\Throwable $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->addResult = [];
|
||||
}
|
||||
}
|
||||
|
||||
public function modTiers(): void
|
||||
{
|
||||
$this->errorMessage = null;
|
||||
|
||||
if (blank($this->modCustId)) {
|
||||
$this->errorMessage = 'Le champ identifiant tiers (CUSTID) est obligatoire.';
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$this->hasModified = true;
|
||||
|
||||
try {
|
||||
$service = app(LogisticsService::class);
|
||||
|
||||
$params = ['CUSTID' => $this->modCustId];
|
||||
|
||||
if (filled($this->modName)) {
|
||||
$params['NAME'] = $this->modName;
|
||||
}
|
||||
if (filled($this->modVat)) {
|
||||
$params['VAT'] = $this->modVat;
|
||||
}
|
||||
if (filled($this->modEmail)) {
|
||||
$params['EMAIL'] = $this->modEmail;
|
||||
}
|
||||
|
||||
$response = $service->thirdMod($params);
|
||||
|
||||
$this->modResult = $response['data'] ?? [];
|
||||
$this->errorMessage = ApiErrorTranslator::translate($response['error'] ?? null);
|
||||
} catch (LogisticsApiException $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->modResult = [];
|
||||
} catch (\Throwable $e) {
|
||||
$this->errorMessage = ApiErrorTranslator::translate($e->getMessage());
|
||||
$this->modResult = [];
|
||||
}
|
||||
}
|
||||
|
||||
public function searchTiers(): void
|
||||
{
|
||||
$this->errorMessage = null;
|
||||
|
||||
@@ -162,6 +162,38 @@ class LogisticsService
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{ARTID: string, NAME1?: string, SALEPRICE?: string, ...} $params
|
||||
*/
|
||||
public function artAdd(array $params): array
|
||||
{
|
||||
return $this->post('art_add', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{ARTID: string, NAME1?: string, SALEPRICE?: string, ...} $params
|
||||
*/
|
||||
public function artMod(array $params): array
|
||||
{
|
||||
return $this->post('art_mod', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{NAME?: string, VAT?: string, EMAIL?: string, ...} $params
|
||||
*/
|
||||
public function thirdAdd(array $params): array
|
||||
{
|
||||
return $this->post('third_add', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{CUSTID: string, NAME?: string, VAT?: string, EMAIL?: string, ...} $params
|
||||
*/
|
||||
public function thirdMod(array $params): array
|
||||
{
|
||||
return $this->post('third_mod', $params);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array{ARTID: string, STKID: string, QTY: string, TOCHECK?: string, TOCHECKDETAIL?: string, MODE?: string} $params
|
||||
*/
|
||||
|
||||
@@ -7,12 +7,48 @@ Dernière mise à jour : 2026-02-23
|
||||
## Table des matières
|
||||
|
||||
1. [Pré-requis](#1-pré-requis)
|
||||
- [Connexion VPN](#connexion-vpn)
|
||||
- [Accès au serveur](#accès-au-serveur)
|
||||
- [Clé API](#clé-api)
|
||||
- [Dossier](#dossier)
|
||||
- [Variables d'environnement](#variables-denvironnement)
|
||||
- [Configuration Laravel](#configuration-laravel)
|
||||
2. [Environnements d'utilisation](#2-environnements-dutilisation)
|
||||
- 2.1 [Projet local avec VPN](#21-projet-local-avec-vpn)
|
||||
- 2.2 [Bureau à distance (Postman)](#22-bureau-à-distance-postman)
|
||||
- 2.3 [Récapitulatif des différences](#23-récapitulatif-des-différences)
|
||||
3. [Comment effectuer des requêtes](#3-comment-effectuer-des-requêtes)
|
||||
- [Méthode HTTP](#méthode-http)
|
||||
- [Format de l'URL](#format-de-lurl)
|
||||
- [Headers obligatoires](#headers-obligatoires)
|
||||
- [Exemple de requête complète](#exemple-de-requête-complète)
|
||||
- [Paramètres des requêtes](#paramètres-des-requêtes)
|
||||
- [Gestion des erreurs](#gestion-des-erreurs)
|
||||
- [Validation des champs](#validation-des-champs)
|
||||
4. [Structure de réponse](#4-structure-de-réponse)
|
||||
- [Format standard](#format-standard)
|
||||
- [Description des clés](#description-des-clés)
|
||||
- [Exemple de réponse réussie](#exemple-de-réponse-réussie)
|
||||
- [Exemple de réponse en erreur](#exemple-de-réponse-en-erreur)
|
||||
- [Métadonnées spécifiques par endpoint](#métadonnées-spécifiques-par-endpoint)
|
||||
5. [Tables et colonnes disponibles](#5-tables-et-colonnes-disponibles)
|
||||
- [Liste des tables](#liste-des-tables)
|
||||
- [Types de colonnes](#types-de-colonnes)
|
||||
- [Colonnes systeme communes](#colonnes-systeme-communes)
|
||||
- [Colonnes detaillees par table](#colonnes-detaillees-par-table)
|
||||
- [Exploration des colonnes](#exploration-des-colonnes)
|
||||
6. [Récupération de données](#6-récupération-de-données)
|
||||
- 6.1 [Structure de la base de données (tables_list, column_list)](#61-structure-de-la-base-de-données)
|
||||
- 6.2 [Articles (art_list, art_getstk)](#62-articles)
|
||||
- 6.3 [Journaux (jnl_list)](#63-journaux)
|
||||
- 6.4 [Documents (document_list, document_detail, Document_GetStatusList, Document_GetUnitPriceAndVat, Document_GetDueDate, Document_GetAttachListThumbnail, Document_GetPDF)](#64-documents)
|
||||
- 6.5 [Tiers (third_list, third_GetArtHistory)](#65-tiers)
|
||||
- 6.6 [Divers (getserialnumber, codes_list, custom_geninv_updatestock)](#66-divers)
|
||||
7. [Envoi de données](#7-envoi-de-données)
|
||||
- 7.1 [Documents (document_add, document_mod)](#71-documents)
|
||||
- 7.2 [Articles (art_add, art_mod)](#72-articles)
|
||||
- 7.3 [Tiers (third_add, third_mod)](#73-tiers)
|
||||
- 7.4 [Divers (custom_geninv_updatestock)](#74-divers)
|
||||
8. [Relations entre entités](#8-relations-entre-entités)
|
||||
9. [Remarques et points d'attention](#9-remarques-et-points-dattention)
|
||||
10. [Ressources externes](#10-ressources-externes)
|
||||
@@ -2223,7 +2259,19 @@ Le paramètre `STKID` doit correspondre à un dépôt ayant un journal d'inventa
|
||||
|
||||
Les endpoints de cette section permettent de créer ou modifier des données dans le système de gestion via l'API.
|
||||
|
||||
### 7.1 Ajout d'un document
|
||||
**Récapitulatif des opérations d'écriture par page** :
|
||||
|
||||
| Page | Création | Modification | Suppression |
|
||||
|------|:--------:|:------------:|:-----------:|
|
||||
| **Documents** | `document_add` | `document_mod` | Non disponible |
|
||||
| **Articles** | `art_add` | `art_mod` | Non disponible |
|
||||
| **Tiers** | `third_add` | `third_mod` | Non disponible |
|
||||
| **Divers** | -- | `custom_geninv_updatestock` | Non disponible |
|
||||
| **Journaux** | Non disponible | Non disponible | Non disponible |
|
||||
|
||||
**Remarque** : aucun endpoint de suppression n'est disponible via l'API. Les endpoints `art_del`, `third_del`, `jnl_add`, `jnl_mod`, `jnl_del` et `document_del` n'existent pas (HTTP 404).
|
||||
|
||||
### 7.1 Documents
|
||||
|
||||
#### `document_add` -- Création d'un document
|
||||
|
||||
@@ -2239,7 +2287,7 @@ Crée un nouveau document commercial (devis, commande, facture, etc.) dans un jo
|
||||
| Paramètre | Type | Obligatoire | Description |
|
||||
|-----------|------|:-----------:|-------------|
|
||||
| `ThirdId` | `string` | Oui | Identifiant du tiers (champ `custid` de la table `cust`). Détermine le client ou fournisseur associé au document. |
|
||||
| `Date` | `string` | Oui | Date d'encodage du document (ex : `"2026-02-20"`). |
|
||||
| `Date` | `string` | Oui | Date d'encodage du document au format `YYYY-MM-DD` (ex : `"2026-02-20"`). |
|
||||
| `Artid` | `array` | Oui | Tableau d'identifiants d'articles (champ `artid` de la table `art`). Chaque élément correspond à une ligne du document. |
|
||||
| `Qty` | `array` | Oui | Tableau de quantités. Correspond position par position au tableau `Artid`. Chaque élément est un `string`. |
|
||||
| `Saleprice` | `array` | Oui | Tableau des prix de vente unitaires. Correspond position par position au tableau `Artid`. Chaque élément est un `string`. |
|
||||
@@ -2259,6 +2307,13 @@ Crée un nouveau document commercial (devis, commande, facture, etc.) dans un jo
|
||||
|
||||
**Correspondance des tableaux** : les tableaux `Artid`, `Qty`, `Saleprice`, `Discount`, `Vatid` et `Vatpc` fonctionnent par correspondance positionnelle. L'élément à l'index 0 de chaque tableau concerne la première ligne du document, l'élément à l'index 1 la deuxième ligne, etc.
|
||||
|
||||
**Métadonnées retournées** :
|
||||
|
||||
| Clé | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| `rowcount` | `int` | Nombre d'éléments dans `data` (1 en cas de succès). |
|
||||
| `issuccess` | `bool` | Indique si l'opération a réussi. |
|
||||
|
||||
**Exemple de requête** :
|
||||
|
||||
```json
|
||||
@@ -2282,13 +2337,37 @@ Crée un nouveau document commercial (devis, commande, facture, etc.) dans un jo
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
**Exemple de réponse (succès)** :
|
||||
|
||||
### 7.2 Modification d'un document
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"number": "2026/0002"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": true },
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- tiers inexistant)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"xml": "<VFPData><headererror><errorcode>001</errorcode><description>Thirdid 'INEXISTANT' does not exist !</description></headererror></VFPData>"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": false },
|
||||
"error": ["Code: 001, Description: Thirdid 'INEXISTANT' does not exist !"]
|
||||
}
|
||||
```
|
||||
|
||||
**Remarque** : tous les tableaux (`Artid`, `Qty`, `Saleprice`, `Discount`, `Vatid`, `Vatpc`) doivent avoir la même longueur. Un décalage entre les tableaux peut provoquer des erreurs silencieuses ou des données incorrectes.
|
||||
|
||||
---
|
||||
|
||||
#### `document_mod` -- Modification d'un document existant
|
||||
|
||||
Modifie un document existant identifié par son numéro et son journal. Permet de mettre à jour les lignes d'articles, les prix, le tiers, ou d'ajouter des fichiers joints.
|
||||
Modifie un document existant identifié par son numéro et son journal. Permet de mettre à jour les lignes d'articles, les prix, le tiers, ou d'ajouter des fichiers joints. Les lignes d'articles fournies **remplacent** les lignes existantes du document.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
@@ -2299,7 +2378,7 @@ Modifie un document existant identifié par son numéro et son journal. Permet d
|
||||
|
||||
| Paramètre | Type | Obligatoire | Description |
|
||||
|-----------|------|:-----------:|-------------|
|
||||
| `number` | `string` | Oui | Identifiant du document à modifier. |
|
||||
| `number` | `string` | Oui | Numéro du document à modifier. |
|
||||
| `JNL` | `string` | Oui | Code du journal lié au document. |
|
||||
| `Thirdid` | `string` | Non | Nouvel identifiant du tiers (si modification du tiers associé). |
|
||||
| `Artid` | `array` | Non | Tableau d'identifiants d'articles (remplace les lignes existantes). |
|
||||
@@ -2307,6 +2386,13 @@ Modifie un document existant identifié par son numéro et son journal. Permet d
|
||||
| `Saleprice` | `array` | Non | Tableau des prix de vente unitaires (correspond position par position à `Artid`). |
|
||||
| `Attachments` | `array` | Non | Liste de fichiers joints (même structure que `document_add`). |
|
||||
|
||||
**Métadonnées retournées** :
|
||||
|
||||
| Clé | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| `rowcount` | `int` | Nombre d'éléments dans `data` (1 en cas de succès). |
|
||||
| `issuccess` | `bool` | Indique si l'opération a réussi. |
|
||||
|
||||
**Exemple de requête** :
|
||||
|
||||
```json
|
||||
@@ -2319,6 +2405,375 @@ Modifie un document existant identifié par son numéro et son journal. Permet d
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (succès)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"updated": true
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": true },
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- document inexistant)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"xml": "<VFPData><headererror><errorcode>001</errorcode><description>Document not found</description></headererror></VFPData>"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": false },
|
||||
"error": ["Code: 001, Description: Document not found"]
|
||||
}
|
||||
```
|
||||
|
||||
**Attention** : lorsque des tableaux `Artid`, `Qty` et `Saleprice` sont fournis, ils **remplacent intégralement** les lignes existantes du document. Pour ajouter une ligne sans supprimer les existantes, il faut inclure toutes les lignes (anciennes + nouvelles) dans les tableaux.
|
||||
|
||||
---
|
||||
|
||||
### 7.2 Articles
|
||||
|
||||
#### `art_add` -- Création d'un article
|
||||
|
||||
Crée un nouvel article dans le catalogue. L'identifiant de l'article (`ARTID`) doit être unique. Les autres champs sont optionnels et correspondent aux colonnes de la table `art` (160 colonnes disponibles via `column_list/art`).
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **URL** | `POST /{dossier}/art_add` |
|
||||
| **Méthode service** | `LogisticsService::artAdd(array $params)` |
|
||||
|
||||
**Paramètres** :
|
||||
|
||||
| Paramètre | Type | Obligatoire | Description |
|
||||
|-----------|------|:-----------:|-------------|
|
||||
| `ARTID` | `string` | Oui | Identifiant unique de l'article à créer. Doit être unique dans la table `art`. |
|
||||
| `NAME1` | `string` | Non | Nom / libellé de l'article. |
|
||||
| `SALEPRICE` | `string` | Non | Prix de vente unitaire (format string, ex : `"49.99"`). |
|
||||
|
||||
**Remarque** : d'autres colonnes de la table `art` peuvent être passées en paramètre (en MAJUSCULES). La liste complète des colonnes est disponible via `column_list/art`.
|
||||
|
||||
**Métadonnées retournées** :
|
||||
|
||||
| Clé | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| `rowcount` | `int` | Nombre d'éléments dans `data` (1 en cas de succès). |
|
||||
| `issuccess` | `bool` | Indique si l'opération a réussi. |
|
||||
|
||||
**Exemple de requête** :
|
||||
|
||||
```json
|
||||
{
|
||||
"ARTID": "ART001",
|
||||
"NAME1": "Clavier sans fil Bluetooth",
|
||||
"SALEPRICE": "49.99"
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (succès)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"artid": "ART001"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": true },
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- ARTID déjà existant)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"xml": "<VFPData><headererror><errorcode>001</errorcode><description>Artid 'ART001' already exist ! Please use Art_Mod function</description></headererror></VFPData>"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": false },
|
||||
"error": ["Code: 001, Description: Artid 'ART001' already exist ! Please use Art_Mod function"]
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- ARTID manquant)** :
|
||||
|
||||
Requête avec body vide `{}` ou sans `ARTID` :
|
||||
|
||||
```
|
||||
HTTP 400 -- ARTID is required and cannot be empty.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `art_mod` -- Modification d'un article existant
|
||||
|
||||
Modifie un article existant identifié par son `ARTID`. Seuls les champs fournis sont mis à jour ; les champs omis restent inchangés.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **URL** | `POST /{dossier}/art_mod` |
|
||||
| **Méthode service** | `LogisticsService::artMod(array $params)` |
|
||||
|
||||
**Paramètres** :
|
||||
|
||||
| Paramètre | Type | Obligatoire | Description |
|
||||
|-----------|------|:-----------:|-------------|
|
||||
| `ARTID` | `string` | Oui | Identifiant de l'article à modifier. Doit exister dans la table `art`. |
|
||||
| `NAME1` | `string` | Non | Nouveau nom / libellé de l'article. |
|
||||
| `SALEPRICE` | `string` | Non | Nouveau prix de vente unitaire (format string). |
|
||||
|
||||
**Remarque** : d'autres colonnes de la table `art` peuvent être passées en paramètre (en MAJUSCULES).
|
||||
|
||||
**Métadonnées retournées** :
|
||||
|
||||
| Clé | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| `rowcount` | `int` | Nombre d'éléments dans `data` (1 en cas de succès). |
|
||||
| `issuccess` | `bool` | Indique si l'opération a réussi. |
|
||||
|
||||
**Exemple de requête** :
|
||||
|
||||
```json
|
||||
{
|
||||
"ARTID": "ART001",
|
||||
"NAME1": "Clavier Bluetooth Premium",
|
||||
"SALEPRICE": "59.99"
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (succès)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"artid": "ART001"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": true },
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- ARTID inexistant)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"xml": "<VFPData><headererror><errorcode>001</errorcode><description>Artid 'INEXISTANT' does not exist !</description></headererror></VFPData>"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": false },
|
||||
"error": ["Code: 001, Description: Artid 'INEXISTANT' does not exist !"]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7.3 Tiers
|
||||
|
||||
#### `third_add` -- Création d'un tiers
|
||||
|
||||
Crée un nouveau tiers (client ou fournisseur) dans la base de données. L'API génère automatiquement un identifiant unique au format `_@NNNNNNNN` (ex : `_@00036051`). Aucun paramètre n'est strictement obligatoire, mais il est recommandé de fournir au minimum un nom (`NAME`).
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **URL** | `POST /{dossier}/third_add` |
|
||||
| **Méthode service** | `LogisticsService::thirdAdd(array $params)` |
|
||||
|
||||
**Paramètres** :
|
||||
|
||||
| Paramètre | Type | Obligatoire | Description |
|
||||
|-----------|------|:-----------:|-------------|
|
||||
| `NAME` | `string` | Non | Nom du tiers (raison sociale ou nom complet). |
|
||||
| `VAT` | `string` | Non | Numéro de TVA (ex : `"BE0123456789"`). |
|
||||
| `EMAIL` | `string` | Non | Adresse e-mail du tiers. |
|
||||
|
||||
**Remarque** : d'autres colonnes de la table `cust` peuvent être passées en paramètre (en MAJUSCULES). La liste complète des colonnes est disponible via `column_list/cust`. Attention : toutes les colonnes de `column_list/cust` ne sont pas nécessairement acceptées (voir la remarque 18 sur `third_list`).
|
||||
|
||||
**Métadonnées retournées** :
|
||||
|
||||
| Clé | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| `rowcount` | `int` | Nombre d'éléments dans `data` (1 en cas de succès). |
|
||||
| `issuccess` | `bool` | Indique si l'opération a réussi. |
|
||||
|
||||
**Exemple de requête** :
|
||||
|
||||
```json
|
||||
{
|
||||
"NAME": "DUPONT SPRL",
|
||||
"VAT": "BE0123456789",
|
||||
"EMAIL": "contact@dupont.be"
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (succès)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"thirdid": "_@00036051"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": true },
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
**Attention** : l'endpoint `third_add` est très permissif. Un appel avec un body vide `{}` ou avec des champs vides crée tout de même un nouveau tiers avec un identifiant généré. Vérifiez les données avant l'envoi pour éviter de créer des fiches vides.
|
||||
|
||||
---
|
||||
|
||||
#### `third_mod` -- Modification d'un tiers existant
|
||||
|
||||
Modifie un tiers existant identifié par son `CUSTID`. Seuls les champs fournis sont mis à jour ; les champs omis restent inchangés.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **URL** | `POST /{dossier}/third_mod` |
|
||||
| **Méthode service** | `LogisticsService::thirdMod(array $params)` |
|
||||
|
||||
**Paramètres** :
|
||||
|
||||
| Paramètre | Type | Obligatoire | Description |
|
||||
|-----------|------|:-----------:|-------------|
|
||||
| `CUSTID` | `string` | Oui | Identifiant du tiers à modifier (champ `custid` de la table `cust`). Doit exister. |
|
||||
| `NAME` | `string` | Non | Nouveau nom du tiers. |
|
||||
| `VAT` | `string` | Non | Nouveau numéro de TVA. |
|
||||
| `EMAIL` | `string` | Non | Nouvelle adresse e-mail. |
|
||||
|
||||
**Remarque** : d'autres colonnes de la table `cust` peuvent être passées en paramètre (en MAJUSCULES).
|
||||
|
||||
**Métadonnées retournées** :
|
||||
|
||||
| Clé | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| `rowcount` | `int` | Nombre d'éléments dans `data` (1 en cas de succès). |
|
||||
| `issuccess` | `bool` | Indique si l'opération a réussi. |
|
||||
|
||||
**Exemple de requête** :
|
||||
|
||||
```json
|
||||
{
|
||||
"CUSTID": "_@00036051",
|
||||
"NAME": "DUPONT SA",
|
||||
"EMAIL": "nouveau@dupont.be"
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (succès)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"thirdid": "_@00036051"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": true },
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- CUSTID inexistant)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"xml": "<VFPData><headererror><errorcode>001</errorcode><description>Custid 'INEXISTANT' not exist !</description></headererror></VFPData>"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": false },
|
||||
"error": ["Code: 001, Description: Custid 'INEXISTANT' not exist !"]
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- CUSTID manquant)** :
|
||||
|
||||
Requête avec body vide `{}` ou sans `CUSTID` :
|
||||
|
||||
```
|
||||
HTTP 400 -- CUSTID is required and cannot be empty.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7.4 Divers
|
||||
|
||||
#### `custom_geninv_updatestock` -- Mise à jour du stock
|
||||
|
||||
Met à jour le stock d'un article dans un dépôt. Deux modes de fonctionnement sont disponibles : Inventaire (MODE=0) et Restock (MODE=1). Le mode Restock crée un mouvement de stock entrant associé à un fournisseur.
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| **URL** | `POST /{dossier}/custom_geninv_updatestock` |
|
||||
| **Méthode service** | `LogisticsService::customGeninvUpdatestock(array $params)` |
|
||||
|
||||
**Paramètres** :
|
||||
|
||||
| Paramètre | Type | Obligatoire | Description |
|
||||
|-----------|------|:-----------:|-------------|
|
||||
| `ARTID` | `string` | Oui | Identifiant de l'article (champ `artid` de la table `art`). |
|
||||
| `STKID` | `string` | Oui | Code du dépôt / entrepôt. Valeurs obtenues via `codes_list` avec `code=STOCK` (ex : `"A"`, `"SG"`). |
|
||||
| `QTY` | `string` | Oui | Quantité à ajouter au stock. Peut être négatif pour retirer du stock (ex : `"-5"`). |
|
||||
| `MODE` | `string` | Oui | Mode de mise à jour : `"0"` = Inventaire (journal KI), `"1"` = Restock (journal KM). |
|
||||
| `THIRDID` | `string` | Si MODE=1 | Identifiant du tiers / fournisseur (champ `custid` de la table `cust`). Obligatoire en mode Restock. |
|
||||
| `TOCHECK` | `string` | Oui | Prix de contrôle. Stocké avec le mouvement mais n'affecte pas la quantité de stock. |
|
||||
| `TOCHECKDETAIL` | `string` | Oui | Remarque / détail de contrôle. Texte libre stocké avec le mouvement. |
|
||||
|
||||
**Modes de fonctionnement** :
|
||||
|
||||
| Mode | Valeur | Journal | Description |
|
||||
|------|--------|---------|-------------|
|
||||
| Inventaire | `"0"` | KI | Ajustement d'inventaire. Nécessite un journal KI configuré pour le dépôt. |
|
||||
| Restock | `"1"` | KM | Réapprovisionnement. Nécessite `THIRDID` (fournisseur) et un journal KM configuré. |
|
||||
|
||||
**Métadonnées retournées** :
|
||||
|
||||
| Clé | Type | Description |
|
||||
|-----|------|-------------|
|
||||
| `rowcount` | `int` | Nombre d'éléments dans `data` (1 en cas de succès). |
|
||||
| `issuccess` | `bool` | Indique si l'opération a réussi. |
|
||||
|
||||
**Exemple de requête (mode Restock)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"ARTID": "003R92572",
|
||||
"STKID": "SG",
|
||||
"QTY": "5",
|
||||
"MODE": "1",
|
||||
"THIRDID": "0100002174",
|
||||
"TOCHECK": "12.50",
|
||||
"TOCHECKDETAIL": "Réapprovisionnement fournisseur"
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (succès)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"custom_geninv_updatestock": "OK : Change applied - Artid : 003R92572 - Real stock received (Restock mode) : 5.00"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": true },
|
||||
"error": null
|
||||
}
|
||||
```
|
||||
|
||||
**Exemple de réponse (erreur -- dépôt sans journal KI)** :
|
||||
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"xml": "<VFPData><headererror><errorcode>002</errorcode><description>Invalid parameter, inventory JNL not found for warehouse : A</description></headererror></VFPData>"
|
||||
},
|
||||
"metadata": { "rowcount": 1, "issuccess": false },
|
||||
"error": ["Code: 002, Description: Invalid parameter, inventory JNL not found for warehouse : A"]
|
||||
}
|
||||
```
|
||||
|
||||
**Remarques** :
|
||||
|
||||
- Le paramètre `STKID` correspond à un code de dépôt obtenu via `codes_list` avec `code=STOCK`. Les dépôts disponibles dépendent de la configuration du dossier.
|
||||
- Le MODE=0 (Inventaire) dépend de la configuration des journaux KI du dossier. Dans certains environnements, aucun journal KI n'est configuré pour les dépôts, ce qui rend le MODE=0 non fonctionnel.
|
||||
- Le champ `QTY` peut être négatif pour retirer du stock.
|
||||
- Les champs `TOCHECK` et `TOCHECKDETAIL` sont toujours envoyés (même vides). Ils servent de traçabilité et n'affectent pas la quantité de stock.
|
||||
|
||||
---
|
||||
|
||||
## 8. Relations entre entités
|
||||
|
||||
@@ -6,74 +6,69 @@ Dernière mise à jour : 2026-02-23
|
||||
|
||||
Aucun travail en cours.
|
||||
|
||||
## Changements récents (2026-02-23, session tableaux de paramètres)
|
||||
## Changements récents (2026-02-23, session documentation écriture + CRUD)
|
||||
|
||||
- **Nouveau composant Blade `<x-logistics.param-table>`** : composant réutilisable dans `resources/views/components/logistics/param-table.blade.php`. Accepte un tableau `$params` (chaque élément contient `name`, `type`, `required`, `description`) et génère un tableau de référence des paramètres API avec les colonnes PARAMETRE / TYPE / OBLIGATOIRE / DESCRIPTION. Style conforme au design system (mêmes classes CSS que le tableau brut qui existait dans la page Divers).
|
||||
- **Tableaux de paramètres ajoutés sur toutes les pages** : chaque endpoint de chaque page Filament dispose désormais d'un tableau de référence des paramètres sous le formulaire. Les descriptions proviennent de la documentation API (`documentation/documentation_api_logistics.md`).
|
||||
- **Divers** : `getserialnumber` (aucun paramètre, composant avec tableau vide = non affiché), `codes_list` (2 params), `custom_geninv_updatestock` (7 params, refactorisé depuis le HTML brut).
|
||||
- **Articles** : `art_list` (3 params), `art_getstk` (1 param).
|
||||
- **Journaux** : `jnl_list` (3 params).
|
||||
- **Tiers** : `third_list` (3 params), `third_GetArtHistory` (1 param).
|
||||
- **Documents** : `document_list` (3 params), `document_detail` (2 params), `Document_GetStatusList` (1 param), `Document_GetUnitPriceAndVat` (5 params), `Document_GetDueDate` (2 params), `Document_GetAttachListThumbnail` (2 params), `Document_GetPDF` (3 params), `document_add` (9 params), `document_mod` (6 params).
|
||||
- **Total : 11 composants Blade** dans le design system (ajout de `param-table`).
|
||||
- **Tests** : 147 passent, 2 en échec pré-existant (FilamentDashboardTest). Aucun nouveau test ajouté (les tests existants vérifient le rendu des pages et passent tous).
|
||||
- **Découverte de 4 nouveaux endpoints CRUD** via investigation directe de l'API :
|
||||
- `art_add` (HTTP 400 sans paramètres = existe) : création d'article. Requiert `ARTID` (MAJUSCULES). Accepte `NAME1`, `SALEPRICE` et autres colonnes de la table `art`.
|
||||
- `art_mod` (HTTP 400 sans paramètres = existe) : modification d'article. Requiert `ARTID` existant.
|
||||
- `third_add` (HTTP 200 sans paramètres = existe, très permissif) : création de tiers. Aucun paramètre obligatoire, génère un ID automatique `_@NNNNNNNN`. Accepte `NAME`, `VAT`, `EMAIL`.
|
||||
- `third_mod` (HTTP 400 sans paramètres = existe) : modification de tiers. Requiert `CUSTID` existant (MAJUSCULES).
|
||||
- **Endpoints inexistants (HTTP 404)** : `art_del`, `third_del`, `jnl_add`, `jnl_mod`, `jnl_del`, `document_del`.
|
||||
- **4 nouvelles méthodes dans `LogisticsService`** : `artAdd()`, `artMod()`, `thirdAdd()`, `thirdMod()`. Total : 23 méthodes.
|
||||
- **Page Articles enrichie** : mode écriture avec formulaires `art_add` (création) et `art_mod` (modification), avec tableaux de paramètres et blocs JSON de résultat.
|
||||
- **Page Tiers enrichie** : mode écriture avec formulaires `third_add` (création) et `third_mod` (modification), avec tableaux de paramètres et blocs JSON de résultat.
|
||||
- **Section 7 de la documentation réécrite** : 7 endpoints d'écriture documentés (document_add, document_mod, art_add, art_mod, third_add, third_mod, custom_geninv_updatestock). Chaque endpoint inclut : description, paramètres, métadonnées, exemples de requête, exemples de réponse (succès + erreur), remarques.
|
||||
- **Tableau récapitulatif CRUD** ajouté en introduction de la section 7 (création/modification/suppression par page).
|
||||
- **Table des matières mise à jour** avec sous-sections 7.1 à 7.4.
|
||||
- **Règle Cursor `.cursor/rules/accents.mdc` créée** : formalise la convention d'écriture avec accents français.
|
||||
- **Règle `.cursor/rules/update-documentation.mdc` mise à jour** : structure corrigée (sections 6/7/8 au lieu de 5/6/7, section "Endpoints non fonctionnels" supprimée, nouveaux endpoints ajoutés).
|
||||
- **`DocumentationTest.php` corrigé** : ancres mises à jour (suppression de `8-endpoints-non-fonctionnels`), assertions ajoutées pour `custom_geninv_updatestock`, `art_add`, `art_mod`, `third_add`, `third_mod`.
|
||||
- **6 nouveaux tests dans `LogisticsServiceTest.php`** : `documentAdd`, `documentMod`, `artAdd`, `artMod`, `thirdAdd`, `thirdMod`.
|
||||
- **7 nouveaux tests dans `ArticlesPageTest.php`** : `art_add` (succès, validation, paramètres optionnels, erreur doublon), `art_mod` (succès, validation, erreur inexistant).
|
||||
- **6 nouveaux tests dans `TiersPageTest.php`** : `third_add` (succès, paramètres optionnels, exception), `third_mod` (succès, validation, erreur inexistant).
|
||||
- **Pint** : formatage validé.
|
||||
|
||||
## Décisions récentes
|
||||
|
||||
- **Composant `param-table` plutôt que HTML brut** (2026-02-23) : Le tableau de paramètres existant dans `divers.blade.php` (pour `custom_geninv_updatestock`) a été extrait dans un composant réutilisable `<x-logistics.param-table>` pour éviter la duplication de HTML/CSS sur toutes les pages.
|
||||
- **Tableaux vides non affichés** (2026-02-23) : Le composant `param-table` ne rend rien si le tableau `$params` est vide. Les endpoints sans paramètres (comme `getserialnumber`) n'affichent donc pas de tableau inutile.
|
||||
- **`custom_geninv_updatestock` fonctionnel** (2026-02-23) : L'endpoint a été reclassé de "non fonctionnel" à "fonctionnel" en MODE=1 (Restock). STKID = code de dépôt (obtenu via `codes_list` STOCK). MODE=1 nécessite THIRDID. MODE=0 dépend de la configuration des journaux KI.
|
||||
- **`codes_list` correspondance exacte** (2026-02-23) : Le paramètre `code` fonctionne par correspondance exacte sur le nom du groupe, pas par préfixe. Sensible à la casse (MAJUSCULES).
|
||||
- **`getserialnumber` structure réponse** (2026-02-23) : Le champ `data` est un objet `{ "getserialnumber": "..." }`, pas une chaîne directe.
|
||||
- **Colonne `name` au lieu de `custname`** (2026-02-23) : La colonne `custname` n'existe pas dans `third_list`. Le nom est dans `name`.
|
||||
- **Document_GetPDF fonctionnel** (2026-02-23) : LAYOUT doit être une valeur numérique en string.
|
||||
- **Format de date YYYY-MM-DD** (2026-02-23) : Tous les endpoints date exigent ce format.
|
||||
- **Investigation CRUD via requêtes directes** (2026-02-23) : Envoi de requêtes POST à des endpoints hypothétiques pour découvrir lesquels existent. HTTP 400 (validation error) = endpoint existe. HTTP 404 = endpoint inexistant.
|
||||
- **Paramètres en MAJUSCULES pour CRUD** (2026-02-23) : Les endpoints `art_add`, `art_mod`, `third_add`, `third_mod` exigent les noms de paramètres en MAJUSCULES (`ARTID`, `CUSTID`, `NAME1`, `NAME`, etc.).
|
||||
- **`third_add` sans paramètre obligatoire** (2026-02-23) : L'endpoint crée un tiers même avec un body vide. L'UI ne bloque pas l'envoi sans paramètre car l'API l'accepte, mais un avertissement est documenté.
|
||||
- **Règle Cursor accents** (2026-02-23) : Formalisation de la convention existante (memory bank 2026-02-20) dans une règle `.cursor/rules/accents.mdc` pour garantir son application systématique.
|
||||
- **Composant `param-table` plutôt que HTML brut** (2026-02-23) : Le tableau de paramètres existant dans `divers.blade.php` a été extrait dans un composant réutilisable.
|
||||
- **Toggle Lecture/Ecriture** (2026-02-21) : Toutes les pages entité disposent d'un toggle.
|
||||
- **Convention d'écriture avec accents** (2026-02-20) : Tous les contenus en français utilisent les accents.
|
||||
|
||||
## Historique
|
||||
|
||||
### 2026-02-23 (session tableaux de paramètres)
|
||||
|
||||
- Nouveau composant Blade `<x-logistics.param-table>`.
|
||||
- Tableaux de paramètres ajoutés sur toutes les pages (17 endpoints).
|
||||
- Total : 11 composants Blade dans le design system.
|
||||
|
||||
### 2026-02-23 (session investigation endpoints Divers)
|
||||
|
||||
- Investigation complète des 3 endpoints Divers.
|
||||
- `getserialnumber` : structure réponse documentée.
|
||||
- `codes_list` : correspondance exacte, sensible à la casse, chaîne vide = liste maître.
|
||||
- `custom_geninv_updatestock` : reclassé fonctionnel en MODE=1 Restock.
|
||||
- 12 nouveaux tests. Total à la fin : 145 tests.
|
||||
- `custom_geninv_updatestock` reclassé fonctionnel en MODE=1 Restock.
|
||||
- 12 nouveaux tests.
|
||||
|
||||
### 2026-02-23 (session investigation endpoints Tiers)
|
||||
|
||||
- Investigation complète des 2 endpoints Tiers.
|
||||
- `third_list` : colonnes de recherche (name, groupid, vat), 15 colonnes valides, colonne `custname` invalide.
|
||||
- `third_GetArtHistory` : thirdid minuscules, historique complet sans limite.
|
||||
- 7 nouveaux tests. Total à la fin : 134 tests.
|
||||
- 7 nouveaux tests.
|
||||
|
||||
### 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é.
|
||||
- 1 nouveau test. Total à la fin : 125 tests.
|
||||
|
||||
### 2026-02-23 (session investigation art_list)
|
||||
|
||||
- Investigation paramètre `results` et `barcode` sur art_list/third_list.
|
||||
- 2 nouveaux tests barcode.
|
||||
|
||||
### 2026-02-23 (session gestion erreurs et validation)
|
||||
|
||||
- Création de `ApiErrorTranslator`. Validation des champs obligatoires. Propriétés de tracking.
|
||||
- 4 nouveaux fichiers de tests. Total : 122 tests.
|
||||
- 1 nouveau test.
|
||||
|
||||
### 2026-02-21 (session endpoints manquants)
|
||||
|
||||
- 2 méthodes ajoutées à `LogisticsService`. Pages Documents, Divers, toggle sur toutes les pages.
|
||||
- 23 nouveaux tests.
|
||||
|
||||
### 2026-02-20
|
||||
|
||||
- Page Documentation, système de design, composants Blade, thème personnalisé, robustesse service.
|
||||
- Page Documentation, système de design, composants Blade, thème personnalisé.
|
||||
|
||||
### 2026-02-19
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ Dernière mise à jour : 2026-02-23
|
||||
- [x] Documentation API rédigée avec accents (`documentation/documentation_api_logistics.md`)
|
||||
- [x] Memory bank créé et structuré (`memory-bank/`, `.cursor/rules/memory-bank.mdc`)
|
||||
- [x] Configuration API Logistics (`.env`, `config/logistics.php`) avec timeout et retry
|
||||
- [x] `LogisticsService` créé (`app/Services/LogisticsService.php`) avec 19 méthodes, timeout, retry, gestion d'erreur
|
||||
- [x] `LogisticsService` créé (`app/Services/LogisticsService.php`) avec 23 méthodes, timeout, retry, gestion d'erreur
|
||||
- [x] `LogisticsApiException` créée (`app/Exceptions/LogisticsApiException.php`) avec messages français
|
||||
- [x] Migration `api_request_logs` créée
|
||||
- [x] Filament v5.0.0 installé et configuré sans authentification
|
||||
@@ -18,7 +18,10 @@ Dernière mise à jour : 2026-02-23
|
||||
- [x] 7 vues Blade associées dans `resources/views/filament/pages/`
|
||||
- [x] Toggle Lecture/Ecriture sur toutes les pages entité (Articles, Documents, Journaux, Tiers, Divers)
|
||||
- [x] Page Documents : 9 endpoints couverts (7 lecture + 2 écriture)
|
||||
- [x] Page Articles : 4 endpoints couverts (2 lecture + 2 écriture : art_add, art_mod)
|
||||
- [x] Page Tiers : 4 endpoints couverts (2 lecture + 2 écriture : third_add, third_mod)
|
||||
- [x] Page Divers : 3 endpoints couverts (2 lecture + 1 écriture fonctionnel en MODE=1 Restock)
|
||||
- [x] Page Journaux : 1 endpoint couvert (1 lecture, aucun endpoint d'écriture disponible via l'API)
|
||||
- [x] Gestion d'erreur dans toutes les pages Filament (LogisticsApiException + Throwable)
|
||||
- [x] Logging des requêtes API réussies et échouées dans `api_request_logs`
|
||||
- [x] Système de design unifié : 11 composants Blade dans `resources/views/components/logistics/`
|
||||
@@ -31,6 +34,7 @@ Dernière mise à jour : 2026-02-23
|
||||
- [x] Page Documentation avec rendu markdown stylisé et export PDF
|
||||
- [x] Connectivité API fonctionnelle (serveur `tse-10-test.esi.local`)
|
||||
- [x] Convention d'écriture avec accents français appliquée
|
||||
- [x] Règle Cursor `.cursor/rules/accents.mdc` créée pour formaliser la convention des accents
|
||||
- [x] `README.md` créé
|
||||
- [x] Formatage Pint validé
|
||||
- [x] CI GitHub Actions (lint + tests)
|
||||
@@ -40,43 +44,31 @@ Dernière mise à jour : 2026-02-23
|
||||
- [x] Badge de comptage corrigé (`count($data)` au lieu de `$metadata['rowcount']`)
|
||||
- [x] Validation des champs obligatoires sur toutes les pages API (messages en français)
|
||||
- [x] Propriétés de tracking (`$hasSearched`, etc.) sur toutes les pages
|
||||
- [x] `ApiErrorTranslator` intégré dans toutes les pages API (Articles, Documents, Divers, Journaux, Tiers, TablesExplorer)
|
||||
- [x] 4 nouveaux fichiers de tests : ArticlesPageTest, JournauxPageTest, TiersPageTest, ApiErrorTranslatorTest
|
||||
- [x] Tests existants mis à jour (DiversPageTest, DocumentsPageTest) avec validation et tracking
|
||||
- [x] `ApiErrorTranslator` intégré dans toutes les pages API
|
||||
- [x] Investigation paramètre `results` : sans effet sur `art_list` (5 max) et `third_list` (10 max), limite fixe côté serveur
|
||||
- [x] Investigation paramètre `barcode` : sans effet observable sur `art_list`, `search` reste obligatoire
|
||||
- [x] Page Articles : `$results` supprimé, `$barcode` ajouté, formulaire mis à jour
|
||||
- [x] Documentation `art_list` et `third_list` corrigée (métadonnées réelles, paramètres inefficaces documentés)
|
||||
- [x] 2 nouveaux tests barcode dans ArticlesPageTest (envoi quand renseigné, omission quand vide)
|
||||
- [x] Investigation complète des 9 endpoints Documents (appels API réels, structures de réponse, formats)
|
||||
- [x] Document_GetPDF reclassé comme fonctionnel (LAYOUT numérique en string, ex: "1")
|
||||
- [x] Format de date YYYY-MM-DD confirmé et documenté pour tous les endpoints avec paramètre date
|
||||
- [x] Codes paydelay documentés (10 codes via codes_list PAYDELAY : 30, 30F, 45F, 50, 60, 60F, 75F, 90, 90F, 0F)
|
||||
- [x] Modes de paiement documentés (codes_list PAYMODE : CAS, VIR, BC, CBEF)
|
||||
- [x] Codes paydelay et paymode documentés via codes_list
|
||||
- [x] Paramètre `results` ajouté à document_list (fonctionne, défaut ~108)
|
||||
- [x] Documents.php : propriété `$results` ajoutée, transmise en string à l'API
|
||||
- [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] 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)
|
||||
- [x] Investigation complète des 3 endpoints Divers (appels API réels)
|
||||
- [x] `getserialnumber` : structure de réponse documentée (objet `{ "getserialnumber": "..." }`, pas une chaîne)
|
||||
- [x] `codes_list` : correspondance exacte (pas préfixe), sensible à la casse, chaîne vide = liste maître (42 groupes), signification des champs documentée
|
||||
- [x] `custom_geninv_updatestock` reclassé comme FONCTIONNEL (MODE=1 Restock). STKID = code de dépôt. THIRDID obligatoire en Restock. QTY négatif possible.
|
||||
- [x] Divers.php : ajout THIRDID, valeur par défaut MODE=1, validation améliorée
|
||||
- [x] divers.blade.php : bandeau mis à jour, champ THIRDID, labels corrigés
|
||||
- [x] Documentation enrichie : getserialnumber (structure réponse), codes_list (2 modes, groupes, champs), custom_geninv_updatestock (reclassé, 7 paramètres, modes, erreurs). Section "Endpoints non fonctionnels" supprimée. 4 nouvelles remarques.
|
||||
- [x] 12 nouveaux tests Pest dans DiversPageTest (total : 22 tests)
|
||||
- [x] Investigation complète des 2 endpoints Tiers et 3 endpoints Divers (appels API réels)
|
||||
- [x] `custom_geninv_updatestock` reclassé comme FONCTIONNEL (MODE=1 Restock)
|
||||
- [x] Composant `<x-logistics.param-table>` créé : tableau de référence des paramètres API réutilisable
|
||||
- [x] Tableaux de paramètres ajoutés sous chaque endpoint de toutes les pages (17 endpoints au total)
|
||||
- [x] Tableau brut HTML de `custom_geninv_updatestock` refactorisé vers le composant `param-table`
|
||||
- [x] Tableaux de paramètres ajoutés sous chaque endpoint de toutes les pages
|
||||
- [x] **Investigation CRUD** : 4 endpoints d'écriture découverts (`art_add`, `art_mod`, `third_add`, `third_mod`), 6 confirmés inexistants (art_del, third_del, jnl_add/mod/del, document_del)
|
||||
- [x] **4 nouvelles méthodes dans LogisticsService** : `artAdd()`, `artMod()`, `thirdAdd()`, `thirdMod()`
|
||||
- [x] **Page Articles : mode écriture implémenté** avec formulaires art_add et art_mod, tableaux de paramètres, blocs JSON de résultat
|
||||
- [x] **Page Tiers : mode écriture implémenté** avec formulaires third_add et third_mod, tableaux de paramètres, blocs JSON de résultat
|
||||
- [x] **Documentation section 7 complète** : 7 endpoints d'écriture documentés avec paramètres, métadonnées, exemples requête/réponse (succès + erreur), remarques
|
||||
- [x] **Tableau récapitulatif CRUD** en introduction de la section 7 (par page)
|
||||
- [x] **DocumentationTest corrigé** : ancres mises à jour, assertions ajoutées pour 5 nouveaux endpoints
|
||||
- [x] **6 nouveaux tests LogisticsServiceTest** : documentAdd, documentMod, artAdd, artMod, thirdAdd, thirdMod
|
||||
- [x] **7 nouveaux tests ArticlesPageTest** : art_add, art_mod (succès, validation, erreurs)
|
||||
- [x] **6 nouveaux tests TiersPageTest** : third_add, third_mod (succès, validation, erreurs)
|
||||
- [x] **Règle update-documentation.mdc mise à jour** : structure corrigée (sections 6/7/8), section "Endpoints non fonctionnels" supprimée
|
||||
|
||||
## Ce qui reste à faire
|
||||
|
||||
@@ -88,21 +80,23 @@ Dernière mise à jour : 2026-02-23
|
||||
## Problèmes connus
|
||||
|
||||
- 2 tests `FilamentDashboardTest` échouent car le dashboard ne contient pas les sections attendues. Tests créés 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.
|
||||
- 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). 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`.
|
||||
- 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.
|
||||
- `custom_geninv_updatestock` MODE=0 (Inventaire) dépend de la configuration des journaux KI du dossier. Dans le dossier de test, aucun journal KI n'est configuré pour les dépôts "A" ou "SG", ce qui rend MODE=0 non fonctionnel dans cet environnement.
|
||||
- La colonne `custname` n'existe pas dans `third_list`. Le nom du tiers est dans la colonne `name`.
|
||||
- `third_GetArtHistory` retourne l'intégralité de l'historique sans pagination.
|
||||
- `custom_geninv_updatestock` MODE=0 (Inventaire) dépend de la configuration des journaux KI du dossier.
|
||||
- `third_add` est très permissif : un body vide crée un tiers avec un ID auto-généré. Risque de fiches vides.
|
||||
- Aucun endpoint de suppression disponible via l'API (art_del, third_del, document_del = HTTP 404).
|
||||
|
||||
## Métriques
|
||||
|
||||
- Tests : 147 passent, 2 en échec pré-existant
|
||||
- Tests : ~166 (estimation après ajout de 19 nouveaux tests)
|
||||
- Pages Filament : 7 (Documentation, TablesExplorer, Articles, Documents, Journaux, Tiers, Divers)
|
||||
- Composants Blade design system : 11 (card, section-header, error-banner, stat-bar, stat-item, data-table, empty-state, search-input, form-field, json-block, param-table)
|
||||
- Endpoints API couverts par LogisticsService : 19
|
||||
- Endpoints accessibles depuis l'interface : 19 (tous fonctionnels, MODE=0 de custom_geninv_updatestock dépend de la config)
|
||||
- Composants Blade design system : 11
|
||||
- Endpoints API couverts par LogisticsService : 23 (16 lecture + 7 écriture)
|
||||
- Endpoints accessibles depuis l'interface : 23
|
||||
- Migrations : 5 (users, cache, jobs, two_factor, api_request_logs)
|
||||
- Règles Cursor : 4 (laravel-boost, memory-bank, design-system, update-documentation)
|
||||
- Règles Cursor : 5 (laravel-boost, memory-bank, design-system, update-documentation, accents)
|
||||
- Classes support : 1 (ApiErrorTranslator)
|
||||
|
||||
@@ -92,7 +92,7 @@ Fichier de config : `config/logistics.php`
|
||||
Réponse `tables_list` : chaque table a `name` et `columnCount`.
|
||||
Réponse `column_list` : chaque colonne a `name`, `dataType` (C/N/T/D/L/M), `length`, `precision`. Les colonnes sont retournées en double par l'API (dédupliquées côté client).
|
||||
|
||||
### Endpoints (19 méthodes dans LogisticsService)
|
||||
### Endpoints (23 méthodes dans LogisticsService)
|
||||
|
||||
| Endpoint | Méthode service | Type | Description | Paramètres principaux |
|
||||
|----------|----------------|------|-------------|-----------------------|
|
||||
@@ -114,10 +114,20 @@ Réponse `column_list` : chaque colonne a `name`, `dataType` (C/N/T/D/L/M), `len
|
||||
| `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_mod` | `documentMod(array)` | Écriture | Modification d'un document | number, Thirdid, Artid[], Qty[], Saleprice[], JNL, ... |
|
||||
| `art_add` | `artAdd(array)` | Écriture | Création d'un article | ARTID (obligatoire), NAME1, SALEPRICE, ... |
|
||||
| `art_mod` | `artMod(array)` | Écriture | Modification d'un article | ARTID (obligatoire, existant), NAME1, SALEPRICE, ... |
|
||||
| `third_add` | `thirdAdd(array)` | Écriture | Création d'un tiers | NAME, VAT, EMAIL (aucun obligatoire, ID auto-généré) |
|
||||
| `third_mod` | `thirdMod(array)` | Écriture | Modification d'un tiers | CUSTID (obligatoire, existant), NAME, VAT, EMAIL, ... |
|
||||
| `custom_geninv_updatestock` | `customGeninvUpdatestock(array)` | Écriture | Mise à jour stock (Restock/Inventaire) | ARTID, STKID, QTY, TOCHECK, TOCHECKDETAIL, MODE, THIRDID |
|
||||
|
||||
**Endpoints inexistants (HTTP 404)** : `art_del`, `third_del`, `jnl_add`, `jnl_mod`, `jnl_del`, `document_del`. Aucune opération de suppression n'est disponible via l'API.
|
||||
|
||||
**Endpoints partiellement fonctionnels** : `Document_GetPDF` (LAYOUT doit être une valeur numérique en string, ex: `"1"`. Les valeurs textuelles provoquent une erreur. Retourne le PDF en base64). `custom_geninv_updatestock` MODE=0 (Inventaire) dépend de la configuration des journaux KI du dossier.
|
||||
|
||||
**`art_add` / `art_mod`** : Paramètres en MAJUSCULES (`ARTID`, `NAME1`, `SALEPRICE`). `art_add` requiert un ARTID unique (erreur si doublon). `art_mod` requiert un ARTID existant. Autres colonnes de la table `art` acceptées.
|
||||
|
||||
**`third_add` / `third_mod`** : `third_add` est très permissif (aucun paramètre obligatoire, ID auto-généré `_@NNNNNNNN`). `third_mod` requiert `CUSTID` existant (MAJUSCULES). Paramètres : `NAME`, `VAT`, `EMAIL` et autres colonnes `cust`.
|
||||
|
||||
**`custom_geninv_updatestock` (fonctionnel en MODE=1 Restock)** : STKID = code de dépôt (obtenu via `codes_list` STOCK, ex: `"SG"`, `"A"`). MODE=1 (Restock) nécessite THIRDID (fournisseur). TOCHECK = prix de contrôle. TOCHECKDETAIL = remarques. QTY peut être négatif. Les 6 paramètres ARTID, STKID, QTY, TOCHECK, TOCHECKDETAIL, MODE sont tous obligatoires.
|
||||
|
||||
**`codes_list` (correspondance exacte)** : le paramètre `code` fonctionne par correspondance exacte (pas par préfixe), sensible à la casse (MAJUSCULES). Chaîne vide = liste maître des 42 groupes (structure `name`/`prompt1`). Nom exact = valeurs du groupe (structure `vala1`-`vala6`, `valn1`, `valn2`).
|
||||
|
||||
@@ -107,13 +107,89 @@
|
||||
</div>
|
||||
</x-logistics.card>
|
||||
@else
|
||||
{{-- art_add --}}
|
||||
<x-logistics.card>
|
||||
<x-logistics.section-header title="art_add" description="Créer un nouvel article" />
|
||||
<div class="p-6">
|
||||
<x-logistics.empty-state
|
||||
icon="heroicon-o-arrow-up-tray"
|
||||
title="Aucun endpoint d'écriture disponible"
|
||||
description="La section Articles ne dispose pas d'endpoints d'envoi de données."
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
<x-logistics.form-field
|
||||
wire:model="addArtId"
|
||||
label="Identifiant article (ARTID)"
|
||||
id="addArtId"
|
||||
placeholder="Ex: ART001"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="addName"
|
||||
label="Nom (NAME1)"
|
||||
id="addName"
|
||||
placeholder="Ex: Clavier sans fil"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="addSalePrice"
|
||||
label="Prix de vente (SALEPRICE)"
|
||||
id="addSalePrice"
|
||||
placeholder="Ex: 49.99"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-3">
|
||||
<x-filament::button wire:click="addArticle" icon="heroicon-o-plus-circle" color="success">
|
||||
Créer l'article
|
||||
</x-filament::button>
|
||||
<div wire:loading wire:target="addArticle" class="flex items-center gap-2">
|
||||
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||
<span class="text-sm text-gray-500">Création en cours...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-logistics.param-table :params="$this->paramTableArtAdd()" />
|
||||
|
||||
<div wire:loading.remove wire:target="addArticle" class="mt-4">
|
||||
<x-logistics.json-block :data="$addResult" :searched="$hasAdded" />
|
||||
</div>
|
||||
</div>
|
||||
</x-logistics.card>
|
||||
|
||||
{{-- art_mod --}}
|
||||
<x-logistics.card>
|
||||
<x-logistics.section-header title="art_mod" description="Modifier un article existant" />
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
<x-logistics.form-field
|
||||
wire:model="modArtId"
|
||||
label="Identifiant article (ARTID)"
|
||||
id="modArtId"
|
||||
placeholder="Ex: ART001"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="modName"
|
||||
label="Nouveau nom (NAME1)"
|
||||
id="modName"
|
||||
placeholder="Ex: Clavier Bluetooth"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="modSalePrice"
|
||||
label="Nouveau prix de vente (SALEPRICE)"
|
||||
id="modSalePrice"
|
||||
placeholder="Ex: 59.99"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-3">
|
||||
<x-filament::button wire:click="modArticle" icon="heroicon-o-pencil-square" color="warning">
|
||||
Modifier l'article
|
||||
</x-filament::button>
|
||||
<div wire:loading wire:target="modArticle" class="flex items-center gap-2">
|
||||
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||
<span class="text-sm text-gray-500">Modification en cours...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-logistics.param-table :params="$this->paramTableArtMod()" />
|
||||
|
||||
<div wire:loading.remove wire:target="modArticle" class="mt-4">
|
||||
<x-logistics.json-block :data="$modResult" :searched="$hasModified" />
|
||||
</div>
|
||||
</div>
|
||||
</x-logistics.card>
|
||||
@endif
|
||||
|
||||
@@ -109,13 +109,95 @@
|
||||
</div>
|
||||
</x-logistics.card>
|
||||
@else
|
||||
{{-- third_add --}}
|
||||
<x-logistics.card>
|
||||
<x-logistics.section-header title="third_add" description="Créer un nouveau tiers" />
|
||||
<div class="p-6">
|
||||
<x-logistics.empty-state
|
||||
icon="heroicon-o-arrow-up-tray"
|
||||
title="Aucun endpoint d'écriture disponible"
|
||||
description="La section Tiers ne dispose pas d'endpoints d'envoi de données."
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-3">
|
||||
<x-logistics.form-field
|
||||
wire:model="addName"
|
||||
label="Nom (NAME)"
|
||||
id="addName"
|
||||
placeholder="Ex: DUPONT SPRL"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="addVat"
|
||||
label="Numéro de TVA (VAT)"
|
||||
id="addVat"
|
||||
placeholder="Ex: BE0123456789"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="addEmail"
|
||||
label="E-mail (EMAIL)"
|
||||
id="addEmail"
|
||||
placeholder="Ex: contact@example.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-3">
|
||||
<x-filament::button wire:click="addTiers" icon="heroicon-o-plus-circle" color="success">
|
||||
Créer le tiers
|
||||
</x-filament::button>
|
||||
<div wire:loading wire:target="addTiers" class="flex items-center gap-2">
|
||||
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||
<span class="text-sm text-gray-500">Création en cours...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-logistics.param-table :params="$this->paramTableThirdAdd()" />
|
||||
|
||||
<div wire:loading.remove wire:target="addTiers" class="mt-4">
|
||||
<x-logistics.json-block :data="$addResult" :searched="$hasAdded" />
|
||||
</div>
|
||||
</div>
|
||||
</x-logistics.card>
|
||||
|
||||
{{-- third_mod --}}
|
||||
<x-logistics.card>
|
||||
<x-logistics.section-header title="third_mod" description="Modifier un tiers existant" />
|
||||
<div class="p-6">
|
||||
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
<x-logistics.form-field
|
||||
wire:model="modCustId"
|
||||
label="Identifiant tiers (CUSTID)"
|
||||
id="modCustId"
|
||||
placeholder="Ex: 0100005650"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="modName"
|
||||
label="Nouveau nom (NAME)"
|
||||
id="modName"
|
||||
placeholder="Ex: DUPONT SA"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="modVat"
|
||||
label="Nouveau numéro de TVA (VAT)"
|
||||
id="modVat"
|
||||
placeholder="Ex: BE0987654321"
|
||||
/>
|
||||
<x-logistics.form-field
|
||||
wire:model="modEmail"
|
||||
label="Nouvel e-mail (EMAIL)"
|
||||
id="modEmail"
|
||||
placeholder="Ex: nouveau@example.com"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex items-center gap-3">
|
||||
<x-filament::button wire:click="modTiers" icon="heroicon-o-pencil-square" color="warning">
|
||||
Modifier le tiers
|
||||
</x-filament::button>
|
||||
<div wire:loading wire:target="modTiers" class="flex items-center gap-2">
|
||||
<x-filament::loading-indicator class="h-4 w-4 text-primary-500" />
|
||||
<span class="text-sm text-gray-500">Modification en cours...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<x-logistics.param-table :params="$this->paramTableThirdMod()" />
|
||||
|
||||
<div wire:loading.remove wire:target="modTiers" class="mt-4">
|
||||
<x-logistics.json-block :data="$modResult" :searched="$hasModified" />
|
||||
</div>
|
||||
</div>
|
||||
</x-logistics.card>
|
||||
@endif
|
||||
|
||||
@@ -169,3 +169,147 @@ it('displays error message on API failure', function () {
|
||||
|
||||
expect(true)->toBeTrue();
|
||||
});
|
||||
|
||||
// --- art_add ---
|
||||
|
||||
it('adds an article via art_add', function () {
|
||||
Http::fake([
|
||||
'*/art_add' => Http::response([
|
||||
'data' => ['artid' => 'ART001'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => true],
|
||||
'error' => null,
|
||||
]),
|
||||
]);
|
||||
|
||||
Livewire::test(Articles::class)
|
||||
->set('mode', 'write')
|
||||
->set('addArtId', 'ART001')
|
||||
->set('addName', 'Test Article')
|
||||
->set('addSalePrice', '49.99')
|
||||
->call('addArticle')
|
||||
->assertSet('hasAdded', true)
|
||||
->assertSet('addResult', ['artid' => 'ART001'])
|
||||
->assertSet('errorMessage', null);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'art_add')
|
||||
&& $body['ARTID'] === 'ART001'
|
||||
&& $body['NAME1'] === 'Test Article'
|
||||
&& $body['SALEPRICE'] === '49.99';
|
||||
});
|
||||
});
|
||||
|
||||
it('shows validation error when addArtId is empty', function () {
|
||||
Http::fake();
|
||||
|
||||
Livewire::test(Articles::class)
|
||||
->set('mode', 'write')
|
||||
->call('addArticle')
|
||||
->assertSet('hasAdded', false)
|
||||
->assertSet('errorMessage', 'Le champ identifiant article (ARTID) est obligatoire.');
|
||||
|
||||
Http::assertNothingSent();
|
||||
});
|
||||
|
||||
it('omits optional params when empty on art_add', function () {
|
||||
Http::fake([
|
||||
'*/art_add' => Http::response([
|
||||
'data' => ['artid' => 'ART001'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => true],
|
||||
'error' => null,
|
||||
]),
|
||||
]);
|
||||
|
||||
Livewire::test(Articles::class)
|
||||
->set('mode', 'write')
|
||||
->set('addArtId', 'ART001')
|
||||
->set('addName', '')
|
||||
->set('addSalePrice', '')
|
||||
->call('addArticle');
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return $body['ARTID'] === 'ART001'
|
||||
&& ! array_key_exists('NAME1', $body)
|
||||
&& ! array_key_exists('SALEPRICE', $body);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles API error on art_add (duplicate)', function () {
|
||||
Http::fake([
|
||||
'*/art_add' => Http::response([
|
||||
'data' => ['xml' => '<VFPData><headererror><errorcode>001</errorcode><description>Artid already exist</description></headererror></VFPData>'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => false],
|
||||
'error' => ['Code: 001, Description: Artid already exist'],
|
||||
]),
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Articles::class)
|
||||
->set('mode', 'write')
|
||||
->set('addArtId', 'ART001')
|
||||
->call('addArticle');
|
||||
|
||||
expect($component->get('errorMessage'))->toContain('Artid already exist');
|
||||
});
|
||||
|
||||
// --- art_mod ---
|
||||
|
||||
it('modifies an article via art_mod', function () {
|
||||
Http::fake([
|
||||
'*/art_mod' => Http::response([
|
||||
'data' => ['artid' => 'ART001'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => true],
|
||||
'error' => null,
|
||||
]),
|
||||
]);
|
||||
|
||||
Livewire::test(Articles::class)
|
||||
->set('mode', 'write')
|
||||
->set('modArtId', 'ART001')
|
||||
->set('modName', 'Updated Name')
|
||||
->set('modSalePrice', '59.99')
|
||||
->call('modArticle')
|
||||
->assertSet('hasModified', true)
|
||||
->assertSet('modResult', ['artid' => 'ART001'])
|
||||
->assertSet('errorMessage', null);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'art_mod')
|
||||
&& $body['ARTID'] === 'ART001'
|
||||
&& $body['NAME1'] === 'Updated Name';
|
||||
});
|
||||
});
|
||||
|
||||
it('shows validation error when modArtId is empty', function () {
|
||||
Http::fake();
|
||||
|
||||
Livewire::test(Articles::class)
|
||||
->set('mode', 'write')
|
||||
->call('modArticle')
|
||||
->assertSet('hasModified', false)
|
||||
->assertSet('errorMessage', 'Le champ identifiant article (ARTID) est obligatoire.');
|
||||
|
||||
Http::assertNothingSent();
|
||||
});
|
||||
|
||||
it('handles API error on art_mod (not found)', function () {
|
||||
Http::fake([
|
||||
'*/art_mod' => Http::response([
|
||||
'data' => ['xml' => '<VFPData><headererror><errorcode>001</errorcode><description>Artid does not exist</description></headererror></VFPData>'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => false],
|
||||
'error' => ['Code: 001, Description: Artid does not exist'],
|
||||
]),
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Articles::class)
|
||||
->set('mode', 'write')
|
||||
->set('modArtId', 'INEXISTANT')
|
||||
->call('modArticle');
|
||||
|
||||
expect($component->get('errorMessage'))->toContain('Artid does not exist');
|
||||
});
|
||||
|
||||
@@ -35,10 +35,9 @@ it('generates heading IDs matching the table of contents anchors', function () {
|
||||
'5-tables-et-colonnes-disponibles',
|
||||
'6-récupération-de-données',
|
||||
'7-envoi-de-données',
|
||||
'8-endpoints-non-fonctionnels',
|
||||
'9-relations-entre-entités',
|
||||
'10-remarques-et-points-dattention',
|
||||
'11-ressources-externes',
|
||||
'8-relations-entre-entités',
|
||||
'9-remarques-et-points-dattention',
|
||||
'10-ressources-externes',
|
||||
];
|
||||
|
||||
foreach ($anchors as $anchor) {
|
||||
@@ -81,5 +80,10 @@ it('documents all service endpoints', function () {
|
||||
->assertSee('third_list')
|
||||
->assertSee('third_GetArtHistory')
|
||||
->assertSee('getserialnumber')
|
||||
->assertSee('codes_list');
|
||||
->assertSee('codes_list')
|
||||
->assertSee('custom_geninv_updatestock')
|
||||
->assertSee('art_add')
|
||||
->assertSee('art_mod')
|
||||
->assertSee('third_add')
|
||||
->assertSee('third_mod');
|
||||
});
|
||||
|
||||
@@ -205,6 +205,128 @@ it('sends correct parameters for custom_geninv_updatestock', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('sends correct parameters for document_add', function () {
|
||||
Http::fake([
|
||||
'*' => Http::response(['data' => ['number' => '2026/0001'], 'metadata' => ['rowcount' => 1, 'issuccess' => true], 'error' => null]),
|
||||
]);
|
||||
|
||||
$service = app(LogisticsService::class);
|
||||
$params = [
|
||||
'ThirdId' => 'CUST001',
|
||||
'Date' => '2026-02-20',
|
||||
'Artid' => ['ART001', 'ART002'],
|
||||
'Qty' => ['2', '5'],
|
||||
'Saleprice' => ['10.00', '25.50'],
|
||||
'JNL' => 'VEN',
|
||||
];
|
||||
$service->documentAdd($params);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'document_add')
|
||||
&& $body['ThirdId'] === 'CUST001'
|
||||
&& $body['JNL'] === 'VEN'
|
||||
&& $body['Artid'] === ['ART001', 'ART002'];
|
||||
});
|
||||
});
|
||||
|
||||
it('sends correct parameters for document_mod', function () {
|
||||
Http::fake([
|
||||
'*' => Http::response(['data' => ['updated' => true], 'metadata' => ['rowcount' => 1, 'issuccess' => true], 'error' => null]),
|
||||
]);
|
||||
|
||||
$service = app(LogisticsService::class);
|
||||
$params = [
|
||||
'number' => '2026/0001',
|
||||
'JNL' => 'VEN',
|
||||
'Thirdid' => 'CUST002',
|
||||
];
|
||||
$service->documentMod($params);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'document_mod')
|
||||
&& $body['number'] === '2026/0001'
|
||||
&& $body['JNL'] === 'VEN'
|
||||
&& $body['Thirdid'] === 'CUST002';
|
||||
});
|
||||
});
|
||||
|
||||
it('sends correct parameters for art_add', function () {
|
||||
Http::fake([
|
||||
'*' => Http::response(['data' => ['artid' => 'ART001'], 'metadata' => ['rowcount' => 1, 'issuccess' => true], 'error' => null]),
|
||||
]);
|
||||
|
||||
$service = app(LogisticsService::class);
|
||||
$params = ['ARTID' => 'ART001', 'NAME1' => 'Test Article', 'SALEPRICE' => '49.99'];
|
||||
$service->artAdd($params);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'art_add')
|
||||
&& $body['ARTID'] === 'ART001'
|
||||
&& $body['NAME1'] === 'Test Article'
|
||||
&& $body['SALEPRICE'] === '49.99';
|
||||
});
|
||||
});
|
||||
|
||||
it('sends correct parameters for art_mod', function () {
|
||||
Http::fake([
|
||||
'*' => Http::response(['data' => ['artid' => 'ART001'], 'metadata' => ['rowcount' => 1, 'issuccess' => true], 'error' => null]),
|
||||
]);
|
||||
|
||||
$service = app(LogisticsService::class);
|
||||
$params = ['ARTID' => 'ART001', 'NAME1' => 'Updated Article'];
|
||||
$service->artMod($params);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'art_mod')
|
||||
&& $body['ARTID'] === 'ART001'
|
||||
&& $body['NAME1'] === 'Updated Article';
|
||||
});
|
||||
});
|
||||
|
||||
it('sends correct parameters for third_add', function () {
|
||||
Http::fake([
|
||||
'*' => Http::response(['data' => ['thirdid' => '_@00036051'], 'metadata' => ['rowcount' => 1, 'issuccess' => true], 'error' => null]),
|
||||
]);
|
||||
|
||||
$service = app(LogisticsService::class);
|
||||
$params = ['NAME' => 'Test Company', 'VAT' => 'BE0123456789', 'EMAIL' => 'test@example.com'];
|
||||
$service->thirdAdd($params);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'third_add')
|
||||
&& $body['NAME'] === 'Test Company'
|
||||
&& $body['VAT'] === 'BE0123456789';
|
||||
});
|
||||
});
|
||||
|
||||
it('sends correct parameters for third_mod', function () {
|
||||
Http::fake([
|
||||
'*' => Http::response(['data' => ['thirdid' => 'CUST001'], 'metadata' => ['rowcount' => 1, 'issuccess' => true], 'error' => null]),
|
||||
]);
|
||||
|
||||
$service = app(LogisticsService::class);
|
||||
$params = ['CUSTID' => 'CUST001', 'NAME' => 'Updated Company'];
|
||||
$service->thirdMod($params);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'third_mod')
|
||||
&& $body['CUSTID'] === 'CUST001'
|
||||
&& $body['NAME'] === 'Updated Company';
|
||||
});
|
||||
});
|
||||
|
||||
it('includes endpoint info in LogisticsApiException', function () {
|
||||
Http::fake(fn () => throw new ConnectionException('Connection timed out'));
|
||||
|
||||
|
||||
@@ -261,3 +261,133 @@ it('filters out empty select parameter', function () {
|
||||
&& ! array_key_exists('select', $data);
|
||||
});
|
||||
});
|
||||
|
||||
// --- third_add ---
|
||||
|
||||
it('adds a third party via third_add', function () {
|
||||
Http::fake([
|
||||
'*/third_add' => Http::response([
|
||||
'data' => ['thirdid' => '_@00036051'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => true],
|
||||
'error' => null,
|
||||
]),
|
||||
]);
|
||||
|
||||
Livewire::test(Tiers::class)
|
||||
->set('mode', 'write')
|
||||
->set('addName', 'Test Company')
|
||||
->set('addVat', 'BE0123456789')
|
||||
->set('addEmail', 'test@example.com')
|
||||
->call('addTiers')
|
||||
->assertSet('hasAdded', true)
|
||||
->assertSet('addResult', ['thirdid' => '_@00036051'])
|
||||
->assertSet('errorMessage', null);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'third_add')
|
||||
&& $body['NAME'] === 'Test Company'
|
||||
&& $body['VAT'] === 'BE0123456789'
|
||||
&& $body['EMAIL'] === 'test@example.com';
|
||||
});
|
||||
});
|
||||
|
||||
it('omits optional params when empty on third_add', function () {
|
||||
Http::fake([
|
||||
'*/third_add' => Http::response([
|
||||
'data' => ['thirdid' => '_@00036052'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => true],
|
||||
'error' => null,
|
||||
]),
|
||||
]);
|
||||
|
||||
Livewire::test(Tiers::class)
|
||||
->set('mode', 'write')
|
||||
->set('addName', '')
|
||||
->set('addVat', '')
|
||||
->set('addEmail', '')
|
||||
->call('addTiers');
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'third_add')
|
||||
&& ! array_key_exists('NAME', $body)
|
||||
&& ! array_key_exists('VAT', $body)
|
||||
&& ! array_key_exists('EMAIL', $body);
|
||||
});
|
||||
});
|
||||
|
||||
it('handles exception on addTiers', function () {
|
||||
Http::fake([
|
||||
'*/third_add' => Http::response('Server Error', 500),
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Tiers::class)
|
||||
->set('mode', 'write')
|
||||
->set('addName', 'Test')
|
||||
->call('addTiers');
|
||||
|
||||
expect($component->get('errorMessage'))->not->toBeNull();
|
||||
expect($component->get('addResult'))->toBe([]);
|
||||
});
|
||||
|
||||
// --- third_mod ---
|
||||
|
||||
it('modifies a third party via third_mod', function () {
|
||||
Http::fake([
|
||||
'*/third_mod' => Http::response([
|
||||
'data' => ['thirdid' => 'CUST001'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => true],
|
||||
'error' => null,
|
||||
]),
|
||||
]);
|
||||
|
||||
Livewire::test(Tiers::class)
|
||||
->set('mode', 'write')
|
||||
->set('modCustId', 'CUST001')
|
||||
->set('modName', 'Updated Company')
|
||||
->set('modVat', 'BE0987654321')
|
||||
->call('modTiers')
|
||||
->assertSet('hasModified', true)
|
||||
->assertSet('modResult', ['thirdid' => 'CUST001'])
|
||||
->assertSet('errorMessage', null);
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
$body = $request->data();
|
||||
|
||||
return str_contains($request->url(), 'third_mod')
|
||||
&& $body['CUSTID'] === 'CUST001'
|
||||
&& $body['NAME'] === 'Updated Company';
|
||||
});
|
||||
});
|
||||
|
||||
it('shows validation error when modCustId is empty', function () {
|
||||
Http::fake();
|
||||
|
||||
Livewire::test(Tiers::class)
|
||||
->set('mode', 'write')
|
||||
->call('modTiers')
|
||||
->assertSet('hasModified', false)
|
||||
->assertSet('errorMessage', 'Le champ identifiant tiers (CUSTID) est obligatoire.');
|
||||
|
||||
Http::assertNothingSent();
|
||||
});
|
||||
|
||||
it('handles API error on third_mod (not found)', function () {
|
||||
Http::fake([
|
||||
'*/third_mod' => Http::response([
|
||||
'data' => ['xml' => '<VFPData><headererror><errorcode>001</errorcode><description>Custid not exist</description></headererror></VFPData>'],
|
||||
'metadata' => ['rowcount' => 1, 'issuccess' => false],
|
||||
'error' => ['Code: 001, Description: Custid not exist'],
|
||||
]),
|
||||
]);
|
||||
|
||||
$component = Livewire::test(Tiers::class)
|
||||
->set('mode', 'write')
|
||||
->set('modCustId', 'INEXISTANT')
|
||||
->call('modTiers');
|
||||
|
||||
expect($component->get('errorMessage'))->toContain('Custid not exist');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user