diff --git a/api.py b/api.py index 8077a9a..6ee5d3f 100644 --- a/api.py +++ b/api.py @@ -191,9 +191,12 @@ async def obtenir_clients( @app.get("/clients/{code}", response_model=ClientDetails, tags=["Clients"]) -async def lire_client_detail(code: str): +async def lire_client_detail( + code: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - client = sage_client.lire_client(code) + client = sage.lire_client(code) if not client: raise HTTPException(404, f"Client {code} introuvable") @@ -212,11 +215,10 @@ async def modifier_client( code: str, client_update: ClientUpdate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - resultat = sage_client.modifier_client( - code, client_update.dict(exclude_none=True) - ) + resultat = sage.modifier_client(code, client_update.dict(exclude_none=True)) logger.info(f"Client {code} modifié avec succès") @@ -236,10 +238,12 @@ async def modifier_client( @app.post("/clients", status_code=201, tags=["Clients"]) async def ajouter_client( - client: ClientCreate, session: AsyncSession = Depends(get_session) + client: ClientCreate, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - nouveau_client = sage_client.creer_client(client.model_dump(mode="json")) + nouveau_client = sage.creer_client(client.model_dump(mode="json")) logger.info(f"Client créé via API: {nouveau_client.get('numero')}") @@ -258,9 +262,12 @@ async def ajouter_client( @app.get("/articles", response_model=List[Article], tags=["Articles"]) -async def rechercher_articles(query: Optional[str] = Query(None)): +async def rechercher_articles( + query: Optional[str] = Query(None), + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - articles = sage_client.lister_articles(filtre=query or "") + articles = sage.lister_articles(filtre=query or "") return [Article(**a) for a in articles] except Exception as e: logger.error(f"Erreur recherche articles: {e}") @@ -273,7 +280,10 @@ async def rechercher_articles(query: Optional[str] = Query(None)): status_code=status.HTTP_201_CREATED, tags=["Articles"], ) -async def creer_article(article: ArticleCreate): +async def creer_article( + article: ArticleCreate, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: if not article.reference or not article.designation: raise HTTPException( @@ -285,7 +295,7 @@ async def creer_article(article: ArticleCreate): logger.info(f"Création article: {article.reference} - {article.designation}") - resultat = sage_client.creer_article(article_data) + resultat = sage.creer_article(article_data) logger.info( f"Article créé: {resultat.get('reference')} (stock: {resultat.get('stock_reel', 0)})" @@ -312,6 +322,7 @@ async def creer_article(article: ArticleCreate): async def modifier_article( reference: str = Path(..., description="Référence de l'article à modifier"), article: ArticleUpdate = Body(...), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: article_data = article.dict(exclude_unset=True) @@ -324,7 +335,7 @@ async def modifier_article( logger.info(f"Modification article {reference}: {list(article_data.keys())}") - resultat = sage_client.modifier_article(reference, article_data) + resultat = sage.modifier_article(reference, article_data) if "stock_reel" in article_data: logger.info( @@ -354,9 +365,10 @@ async def modifier_article( @app.get("/articles/{reference}", response_model=Article, tags=["Articles"]) async def lire_article( reference: str = Path(..., description="Référence de l'article"), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - article = sage_client.lire_article(reference) + article = sage.lire_article(reference) if not article: logger.warning(f"Article {reference} introuvable") @@ -380,7 +392,10 @@ async def lire_article( @app.post("/devis", response_model=Devis, status_code=201, tags=["Devis"]) -async def creer_devis(devis: DevisRequest): +async def creer_devis( + devis: DevisRequest, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: devis_data = { "client_id": devis.client_id, @@ -392,7 +407,7 @@ async def creer_devis(devis: DevisRequest): "lignes": _preparer_lignes_document(devis.lignes), } - resultat = sage_client.creer_devis(devis_data) + resultat = sage.creer_devis(devis_data) logger.info( f"Devis créé: {resultat.get('numero_devis')} " @@ -418,6 +433,7 @@ async def modifier_devis( id: str, devis_update: DevisUpdate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: update_data = {} @@ -441,7 +457,7 @@ async def modifier_devis( if devis_update.reference is not None: update_data["reference"] = devis_update.reference - resultat = sage_client.modifier_devis(id, update_data) + resultat = sage.modifier_devis(id, update_data) logger.info(f"Devis {id} modifié avec succès") @@ -460,7 +476,9 @@ async def modifier_devis( @app.post("/commandes", status_code=201, tags=["Commandes"]) async def creer_commande( - commande: CommandeCreate, session: AsyncSession = Depends(get_session) + commande: CommandeCreate, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: commande_data = { @@ -475,7 +493,7 @@ async def creer_commande( "lignes": _preparer_lignes_document(commande.lignes), } - resultat = sage_client.creer_commande(commande_data) + resultat = sage.creer_commande(commande_data) logger.info( f"Commande créée: {resultat.get('numero_commande')} " @@ -509,6 +527,7 @@ async def modifier_commande( id: str, commande_update: CommandeUpdate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: update_data = {} @@ -532,7 +551,7 @@ async def modifier_commande( if commande_update.reference is not None: update_data["reference"] = commande_update.reference - resultat = sage_client.modifier_commande(id, update_data) + resultat = sage.modifier_commande(id, update_data) logger.info(f"Commande {id} modifiée avec succès") @@ -556,9 +575,10 @@ async def lister_devis( inclure_lignes: bool = Query( True, description="Inclure les lignes de chaque devis" ), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - devis_list = sage_client.lister_devis( + devis_list = sage.lister_devis( limit=limit, statut=statut, inclure_lignes=inclure_lignes ) return devis_list @@ -569,9 +589,12 @@ async def lister_devis( @app.get("/devis/{id}", tags=["Devis"]) -async def lire_devis(id: str): +async def lire_devis( + id: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - devis = sage_client.lire_devis(id) + devis = sage.lire_devis(id) if not devis: raise HTTPException(404, f"Devis {id} introuvable") @@ -586,7 +609,10 @@ async def lire_devis(id: str): @app.get("/devis/{id}/pdf", tags=["Devis"]) -async def telecharger_devis_pdf(id: str): +async def telecharger_devis_pdf( + id: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: pdf_bytes = email_queue._generate_pdf(id, TypeDocument.DEVIS) @@ -607,6 +633,7 @@ async def telecharger_document_pdf( description="Type de document (0=Devis, 10=Commande, 30=Livraison, 60=Facture, 50=Avoir)", ), numero: str = Path(..., description="Numéro du document"), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: types_labels = { @@ -630,7 +657,7 @@ async def telecharger_document_pdf( logger.info(f"Génération PDF: {label} {numero} (type={type_doc})") - pdf_bytes = sage_client.generer_pdf_document(numero, type_doc) + pdf_bytes = sage.generer_pdf_document(numero, type_doc) if not pdf_bytes: raise HTTPException(500, f"Le PDF du document {numero} est vide") @@ -659,7 +686,10 @@ async def telecharger_document_pdf( @app.post("/devis/{id}/envoyer", tags=["Devis"]) async def envoyer_devis_email( - id: str, request: EmailEnvoi, session: AsyncSession = Depends(get_session) + id: str, + request: EmailEnvoi, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: tous_destinataires = [request.destinataire] + request.cc + request.cci @@ -714,6 +744,7 @@ async def changer_statut_document( nouveau_statut: int = Query( ..., ge=0, le=6, description="0=Saisi, 1=Confirmé, 2=Accepté" ), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): document_type_sql = None document_type_code = None @@ -755,7 +786,7 @@ async def changer_statut_document( f"Type de document invalide: {type_doc}", ) - document_existant = sage_client.lire_document(numero, document_type_sql) + document_existant = sage.lire_document(numero, document_type_sql) if not document_existant: raise HTTPException(404, f"Document {numero} introuvable") @@ -799,7 +830,7 @@ async def changer_statut_document( else type_doc_normalized ) - resultat = sage_client.changer_statut_document( + resultat = sage.changer_statut_document( document_type_code=document_type_int, numero=numero, nouveau_statut=nouveau_statut, @@ -827,9 +858,12 @@ async def changer_statut_document( @app.get("/commandes/{id}", tags=["Commandes"]) -async def lire_commande(id: str): +async def lire_commande( + id: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - commande = sage_client.lire_document(id, TypeDocumentSQL.BON_COMMANDE) + commande = sage.lire_document(id, TypeDocumentSQL.BON_COMMANDE) if not commande: raise HTTPException(404, f"Commande {id} introuvable") return commande @@ -842,10 +876,12 @@ async def lire_commande(id: str): @app.get("/commandes", tags=["Commandes"]) async def lister_commandes( - limit: int = Query(100, le=1000), statut: Optional[int] = Query(None) + limit: int = Query(100, le=1000), + statut: Optional[int] = Query(None), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - commandes = sage_client.lister_commandes(limit=limit, statut=statut) + commandes = sage.lister_commandes(limit=limit, statut=statut) return commandes except Exception as e: @@ -854,9 +890,13 @@ async def lister_commandes( @app.post("/workflow/devis/{id}/to-commande", tags=["Workflows"]) -async def devis_vers_commande(id: str, session: AsyncSession = Depends(get_session)): +async def devis_vers_commande( + id: str, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - resultat = sage_client.transformer_document( + resultat = sage.transformer_document( numero_source=id, type_source=settings.SAGE_TYPE_DEVIS, # = 0 type_cible=settings.SAGE_TYPE_BON_COMMANDE, # = 10 @@ -894,9 +934,13 @@ async def devis_vers_commande(id: str, session: AsyncSession = Depends(get_sessi @app.post("/workflow/commande/{id}/to-facture", tags=["Workflows"]) -async def commande_vers_facture(id: str, session: AsyncSession = Depends(get_session)): +async def commande_vers_facture( + id: str, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - resultat = sage_client.transformer_document( + resultat = sage.transformer_document( numero_source=id, type_source=settings.SAGE_TYPE_BON_COMMANDE, # = 10 type_cible=settings.SAGE_TYPE_FACTURE, # = 60 @@ -1254,9 +1298,10 @@ async def envoyer_emails_lot( async def valider_remise( client_id: str = Query(..., min_length=1), remise_pourcentage: float = Query(0.0, ge=0, le=100), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - remise_max = sage_client.lire_remise_max_client(client_id) + remise_max = sage.lire_remise_max_client(client_id) autorisee = remise_pourcentage <= remise_max @@ -1283,14 +1328,17 @@ async def valider_remise( @app.post("/devis/{id}/relancer-signature", tags=["Devis"]) async def relancer_devis_signature( - id: str, relance: RelanceDevis, session: AsyncSession = Depends(get_session) + id: str, + relance: RelanceDevis, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - devis = sage_client.lire_devis(id) + devis = sage.lire_devis(id) if not devis: raise HTTPException(404, f"Devis {id} introuvable") - contact = sage_client.lire_contact_client(devis["client_code"]) + contact = sage.lire_contact_client(devis["client_code"]) if not contact or not contact.get("email"): raise HTTPException(400, "Aucun email trouvé pour ce client") @@ -1347,13 +1395,16 @@ class ContactClientResponse(BaseModel): @app.get("/devis/{id}/contact", response_model=ContactClientResponse, tags=["Devis"]) -async def recuperer_contact_devis(id: str): +async def recuperer_contact_devis( + id: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - devis = sage_client.lire_devis(id) + devis = sage.lire_devis(id) if not devis: raise HTTPException(404, f"Devis {id} introuvable") - contact = sage_client.lire_contact_client(devis["client_code"]) + contact = sage.lire_contact_client(devis["client_code"]) if not contact: raise HTTPException( 404, f"Contact introuvable pour client {devis['client_code']}" @@ -1371,10 +1422,12 @@ async def recuperer_contact_devis(id: str): @app.get("/factures", tags=["Factures"]) async def lister_factures( - limit: int = Query(100, le=1000), statut: Optional[int] = Query(None) + limit: int = Query(100, le=1000), + statut: Optional[int] = Query(None), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - factures = sage_client.lister_factures(limit=limit, statut=statut) + factures = sage.lister_factures(limit=limit, statut=statut) return factures except Exception as e: @@ -1383,9 +1436,12 @@ async def lister_factures( @app.get("/factures/{numero}", tags=["Factures"]) -async def lire_facture_detail(numero: str): +async def lire_facture_detail( + numero: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - facture = sage_client.lire_document(numero, TypeDocumentSQL.FACTURE) + facture = sage.lire_document(numero, TypeDocumentSQL.FACTURE) if not facture: raise HTTPException(404, f"Facture {numero} introuvable") @@ -1406,7 +1462,9 @@ class RelanceFacture(BaseModel): @app.post("/factures", status_code=201, tags=["Factures"]) async def creer_facture( - facture: FactureCreate, session: AsyncSession = Depends(get_session) + facture: FactureCreate, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: facture_data = { @@ -1421,7 +1479,7 @@ async def creer_facture( "lignes": _preparer_lignes_document(facture.lignes), } - resultat = sage_client.creer_facture(facture_data) + resultat = sage.creer_facture(facture_data) logger.info( f"Facture créée: {resultat.get('numero_facture')} " @@ -1455,6 +1513,7 @@ async def modifier_facture( id: str, facture_update: FactureUpdate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: update_data = {} @@ -1478,7 +1537,7 @@ async def modifier_facture( if facture_update.reference is not None: update_data["reference"] = facture_update.reference - resultat = sage_client.modifier_facture(id, update_data) + resultat = sage.modifier_facture(id, update_data) logger.info(f"Facture {id} modifiée avec succès") @@ -1523,13 +1582,14 @@ async def relancer_facture( id: str, relance: RelanceFacture, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - facture = sage_client.lire_document(id, TypeDocumentSQL.FACTURE) + facture = sage.lire_document(id, TypeDocumentSQL.FACTURE) if not facture: raise HTTPException(404, f"Facture {id} introuvable") - contact = sage_client.lire_contact_client(facture["client_code"]) + contact = sage.lire_contact_client(facture["client_code"]) if not contact or not contact.get("email"): raise HTTPException(400, "Aucun email trouvé pour ce client") @@ -1567,7 +1627,7 @@ async def relancer_facture( email_queue.enqueue(email_log.id) - sage_client.mettre_a_jour_derniere_relance(id, TypeDocument.FACTURE) + sage.mettre_a_jour_derniere_relance(id, TypeDocument.FACTURE) await session.commit() @@ -1592,6 +1652,7 @@ async def journal_emails( destinataire: Optional[str] = Query(None), limit: int = Query(100, le=1000), session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): query = select(EmailLog) @@ -1626,6 +1687,7 @@ async def journal_emails( async def exporter_logs_csv( statut: Optional[StatutEmail] = Query(None), session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): query = select(EmailLog) if statut: @@ -1764,13 +1826,16 @@ async def supprimer_template(template_id: str): @app.post("/templates/emails/preview", tags=["Emails"]) -async def previsualiser_email(preview: TemplatePreview): +async def previsualiser_email( + preview: TemplatePreview, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): if preview.template_id not in templates_email_db: raise HTTPException(404, f"Template {preview.template_id} introuvable") template = templates_email_db[preview.template_id] - doc = sage_client.lire_document(preview.document_id, preview.type_document) + doc = sage.lire_document(preview.document_id, preview.type_document) if not doc: raise HTTPException(404, f"Document {preview.document_id} introuvable") @@ -1799,9 +1864,12 @@ async def previsualiser_email(preview: TemplatePreview): @app.get("/prospects", tags=["Prospects"]) -async def rechercher_prospects(query: Optional[str] = Query(None)): +async def rechercher_prospects( + query: Optional[str] = Query(None), + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - prospects = sage_client.lister_prospects(filtre=query or "") + prospects = sage.lister_prospects(filtre=query or "") return prospects except Exception as e: logger.error(f"Erreur recherche prospects: {e}") @@ -1809,9 +1877,12 @@ async def rechercher_prospects(query: Optional[str] = Query(None)): @app.get("/prospects/{code}", tags=["Prospects"]) -async def lire_prospect(code: str): +async def lire_prospect( + code: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - prospect = sage_client.lire_prospect(code) + prospect = sage.lire_prospect(code) if not prospect: raise HTTPException(404, f"Prospect {code} introuvable") return prospect @@ -1825,9 +1896,12 @@ async def lire_prospect(code: str): @app.get( "/fournisseurs", response_model=List[FournisseurDetails], tags=["Fournisseurs"] ) -async def rechercher_fournisseurs(query: Optional[str] = Query(None)): +async def rechercher_fournisseurs( + query: Optional[str] = Query(None), + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - fournisseurs = sage_client.lister_fournisseurs(filtre=query or "") + fournisseurs = sage.lister_fournisseurs(filtre=query or "") logger.info(f"{len(fournisseurs)} fournisseurs") @@ -1845,9 +1919,10 @@ async def rechercher_fournisseurs(query: Optional[str] = Query(None)): async def ajouter_fournisseur( fournisseur: FournisseurCreate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - nouveau_fournisseur = sage_client.creer_fournisseur(fournisseur.dict()) + nouveau_fournisseur = sage.creer_fournisseur(fournisseur.dict()) logger.info(f"Fournisseur créé via API: {nouveau_fournisseur.get('numero')}") @@ -1873,9 +1948,10 @@ async def modifier_fournisseur( code: str, fournisseur_update: FournisseurUpdate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - resultat = sage_client.modifier_fournisseur( + resultat = sage.modifier_fournisseur( code, fournisseur_update.dict(exclude_none=True) ) @@ -1892,9 +1968,12 @@ async def modifier_fournisseur( @app.get("/fournisseurs/{code}", tags=["Fournisseurs"]) -async def lire_fournisseur(code: str): +async def lire_fournisseur( + code: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - fournisseur = sage_client.lire_fournisseur(code) + fournisseur = sage.lire_fournisseur(code) if not fournisseur: raise HTTPException(404, f"Fournisseur {code} introuvable") return fournisseur @@ -1907,10 +1986,12 @@ async def lire_fournisseur(code: str): @app.get("/avoirs", tags=["Avoirs"]) async def lister_avoirs( - limit: int = Query(100, le=1000), statut: Optional[int] = Query(None) + limit: int = Query(100, le=1000), + statut: Optional[int] = Query(None), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - avoirs = sage_client.lister_avoirs(limit=limit, statut=statut) + avoirs = sage.lister_avoirs(limit=limit, statut=statut) return avoirs except Exception as e: logger.error(f"Erreur liste avoirs: {e}") @@ -1918,9 +1999,12 @@ async def lister_avoirs( @app.get("/avoirs/{numero}", tags=["Avoirs"]) -async def lire_avoir(numero: str): +async def lire_avoir( + numero: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - avoir = sage_client.lire_document(numero, TypeDocumentSQL.BON_AVOIR) + avoir = sage.lire_document(numero, TypeDocumentSQL.BON_AVOIR) if not avoir: raise HTTPException(404, f"Avoir {numero} introuvable") return avoir @@ -1932,7 +2016,11 @@ async def lire_avoir(numero: str): @app.post("/avoirs", status_code=201, tags=["Avoirs"]) -async def creer_avoir(avoir: AvoirCreate, session: AsyncSession = Depends(get_session)): +async def creer_avoir( + avoir: AvoirCreate, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: avoir_data = { "client_id": avoir.client_id, @@ -1944,7 +2032,7 @@ async def creer_avoir(avoir: AvoirCreate, session: AsyncSession = Depends(get_se "lignes": _preparer_lignes_document(avoir.lignes), } - resultat = sage_client.creer_avoir(avoir_data) + resultat = sage.creer_avoir(avoir_data) logger.info( f"Avoir créé: {resultat.get('numero_avoir')} " @@ -1978,6 +2066,7 @@ async def modifier_avoir( id: str, avoir_update: AvoirUpdate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: update_data = {} @@ -2001,7 +2090,7 @@ async def modifier_avoir( if avoir_update.reference is not None: update_data["reference"] = avoir_update.reference - resultat = sage_client.modifier_avoir(id, update_data) + resultat = sage.modifier_avoir(id, update_data) logger.info(f"Avoir {id} modifié avec succès") @@ -2020,10 +2109,12 @@ async def modifier_avoir( @app.get("/livraisons", tags=["Livraisons"]) async def lister_livraisons( - limit: int = Query(100, le=1000), statut: Optional[int] = Query(None) + limit: int = Query(100, le=1000), + statut: Optional[int] = Query(None), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - livraisons = sage_client.lister_livraisons(limit=limit, statut=statut) + livraisons = sage.lister_livraisons(limit=limit, statut=statut) return livraisons except Exception as e: logger.error(f"Erreur liste livraisons: {e}") @@ -2031,9 +2122,12 @@ async def lister_livraisons( @app.get("/livraisons/{numero}", tags=["Livraisons"]) -async def lire_livraison(numero: str): +async def lire_livraison( + numero: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - livraison = sage_client.lire_document(numero, TypeDocumentSQL.BON_LIVRAISON) + livraison = sage.lire_document(numero, TypeDocumentSQL.BON_LIVRAISON) if not livraison: raise HTTPException(404, f"Livraison {numero} introuvable") return livraison @@ -2046,14 +2140,10 @@ async def lire_livraison(numero: str): @app.post("/livraisons", status_code=201, tags=["Livraisons"]) async def creer_livraison( - livraison: LivraisonCreate, session: AsyncSession = Depends(get_session) + livraison: LivraisonCreate, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): - """ - Crée un bon de livraison dans Sage 100 - - - Le prix_unitaire_ht est optionnel (utilise le prix Sage si non fourni) - - La remise_pourcentage est appliquée après le prix - """ try: livraison_data = { "client_id": livraison.client_id, @@ -2071,7 +2161,7 @@ async def creer_livraison( "lignes": _preparer_lignes_document(livraison.lignes), } - resultat = sage_client.creer_livraison(livraison_data) + resultat = sage.creer_livraison(livraison_data) logger.info( f"Livraison créée: {resultat.get('numero_livraison')} " @@ -2105,6 +2195,7 @@ async def modifier_livraison( id: str, livraison_update: LivraisonUpdate, session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: update_data = {} @@ -2128,7 +2219,7 @@ async def modifier_livraison( if livraison_update.reference is not None: update_data["reference"] = livraison_update.reference - resultat = sage_client.modifier_livraison(id, update_data) + resultat = sage.modifier_livraison(id, update_data) logger.info(f"Livraison {id} modifiée avec succès") @@ -2146,9 +2237,13 @@ async def modifier_livraison( @app.post("/workflow/livraison/{id}/to-facture", tags=["Workflows"]) -async def livraison_vers_facture(id: str, session: AsyncSession = Depends(get_session)): +async def livraison_vers_facture( + id: str, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - resultat = sage_client.transformer_document( + resultat = sage.transformer_document( numero_source=id, type_source=settings.SAGE_TYPE_BON_LIVRAISON, # = 30 type_cible=settings.SAGE_TYPE_FACTURE, # = 60 @@ -2186,10 +2281,12 @@ async def livraison_vers_facture(id: str, session: AsyncSession = Depends(get_se @app.post("/workflow/devis/{id}/to-facture", tags=["Workflows"]) async def devis_vers_facture_direct( - id: str, session: AsyncSession = Depends(get_session) + id: str, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - devis_existant = sage_client.lire_devis(id) + devis_existant = sage.lire_devis(id) if not devis_existant: raise HTTPException(404, f"Devis {id} introuvable") @@ -2201,7 +2298,7 @@ async def devis_vers_facture_direct( f"Vérifiez les documents déjà créés depuis ce devis.", ) - resultat = sage_client.transformer_document( + resultat = sage.transformer_document( numero_source=id, type_source=settings.SAGE_TYPE_DEVIS, # = 0 type_cible=settings.SAGE_TYPE_FACTURE, # = 60 @@ -2244,10 +2341,12 @@ async def devis_vers_facture_direct( @app.post("/workflow/commande/{id}/to-livraison", tags=["Workflows"]) async def commande_vers_livraison( - id: str, session: AsyncSession = Depends(get_session) + id: str, + session: AsyncSession = Depends(get_session), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - commande_existante = sage_client.lire_document(id, TypeDocumentSQL.BON_COMMANDE) + commande_existante = sage.lire_document(id, TypeDocumentSQL.BON_COMMANDE) if not commande_existante: raise HTTPException(404, f"Commande {id} introuvable") @@ -2266,7 +2365,7 @@ async def commande_vers_livraison( f"La commande {id} est annulée (statut=6) et ne peut pas être transformée.", ) - resultat = sage_client.transformer_document( + resultat = sage.transformer_document( numero_source=id, type_source=settings.SAGE_TYPE_BON_COMMANDE, # = 10 type_cible=settings.SAGE_TYPE_BON_LIVRAISON, # = 30 @@ -2315,9 +2414,10 @@ async def commande_vers_livraison( ) async def lister_familles( filtre: Optional[str] = Query(None, description="Filtre sur code ou intitulé"), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - familles = sage_client.lister_familles(filtre or "") + familles = sage.lister_familles(filtre or "") logger.info(f"{len(familles)} famille(s) retournée(s)") @@ -2339,9 +2439,10 @@ async def lister_familles( ) async def lire_famille( code: str = Path(..., description="Code de la famille (ex: ZDIVERS)"), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - famille = sage_client.lire_famille(code) + famille = sage.lire_famille(code) if not famille: logger.warning(f"Famille {code} introuvable") @@ -2371,7 +2472,10 @@ async def lire_famille( tags=["Familles"], summary="Création d'une famille d'articles", ) -async def creer_famille(famille: FamilleCreate): +async def creer_famille( + famille: FamilleCreate, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: if not famille.code or not famille.intitule: raise HTTPException( @@ -2383,7 +2487,7 @@ async def creer_famille(famille: FamilleCreate): logger.info(f"Création famille: {famille.code} - {famille.intitule}") - resultat = sage_client.creer_famille(famille_data) + resultat = sage.creer_famille(famille_data) logger.info(f"Famille créée: {resultat.get('code')}") @@ -2411,7 +2515,10 @@ async def creer_famille(famille: FamilleCreate): tags=["Stock"], summary="ENTRÉE EN STOCK : Ajoute des articles dans le stock", ) -async def creer_entree_stock(entree: EntreeStock): +async def creer_entree_stock( + entree: EntreeStock, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: entree_data = entree.dict() if entree_data.get("date_entree"): @@ -2419,7 +2526,7 @@ async def creer_entree_stock(entree: EntreeStock): logger.info(f"Création entrée stock: {len(entree.lignes)} ligne(s)") - resultat = sage_client.creer_entree_stock(entree_data) + resultat = sage.creer_entree_stock(entree_data) logger.info(f"Entrée stock créée: {resultat.get('numero')}") @@ -2444,7 +2551,10 @@ async def creer_entree_stock(entree: EntreeStock): tags=["Stock"], summary="SORTIE DE STOCK : Retire des articles du stock", ) -async def creer_sortie_stock(sortie: SortieStock): +async def creer_sortie_stock( + sortie: SortieStock, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: sortie_data = sortie.dict() if sortie_data.get("date_sortie"): @@ -2452,7 +2562,7 @@ async def creer_sortie_stock(sortie: SortieStock): logger.info(f"Création sortie stock: {len(sortie.lignes)} ligne(s)") - resultat = sage_client.creer_sortie_stock(sortie_data) + resultat = sage.creer_sortie_stock(sortie_data) logger.info(f"Sortie stock créée: {resultat.get('numero')}") @@ -2478,9 +2588,10 @@ async def creer_sortie_stock(sortie: SortieStock): ) async def lire_mouvement_stock( numero: str = Path(..., description="Numéro du mouvement (ex: ME00123 ou MS00124)"), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: - mouvement = sage_client.lire_mouvement_stock(numero) + mouvement = sage.lire_mouvement_stock(numero) if not mouvement: logger.warning(f"Mouvement {numero} introuvable") @@ -2508,9 +2619,11 @@ async def lire_mouvement_stock( tags=["Familles"], summary="Statistiques sur les familles", ) -async def statistiques_familles(): +async def statistiques_familles( + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - stats = sage_client.get_stats_familles() + stats = sage.get_stats_familles() return {"success": True, "data": stats} @@ -2611,10 +2724,14 @@ async def statistiques_utilisateurs(session: AsyncSession = Depends(get_session) @app.post("/tiers/{numero}/contacts", response_model=Contact, tags=["Contacts"]) -async def creer_contact(numero: str, contact: ContactCreate): +async def creer_contact( + numero: str, + contact: ContactCreate, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: try: - sage_client.lire_tiers(numero) + sage.lire_tiers(numero) except HTTPException: raise except Exception: @@ -2623,7 +2740,7 @@ async def creer_contact(numero: str, contact: ContactCreate): if contact.numero != numero: contact.numero = numero - resultat = sage_client.creer_contact(contact.dict()) + resultat = sage.creer_contact(contact.dict()) if isinstance(resultat, dict) and "data" in resultat: contact_data = resultat["data"] @@ -2640,9 +2757,12 @@ async def creer_contact(numero: str, contact: ContactCreate): @app.get("/tiers/{numero}/contacts", response_model=List[Contact], tags=["Contacts"]) -async def lister_contacts(numero: str): +async def lister_contacts( + numero: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - contacts = sage_client.lister_contacts(numero) + contacts = sage.lister_contacts(numero) return [Contact(**c) for c in contacts] except Exception as e: logger.error(f"Erreur liste contacts: {e}") @@ -2654,9 +2774,13 @@ async def lister_contacts(numero: str): response_model=Contact, tags=["Contacts"], ) -async def obtenir_contact(numero: str, contact_numero: int): +async def obtenir_contact( + numero: str, + contact_numero: int, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - contact = sage_client.obtenir_contact(numero, contact_numero) + contact = sage.obtenir_contact(numero, contact_numero) if not contact: raise HTTPException( 404, f"Contact {contact_numero} non trouvé pour client {numero}" @@ -2674,9 +2798,14 @@ async def obtenir_contact(numero: str, contact_numero: int): response_model=Contact, tags=["Contacts"], ) -async def modifier_contact(numero: str, contact_numero: int, contact: ContactUpdate): +async def modifier_contact( + numero: str, + contact_numero: int, + contact: ContactUpdate, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - contact_existant = sage_client.obtenir_contact(numero, contact_numero) + contact_existant = sage.obtenir_contact(numero, contact_numero) if not contact_existant: raise HTTPException(404, f"Contact {contact_numero} non trouvé") @@ -2685,7 +2814,7 @@ async def modifier_contact(numero: str, contact_numero: int, contact: ContactUpd if not updates: raise HTTPException(400, "Aucune modification fournie") - resultat = sage_client.modifier_contact(numero, contact_numero, updates) + resultat = sage.modifier_contact(numero, contact_numero, updates) if isinstance(resultat, dict) and "data" in resultat: contact_data = resultat["data"] else: @@ -2701,9 +2830,13 @@ async def modifier_contact(numero: str, contact_numero: int, contact: ContactUpd @app.delete("/tiers/{numero}/contacts/{contact_numero}", tags=["Contacts"]) -async def supprimer_contact(numero: str, contact_numero: int): +async def supprimer_contact( + numero: str, + contact_numero: int, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - sage_client.supprimer_contact(numero, contact_numero) + sage.supprimer_contact(numero, contact_numero) return {"success": True, "message": f"Contact {contact_numero} supprimé"} except Exception as e: logger.error(f"Erreur suppression contact: {e}") @@ -2711,9 +2844,13 @@ async def supprimer_contact(numero: str, contact_numero: int): @app.post("/tiers/{numero}/contacts/{contact_numero}/definir-defaut", tags=["Contacts"]) -async def definir_contact_defaut(numero: str, contact_numero: int): +async def definir_contact_defaut( + numero: str, + contact_numero: int, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - resultat = sage_client.definir_contact_defaut(numero, contact_numero) + resultat = sage.definir_contact_defaut(numero, contact_numero) return { "success": True, "message": f"Contact {contact_numero} défini comme contact par défaut", @@ -2731,10 +2868,11 @@ async def obtenir_tiers( description="Filtre par type: 0/client, 1/fournisseur, 2/prospect, 3/all ou strings", ), query: Optional[str] = Query(None, description="Recherche sur code ou intitulé"), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): try: type_normalise = normaliser_type_tiers(type_tiers) - tiers = sage_client.lister_tiers(type_tiers=type_normalise, filtre=query or "") + tiers = sage.lister_tiers(type_tiers=type_normalise, filtre=query or "") return [TiersDetails(**t) for t in tiers] except Exception as e: logger.error(f"Erreur recherche tiers: {e}") @@ -2742,9 +2880,12 @@ async def obtenir_tiers( @app.get("/tiers/{code}", response_model=TiersDetails, tags=["Tiers"]) -async def lire_tiers_detail(code: str): +async def lire_tiers_detail( + code: str, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - tiers = sage_client.lire_tiers(code) + tiers = sage.lire_tiers(code) if not tiers: raise HTTPException(404, f"Tiers {code} introuvable") return TiersDetails(**tiers) @@ -2779,10 +2920,11 @@ async def lister_collaborateurs( actifs_seulement: bool = Query( True, description="Exclure les collaborateurs en sommeil" ), + sage: SageGatewayClient = Depends(get_sage_client_for_user), ): """Liste tous les collaborateurs""" try: - collaborateurs = sage_client.lister_collaborateurs(filtre, actifs_seulement) + collaborateurs = sage.lister_collaborateurs(filtre, actifs_seulement) return [CollaborateurDetails(**c) for c in collaborateurs] except Exception as e: logger.error(f"Erreur liste collaborateurs: {e}") @@ -2794,10 +2936,13 @@ async def lister_collaborateurs( response_model=CollaborateurDetails, tags=["Collaborateurs"], ) -async def lire_collaborateur_detail(numero: int): +async def lire_collaborateur_detail( + numero: int, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): """Lit un collaborateur par son numéro""" try: - collaborateur = sage_client.lire_collaborateur(numero) + collaborateur = sage.lire_collaborateur(numero) if not collaborateur: raise HTTPException(404, f"Collaborateur {numero} introuvable") @@ -2817,10 +2962,13 @@ async def lire_collaborateur_detail(numero: int): tags=["Collaborateurs"], status_code=201, ) -async def creer_collaborateur(collaborateur: CollaborateurCreate): +async def creer_collaborateur( + collaborateur: CollaborateurCreate, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): """Crée un nouveau collaborateur""" try: - nouveau = sage_client.creer_collaborateur(collaborateur.model_dump()) + nouveau = sage.creer_collaborateur(collaborateur.model_dump()) if not nouveau: raise HTTPException(500, "Échec création collaborateur") @@ -2839,10 +2987,14 @@ async def creer_collaborateur(collaborateur: CollaborateurCreate): response_model=CollaborateurDetails, tags=["Collaborateurs"], ) -async def modifier_collaborateur(numero: int, collaborateur: CollaborateurUpdate): +async def modifier_collaborateur( + numero: int, + collaborateur: CollaborateurUpdate, + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): """Modifie un collaborateur existant""" try: - modifie = sage_client.modifier_collaborateur( + modifie = sage.modifier_collaborateur( numero, collaborateur.model_dump(exclude_unset=True) ) @@ -2859,9 +3011,11 @@ async def modifier_collaborateur(numero: int, collaborateur: CollaborateurUpdate @app.get("/societe/info", response_model=SocieteInfo, tags=["Société"]) -async def obtenir_informations_societe(): +async def obtenir_informations_societe( + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): try: - societe = sage_client.lire_informations_societe() + societe = sage.lire_informations_societe() if not societe: raise HTTPException(404, "Informations société introuvables") @@ -2876,10 +3030,12 @@ async def obtenir_informations_societe(): @app.get("/societe/logo", tags=["Société"]) -async def obtenir_logo_societe(): +async def obtenir_logo_societe( + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): """Retourne le logo en tant qu'image directe""" try: - societe = sage_client.lire_informations_societe() + societe = sage.lire_informations_societe() if not societe or not societe.get("logo_base64"): raise HTTPException(404, "Logo introuvable") @@ -2898,10 +3054,12 @@ async def obtenir_logo_societe(): @app.get("/societe/preview", response_class=HTMLResponse, tags=["Société"]) -async def preview_societe(): +async def preview_societe( + sage: SageGatewayClient = Depends(get_sage_client_for_user), +): """Page HTML pour visualiser les infos société avec logo""" try: - societe = sage_client.lire_informations_societe() + societe = sage.lire_informations_societe() if not societe: return "