Unification for document's schemas

This commit is contained in:
Fanilo-Nantenaina 2026-01-05 17:22:27 +03:00
parent e7bdf2d6a2
commit 8850c7c266
9 changed files with 107 additions and 121 deletions

100
api.py
View file

@ -78,7 +78,7 @@ from core.sage_context import (
get_gateway_context_for_user,
GatewayContext,
)
from utils.generic_functions import _preparer_lignes_document
if os.path.exists("/app"):
LOGS_DIR = FilePath("/app/logs")
@ -526,19 +526,15 @@ async def creer_devis(devis: DevisRequest):
devis.date_livraison.isoformat() if devis.date_livraison else None
),
"reference": devis.reference,
"lignes": [
{
"article_code": ligne.article_code,
"quantite": ligne.quantite,
"remise_pourcentage": ligne.remise_pourcentage,
}
for ligne in devis.lignes
],
"lignes": _preparer_lignes_document(devis.lignes),
}
resultat = sage_client.creer_devis(devis_data)
logger.info(f"Devis créé: {resultat.get('numero_devis')}")
logger.info(
f"✅ Devis créé: {resultat.get('numero_devis')} "
f"({resultat.get('total_ttc')}€ TTC)"
)
return Devis(
id=resultat["numero_devis"],
@ -550,7 +546,7 @@ async def creer_devis(devis: DevisRequest):
)
except Exception as e:
logger.error(f"Erreur création devis: {e}")
logger.error(f"Erreur création devis: {e}")
raise HTTPException(500, str(e))
@ -613,19 +609,15 @@ async def creer_commande(
commande.date_livraison.isoformat() if commande.date_livraison else None
),
"reference": commande.reference,
"lignes": [
{
"article_code": ligne.article_code,
"quantite": ligne.quantite,
"remise_pourcentage": ligne.remise_pourcentage,
}
for ligne in commande.lignes
],
"lignes": _preparer_lignes_document(commande.lignes),
}
resultat = sage_client.creer_commande(commande_data)
logger.info(f"Commande créée: {resultat.get('numero_commande')}")
logger.info(
f"✅ Commande créée: {resultat.get('numero_commande')} "
f"({resultat.get('total_ttc')}€ TTC)"
)
return {
"success": True,
@ -637,14 +629,15 @@ async def creer_commande(
"total_ht": resultat["total_ht"],
"total_ttc": resultat["total_ttc"],
"nb_lignes": resultat["nb_lignes"],
"reference": commande.reference,
"reference": resultat.get("reference"),
"date_livraison": resultat.get("date_livraison"),
},
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Erreur création commande: {e}")
logger.error(f"Erreur création commande: {e}")
raise HTTPException(500, str(e))
@ -1798,19 +1791,15 @@ async def creer_facture(
facture.date_livraison.isoformat() if facture.date_livraison else None
),
"reference": facture.reference,
"lignes": [
{
"article_code": ligne.article_code,
"quantite": ligne.quantite,
"remise_pourcentage": ligne.remise_pourcentage,
}
for ligne in facture.lignes
],
"lignes": _preparer_lignes_document(facture.lignes),
}
resultat = sage_client.creer_facture(facture_data)
logger.info(f"Facture créée: {resultat.get('numero_facture')}")
logger.info(
f"✅ Facture créée: {resultat.get('numero_facture')} "
f"({resultat.get('total_ttc')}€ TTC)"
)
return {
"success": True,
@ -1822,14 +1811,15 @@ async def creer_facture(
"total_ht": resultat["total_ht"],
"total_ttc": resultat["total_ttc"],
"nb_lignes": resultat["nb_lignes"],
"reference": facture.reference,
"reference": resultat.get("reference"),
"date_livraison": resultat.get("date_livraison"),
},
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Erreur création facture: {e}")
logger.error(f"Erreur création facture: {e}")
raise HTTPException(500, str(e))
@ -2324,19 +2314,15 @@ async def creer_avoir(avoir: AvoirCreate, session: AsyncSession = Depends(get_se
avoir.date_livraison.isoformat() if avoir.date_livraison else None
),
"reference": avoir.reference,
"lignes": [
{
"article_code": ligne.article_code,
"quantite": ligne.quantite,
"remise_pourcentage": ligne.remise_pourcentage,
}
for ligne in avoir.lignes
],
"lignes": _preparer_lignes_document(avoir.lignes),
}
resultat = sage_client.creer_avoir(avoir_data)
logger.info(f"Avoir créé: {resultat.get('numero_avoir')}")
logger.info(
f"✅ Avoir créé: {resultat.get('numero_avoir')} "
f"({resultat.get('total_ttc')}€ TTC)"
)
return {
"success": True,
@ -2348,14 +2334,15 @@ async def creer_avoir(avoir: AvoirCreate, session: AsyncSession = Depends(get_se
"total_ht": resultat["total_ht"],
"total_ttc": resultat["total_ttc"],
"nb_lignes": resultat["nb_lignes"],
"reference": avoir.reference,
"reference": resultat.get("reference"),
"date_livraison": resultat.get("date_livraison"),
},
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Erreur création avoir: {e}")
logger.error(f"Erreur création avoir: {e}")
raise HTTPException(500, str(e))
@ -2434,6 +2421,12 @@ async def lire_livraison(numero: str):
async def creer_livraison(
livraison: LivraisonCreate, session: AsyncSession = Depends(get_session)
):
"""
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,
@ -2448,19 +2441,15 @@ async def creer_livraison(
else None
),
"reference": livraison.reference,
"lignes": [
{
"article_code": ligne.article_code,
"quantite": ligne.quantite,
"remise_pourcentage": ligne.remise_pourcentage,
}
for ligne in livraison.lignes
],
"lignes": _preparer_lignes_document(livraison.lignes),
}
resultat = sage_client.creer_livraison(livraison_data)
logger.info(f"Livraison créée: {resultat.get('numero_livraison')}")
logger.info(
f"✅ Livraison créée: {resultat.get('numero_livraison')} "
f"({resultat.get('total_ttc')}€ TTC)"
)
return {
"success": True,
@ -2469,17 +2458,18 @@ async def creer_livraison(
"numero_livraison": resultat["numero_livraison"],
"client_id": livraison.client_id,
"date_livraison": resultat["date_livraison"],
"date_livraison_prevue": resultat.get("date_livraison_prevue"),
"total_ht": resultat["total_ht"],
"total_ttc": resultat["total_ttc"],
"nb_lignes": resultat["nb_lignes"],
"reference": livraison.reference,
"reference": resultat.get("reference"),
},
}
except HTTPException:
raise
except Exception as e:
logger.error(f"Erreur création livraison: {e}")
logger.error(f"Erreur création livraison: {e}")
raise HTTPException(500, str(e))

View file

@ -1,23 +1,14 @@
from pydantic import BaseModel, Field, field_validator
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import date
class LigneAvoir(BaseModel):
article_code: str
quantite: float
remise_pourcentage: Optional[float] = 0.0
@field_validator("article_code", mode="before")
def strip_insecables(cls, v):
return v.replace("\xa0", "").strip()
from schemas.documents.ligne_document import LigneDocument
class AvoirCreate(BaseModel):
client_id: str
date_avoir: Optional[date] = None
date_livraison: Optional[date] = None
lignes: List[LigneAvoir]
lignes: List[LigneDocument]
reference: Optional[str] = None
class Config:
@ -41,7 +32,7 @@ class AvoirCreate(BaseModel):
class AvoirUpdate(BaseModel):
date_avoir: Optional[date] = None
date_livraison: Optional[date] = None
lignes: Optional[List[LigneAvoir]] = None
lignes: Optional[List[LigneDocument]] = None
statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None

View file

@ -1,23 +1,14 @@
from pydantic import BaseModel, Field, field_validator
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import date
class LigneCommande(BaseModel):
article_code: str
quantite: float
remise_pourcentage: Optional[float] = 0.0
@field_validator("article_code", mode="before")
def strip_insecables(cls, v):
return v.replace("\xa0", "").strip()
from schemas.documents.ligne_document import LigneDocument
class CommandeCreate(BaseModel):
client_id: str
date_commande: Optional[date] = None
date_livraison: Optional[date] = None
lignes: List[LigneCommande]
lignes: List[LigneDocument]
reference: Optional[str] = None
class Config:
@ -41,7 +32,7 @@ class CommandeCreate(BaseModel):
class CommandeUpdate(BaseModel):
date_commande: Optional[date] = None
date_livraison: Optional[date] = None
lignes: Optional[List[LigneCommande]] = None
lignes: Optional[List[LigneDocument]] = None
statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None

View file

@ -1,16 +1,8 @@
from pydantic import BaseModel, Field, field_validator
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import date
class LigneDevis(BaseModel):
article_code: str
quantite: float
remise_pourcentage: Optional[float] = 0.0
@field_validator("article_code", mode="before")
def strip_insecables(cls, v):
return v.replace("\xa0", "").strip()
from schemas.documents.ligne_document import LigneDocument
class DevisRequest(BaseModel):
@ -18,7 +10,7 @@ class DevisRequest(BaseModel):
date_devis: Optional[date] = None
date_livraison: Optional[date] = None
reference: Optional[str] = None
lignes: List[LigneDevis]
lignes: List[LigneDocument]
class Devis(BaseModel):
@ -35,8 +27,8 @@ class DevisUpdate(BaseModel):
date_devis: Optional[date] = None
date_livraison: Optional[date] = None
lignes: Optional[List[LigneDocument]] = None
reference: Optional[str] = None
lignes: Optional[List[LigneDevis]] = None
statut: Optional[int] = Field(None, ge=0, le=6)
class Config:

View file

@ -1,23 +1,14 @@
from pydantic import BaseModel, Field, field_validator
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import date
class LigneFacture(BaseModel):
article_code: str
quantite: float
remise_pourcentage: Optional[float] = 0.0
@field_validator("article_code", mode="before")
def strip_insecables(cls, v):
return v.replace("\xa0", "").strip()
from schemas.documents.ligne_document import LigneDocument
class FactureCreate(BaseModel):
client_id: str
date_facture: Optional[date] = None
date_livraison: Optional[date] = None
lignes: List[LigneFacture]
lignes: List[LigneDocument]
reference: Optional[str] = None
class Config:
@ -41,7 +32,7 @@ class FactureCreate(BaseModel):
class FactureUpdate(BaseModel):
date_facture: Optional[date] = None
date_livraison: Optional[date] = None
lignes: Optional[List[LigneFacture]] = None
lignes: Optional[List[LigneDocument]] = None
statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None

View file

@ -0,0 +1,25 @@
from pydantic import BaseModel, field_validator
from typing import Optional
class LigneDocument(BaseModel):
article_code: str
quantite: float
prix_unitaire_ht: Optional[float] = None
remise_pourcentage: Optional[float] = 0.0
@field_validator("article_code", mode="before")
def strip_insecables(cls, v):
return v.replace("\xa0", "").strip()
@field_validator("quantite")
def validate_quantite(cls, v):
if v <= 0:
raise ValueError("La quantité doit être positive")
return v
@field_validator("remise_pourcentage")
def validate_remise(cls, v):
if v is not None and (v < 0 or v > 100):
raise ValueError("La remise doit être entre 0 et 100")
return v

View file

@ -1,23 +1,15 @@
from pydantic import BaseModel, Field, field_validator
from pydantic import BaseModel, Field
from typing import List, Optional
from datetime import date
class LigneLivraison(BaseModel):
article_code: str
quantite: float
remise_pourcentage: Optional[float] = 0.0
@field_validator("article_code", mode="before")
def strip_insecables(cls, v):
return v.replace("\xa0", "").strip()
from schemas.documents.ligne_document import LigneDocument
class LivraisonCreate(BaseModel):
client_id: str
date_livraison: Optional[date] = None
date_livraison_prevue: Optional[date] = None
lignes: List[LigneLivraison]
lignes: List[LigneDocument]
reference: Optional[str] = None
class Config:
@ -41,7 +33,7 @@ class LivraisonCreate(BaseModel):
class LivraisonUpdate(BaseModel):
date_livraison: Optional[date] = None
date_livraison_prevue: Optional[date] = None
lignes: Optional[List[LigneLivraison]] = None
lignes: Optional[List[LigneDocument]] = None
statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None

View file

@ -1,6 +1,5 @@
from pydantic import BaseModel, Field, field_validator
from typing import List, Optional
from schemas.tiers.contact import Contact
from typing import Optional
from schemas.tiers.tiers import TiersDetails

View file

@ -1,4 +1,4 @@
from typing import Dict
from typing import Dict, List
from config.config import settings
import logging
@ -264,3 +264,18 @@ async def universign_statut(transaction_id: str) -> Dict:
except Exception as e:
logger.error(f"Erreur statut Universign: {e}")
return {"statut": "ERREUR", "error": str(e)}
def _preparer_lignes_document(lignes: List) -> List[Dict]:
return [
{
"article_code": ligne.article_code,
"quantite": ligne.quantite,
"prix_unitaire_ht": ligne.prix_unitaire_ht,
"remise_pourcentage": ligne.remise_pourcentage or 0.0,
}
for ligne in lignes
]
__all__ = ["_preparer_lignes_document"]