diff --git a/api.py b/api.py index 61e9a85..6b5d2cb 100644 --- a/api.py +++ b/api.py @@ -162,6 +162,31 @@ class ClientCreateAPIRequest(BaseModel): tva_intra: Optional[str] = None +class ClientUpdateRequest(BaseModel): + """Modèle pour modification d'un client existant""" + intitule: Optional[str] = Field(None, min_length=1, max_length=69) + adresse: Optional[str] = Field(None, max_length=35) + code_postal: Optional[str] = Field(None, max_length=9) + ville: Optional[str] = Field(None, max_length=35) + pays: Optional[str] = Field(None, max_length=35) + email: Optional[EmailStr] = None + telephone: Optional[str] = Field(None, max_length=21) + siret: Optional[str] = Field(None, max_length=14) + tva_intra: Optional[str] = Field(None, max_length=25) + + class Config: + json_schema_extra = { + "example": { + "intitule": "SARL TEST MODIFIÉ", + "adresse": "456 Avenue des Champs", + "code_postal": "75008", + "ville": "Paris", + "email": "nouveau@email.fr", + "telephone": "0198765432" + } + } + + from pydantic import BaseModel from typing import List, Optional from datetime import datetime @@ -368,6 +393,79 @@ async def rechercher_clients(query: Optional[str] = Query(None)): logger.error(f"Erreur recherche clients: {e}") raise HTTPException(500, str(e)) +@app.get("/clients/{code}", tags=["US-A1"]) +async def lire_client_detail(code: str): + """ + 📄 Lecture détaillée d'un client par son code + + Args: + code: Code du client (ex: "CLI000001", "SARL", etc.) + + Returns: + Toutes les informations du client + """ + try: + client = sage_client.lire_client(code) + + if not client: + raise HTTPException(404, f"Client {code} introuvable") + + return { + "success": True, + "data": client + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Erreur lecture client {code}: {e}") + raise HTTPException(500, str(e)) + + +@app.put("/clients/{code}", tags=["US-A1"]) +async def modifier_client( + code: str, + client_update: ClientUpdateRequest, + session: AsyncSession = Depends(get_session) +): + """ + ✏️ Modification d'un client existant + + Args: + code: Code du client à modifier + client_update: Champs à mettre à jour (seuls les champs fournis seront modifiés) + + Returns: + Client modifié avec ses nouvelles valeurs + + Example: + PUT /clients/SARL + { + "email": "nouveau@email.fr", + "telephone": "0198765432" + } + """ + try: + # Appel à la gateway Windows + resultat = sage_client.modifier_client(code, client_update.dict(exclude_none=True)) + + logger.info(f"✅ Client {code} modifié avec succès") + + return { + "success": True, + "message": f"Client {code} modifié avec succès", + "client": resultat + } + + except ValueError as e: + # Erreur métier (client introuvable, etc.) + logger.warning(f"Erreur métier modification client {code}: {e}") + raise HTTPException(404, str(e)) + except Exception as e: + # Erreur technique + logger.error(f"Erreur technique modification client {code}: {e}") + raise HTTPException(500, str(e)) + @app.post("/clients", status_code=201, tags=["US-A8"]) async def ajouter_client( client: ClientCreateAPIRequest, @@ -1213,6 +1311,34 @@ async def lister_factures( raise HTTPException(500, str(e)) +@app.get("/factures/{numero}", tags=["US-A7"]) +async def lire_facture_detail(numero: str): + """ + 📄 Lecture détaillée d'une facture avec ses lignes + + Args: + numero: Numéro de la facture (ex: "FA000001") + + Returns: + Facture complète avec lignes, client, totaux, etc. + """ + try: + facture = sage_client.lire_document(numero, TypeDocument.FACTURE) + + if not facture: + raise HTTPException(404, f"Facture {numero} introuvable") + + return { + "success": True, + "data": facture + } + + except HTTPException: + raise + except Exception as e: + logger.error(f"Erreur lecture facture {numero}: {e}") + raise HTTPException(500, str(e)) + class RelanceFactureRequest(BaseModel): doc_id: str message_personnalise: Optional[str] = None diff --git a/sage_client.py b/sage_client.py index 0037c63..732fe2d 100644 --- a/sage_client.py +++ b/sage_client.py @@ -191,9 +191,6 @@ class SageGatewayClient: payload["statut"] = statut return self._post("/sage/commandes/list", payload).get("data", []) - # ===================================================== - # FACTURES (US-A7) - # ===================================================== def lister_factures( self, limit: int = 100, statut: Optional[int] = None ) -> List[Dict]: @@ -339,6 +336,23 @@ class SageGatewayClient: """ # 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", {}) # Instance globale