refactor(sage_client): remove section comments and redundant docstrings

This commit is contained in:
Fanilo-Nantenaina 2025-12-17 11:14:16 +03:00
parent 0faec99817
commit 42b3164f79
2 changed files with 561 additions and 1011 deletions

1264
api.py

File diff suppressed because it is too large Load diff

View file

@ -63,9 +63,6 @@ class SageGatewayClient:
raise
time.sleep(2**attempt)
# =====================================================
# CLIENTS
# =====================================================
def lister_clients(self, filtre: str = "") -> List[Dict]:
"""Liste tous les clients avec filtre optionnel"""
return self._post("/sage/clients/list", {"filtre": filtre}).get("data", [])
@ -74,9 +71,6 @@ class SageGatewayClient:
"""Lecture d'un client par code"""
return self._post("/sage/clients/get", {"code": code}).get("data")
# =====================================================
# ARTICLES
# =====================================================
def lister_articles(self, filtre: str = "") -> List[Dict]:
"""Liste tous les articles avec filtre optionnel"""
return self._post("/sage/articles/list", {"filtre": filtre}).get("data", [])
@ -85,9 +79,6 @@ class SageGatewayClient:
"""Lecture d'un article par référence"""
return self._post("/sage/articles/get", {"code": ref}).get("data")
# =====================================================
# DEVIS (US-A1)
# =====================================================
def creer_devis(self, devis_data: Dict) -> Dict:
"""Création d'un devis"""
return self._post("/sage/devis/create", devis_data).get("data", {})
@ -102,18 +93,12 @@ class SageGatewayClient:
statut: Optional[int] = None,
inclure_lignes: bool = True,
) -> List[Dict]:
"""
Liste tous les devis avec filtres
"""
payload = {"limit": limit, "inclure_lignes": inclure_lignes}
if statut is not None:
payload["statut"] = statut
return self._post("/sage/devis/list", payload).get("data", [])
def changer_statut_devis(self, numero: str, nouveau_statut: int) -> Dict:
"""
CORRECTION: Utilise query params au lieu du body
"""
try:
r = requests.post(
f"{self.url}/sage/devis/statut",
@ -130,9 +115,6 @@ class SageGatewayClient:
logger.error(f"❌ Erreur changement statut: {e}")
raise
# =====================================================
# DOCUMENTS GÉNÉRIQUES
# =====================================================
def lire_document(self, numero: str, type_doc: int) -> Optional[Dict]:
"""Lecture d'un document générique"""
return self._post(
@ -142,9 +124,6 @@ class SageGatewayClient:
def transformer_document(
self, numero_source: str, type_source: int, type_cible: int
) -> Dict:
"""
CORRECTION: Utilise query params pour la transformation
"""
try:
r = requests.post(
f"{self.url}/sage/documents/transform",
@ -177,15 +156,9 @@ class SageGatewayClient:
)
return resp.get("success", False)
# =====================================================
# COMMANDES (US-A2)
# =====================================================
def lister_commandes(
self, limit: int = 100, statut: Optional[int] = None
) -> List[Dict]:
"""
Utilise l'endpoint /sage/commandes/list qui filtre déjà sur type 10
"""
payload = {"limit": limit}
if statut is not None:
payload["statut"] = statut
@ -194,10 +167,6 @@ class SageGatewayClient:
def lister_factures(
self, limit: int = 100, statut: Optional[int] = None
) -> List[Dict]:
"""
Liste toutes les factures
Utilise l'endpoint /sage/factures/list qui filtre déjà sur type 60
"""
payload = {"limit": limit}
if statut is not None:
payload["statut"] = statut
@ -210,24 +179,15 @@ class SageGatewayClient:
)
return resp.get("success", False)
# =====================================================
# CONTACTS (US-A6)
# =====================================================
def lire_contact_client(self, code_client: str) -> Optional[Dict]:
"""Lecture du contact principal d'un client"""
return self._post("/sage/contact/read", {"code": code_client}).get("data")
# =====================================================
# REMISES (US-A5)
# =====================================================
def lire_remise_max_client(self, code_client: str) -> float:
"""Récupère la remise max autorisée pour un client"""
result = self._post("/sage/client/remise-max", {"code": code_client})
return result.get("data", {}).get("remise_max", 10.0)
# =====================================================
# GÉNÉRATION PDF (pour email_queue)
# =====================================================
def generer_pdf_document(self, doc_id: str, type_doc: int) -> bytes:
"""Génère le PDF d'un document via la gateway Windows"""
try:
@ -253,9 +213,6 @@ class SageGatewayClient:
logger.error(f"Erreur génération PDF: {e}")
raise
# =====================================================
# PROSPECTS
# =====================================================
def lister_prospects(self, filtre: str = "") -> List[Dict]:
"""Liste tous les prospects avec filtre optionnel"""
return self._post("/sage/prospects/list", {"filtre": filtre}).get("data", [])
@ -264,9 +221,6 @@ class SageGatewayClient:
"""Lecture d'un prospect par code"""
return self._post("/sage/prospects/get", {"code": code}).get("data")
# =====================================================
# FOURNISSEURS
# =====================================================
def lister_fournisseurs(self, filtre: str = "") -> List[Dict]:
"""Liste tous les fournisseurs avec filtre optionnel"""
return self._post("/sage/fournisseurs/list", {"filtre": filtre}).get("data", [])
@ -276,37 +230,14 @@ class SageGatewayClient:
return self._post("/sage/fournisseurs/get", {"code": code}).get("data")
def creer_fournisseur(self, fournisseur_data: Dict) -> Dict:
"""
Envoie la requête de création de fournisseur à la gateway Windows.
Args:
fournisseur_data: Dict contenant intitule, compte_collectif, etc.
Returns:
Fournisseur créé avec son numéro définitif
"""
return self._post("/sage/fournisseurs/create", fournisseur_data).get("data", {})
def modifier_fournisseur(self, code: str, fournisseur_data: Dict) -> Dict:
"""
Modification d'un fournisseur existant
Args:
code: Code du fournisseur à modifier
fournisseur_data: Dictionnaire contenant les champs à modifier
(seuls les champs présents seront mis à jour)
Returns:
Fournisseur modifié
"""
return self._post(
"/sage/fournisseurs/update",
{"code": code, "fournisseur_data": fournisseur_data},
).get("data", {})
# =====================================================
# AVOIRS
# =====================================================
def lister_avoirs(
self, limit: int = 100, statut: Optional[int] = None
) -> List[Dict]:
@ -320,9 +251,6 @@ class SageGatewayClient:
"""Lecture d'un avoir avec ses lignes"""
return self._post("/sage/avoirs/get", {"code": numero}).get("data")
# =====================================================
# LIVRAISONS
# =====================================================
def lister_livraisons(
self, limit: int = 100, statut: Optional[int] = None
) -> List[Dict]:
@ -359,206 +287,52 @@ class SageGatewayClient:
return {"status": "down"}
def creer_client(self, client_data: Dict) -> Dict:
"""
Envoie la requête de création de client à la gateway Windows.
:param client_data: Dict contenant intitule, compte_collectif, etc.
"""
# On appelle la route définie dans main.py
return self._post("/sage/clients/create", client_data).get("data", {})
def modifier_client(self, code: str, client_data: Dict) -> Dict:
"""
Modification d'un client existant
Args:
code: Code du client à modifier
client_data: Dictionnaire contenant les champs à modifier
(seuls les champs présents seront mis à jour)
Returns:
Client modifié
"""
return self._post(
"/sage/clients/update", {"code": code, "client_data": client_data}
).get("data", {})
def modifier_devis(self, numero: str, devis_data: Dict) -> Dict:
"""
Modification d'un devis existant
Args:
numero: Numéro du devis à modifier
devis_data: Dictionnaire contenant les champs à modifier:
- date_devis (str, optional): Nouvelle date
- lignes (List, optional): Nouvelles lignes
- statut (int, optional): Nouveau statut
Returns:
Devis modifié avec totaux recalculés
"""
return self._post(
"/sage/devis/update", {"numero": numero, "devis_data": devis_data}
).get("data", {})
def creer_commande(self, commande_data: Dict) -> Dict:
"""
Création d'une nouvelle commande (Bon de commande)
Args:
commande_data: Dictionnaire contenant:
- client_id (str): Code du client
- date_commande (str, optional): Date au format ISO
- reference (str, optional): Référence externe
- lignes (List[Dict]): Liste des lignes avec:
- article_code (str)
- quantite (float)
- prix_unitaire_ht (float, optional)
- remise_pourcentage (float, optional)
Returns:
Commande créée avec son numéro et ses totaux
"""
return self._post("/sage/commandes/create", commande_data).get("data", {})
def modifier_commande(self, numero: str, commande_data: Dict) -> Dict:
"""
Modification d'une commande existante
Args:
numero: Numéro de la commande à modifier
commande_data: Dictionnaire contenant les champs à modifier:
- date_commande (str, optional): Nouvelle date
- lignes (List, optional): Nouvelles lignes
- statut (int, optional): Nouveau statut
- reference (str, optional): Nouvelle référence
Returns:
Commande modifiée avec totaux recalculés
"""
return self._post(
"/sage/commandes/update", {"numero": numero, "commande_data": commande_data}
).get("data", {})
def creer_livraison(self, livraison_data: Dict) -> Dict:
"""
Création d'une nouvelle livraison (Bon de livraison)
"""
return self._post("/sage/livraisons/create", livraison_data).get("data", {})
def modifier_livraison(self, numero: str, livraison_data: Dict) -> Dict:
"""
Modification d'une livraison existante
"""
return self._post(
"/sage/livraisons/update",
{"numero": numero, "livraison_data": livraison_data},
).get("data", {})
def creer_avoir(self, avoir_data: Dict) -> Dict:
"""
Création d'un avoir (Bon d'avoir)
Args:
avoir_data: Dictionnaire contenant:
- client_id (str): Code du client
- date_avoir (str, optional): Date au format ISO
- reference (str, optional): Référence externe
- lignes (List[Dict]): Liste des lignes avec:
- article_code (str)
- quantite (float)
- prix_unitaire_ht (float, optional)
- remise_pourcentage (float, optional)
Returns:
Avoir créé avec son numéro et ses totaux
"""
return self._post("/sage/avoirs/create", avoir_data).get("data", {})
def modifier_avoir(self, numero: str, avoir_data: Dict) -> Dict:
"""
Modification d'un avoir existant
Args:
numero: Numéro de l'avoir à modifier
avoir_data: Dictionnaire contenant les champs à modifier:
- date_avoir (str, optional): Nouvelle date
- lignes (List, optional): Nouvelles lignes
- statut (int, optional): Nouveau statut
- reference (str, optional): Nouvelle référence
Returns:
Avoir modifié avec totaux recalculés
"""
return self._post(
"/sage/avoirs/update", {"numero": numero, "avoir_data": avoir_data}
).get("data", {})
def creer_facture(self, facture_data: Dict) -> Dict:
"""
Création d'une facture
Args:
facture_data: Dictionnaire contenant:
- client_id (str): Code du client
- date_facture (str, optional): Date au format ISO
- reference (str, optional): Référence externe
- lignes (List[Dict]): Liste des lignes avec:
- article_code (str)
- quantite (float)
- prix_unitaire_ht (float, optional)
- remise_pourcentage (float, optional)
Returns:
Facture créée avec son numéro et ses totaux
"""
return self._post("/sage/factures/create", facture_data).get("data", {})
def modifier_facture(self, numero: str, facture_data: Dict) -> Dict:
"""
Modification d'une facture existante
Args:
numero: Numéro de la facture à modifier
facture_data: Dictionnaire contenant les champs à modifier:
- date_facture (str, optional): Nouvelle date
- lignes (List, optional): Nouvelles lignes
- statut (int, optional): Nouveau statut
- reference (str, optional): Nouvelle référence
Returns:
Facture modifiée avec totaux recalculés
"""
return self._post(
"/sage/factures/update", {"numero": numero, "facture_data": facture_data}
).get("data", {})
def generer_pdf_document(self, doc_id: str, type_doc: int) -> bytes:
"""
🆕 Génère le PDF d'un document via la gateway Windows (route généralisée)
**Cette méthode remplace les appels spécifiques par type de document**
Args:
doc_id: Numéro du document (ex: "DE00001", "FA00001")
type_doc: Type de document Sage:
- 0: Devis
- 10: Bon de commande
- 30: Bon de livraison
- 60: Facture
- 50: Bon d'avoir
Returns:
bytes: Contenu du PDF (binaire)
Raises:
ValueError: Si le PDF retourné est vide
RuntimeError: Si erreur de communication avec la gateway
Example:
>>> pdf_bytes = sage_client.generer_pdf_document("DE00001", 0)
>>> with open("devis.pdf", "wb") as f:
... f.write(pdf_bytes)
"""
try:
logger.info(f"📄 Demande génération PDF: doc_id={doc_id}, type={type_doc}")
@ -610,59 +384,49 @@ class SageGatewayClient:
logger.error(f"❌ Erreur génération PDF: {e}", exc_info=True)
raise
def creer_article(self, article_data: Dict) -> Dict:
"""
Création d'un article
Args:
article_data: Dictionnaire contenant:
- reference (str, obligatoire): Référence article
- designation (str, obligatoire): Désignation
- prix_vente (float, optionnel): Prix vente HT
- stock_reel (float, optionnel): Stock initial
- ... (voir ArticleCreateRequest dans main.py)
Returns:
Article créé
Example:
>>> article = sage_client.creer_article({
... "reference": "ART001",
... "designation": "Article test",
... "prix_vente": 10.0,
... "stock_reel": 100.0
... })
"""
return self._post("/sage/articles/create", article_data).get("data", {})
def modifier_article(self, reference: str, article_data: Dict) -> Dict:
"""
Modification d'un article
**Usage critique**: Augmenter le stock pour résoudre l'erreur 2881
Args:
reference: Référence de l'article à modifier
article_data: Dictionnaire contenant les champs à modifier:
- stock_reel (float, optionnel): Nouveau stock
- prix_vente (float, optionnel): Nouveau prix
- ... (seuls les champs présents seront mis à jour)
Returns:
Article modifié
Example - Résoudre erreur de stock:
>>> # L'erreur 2881 indique un stock insuffisant
>>> sage_client.modifier_article("ART001", {
... "stock_reel": 100.0 # Augmenter le stock
... })
"""
return self._post(
"/sage/articles/update",
{"reference": reference, "article_data": article_data}
{"reference": reference, "article_data": article_data},
).get("data", {})
def lister_familles(self, filtre: str = "") -> List[Dict]:
return self._get("/sage/familles", params={"filtre": filtre}).get("data", [])
def lire_famille(self, code: str) -> Optional[Dict]:
try:
response = self._get(f"/sage/familles/{code}")
return response.get("data")
except Exception as e:
logger.error(f"Erreur lecture famille {code}: {e}")
return None
def creer_famille(self, famille_data: Dict) -> Dict:
return self._post("/sage/familles/create", famille_data).get("data", {})
def get_stats_familles(self) -> Dict:
return self._get("/sage/familles/stats").get("data", {})
def creer_entree_stock(self, entree_data: Dict) -> Dict:
return self._post("/sage/stock/entree", entree_data).get("data", {})
def creer_sortie_stock(self, sortie_data: Dict) -> Dict:
return self._post("/sage/stock/sortie", sortie_data).get("data", {})
def lire_mouvement_stock(self, numero: str) -> Optional[Dict]:
try:
response = self._get(f"/sage/stock/mouvement/{numero}")
return response.get("data")
except Exception as e:
logger.error(f"Erreur lecture mouvement {numero}: {e}")
return None
# Instance globale
sage_client = SageGatewayClient()