feat(api): add date fields to document models

This commit is contained in:
Fanilo-Nantenaina 2025-12-20 16:19:23 +03:00
parent edfa4a0231
commit dbb2a6f16e
2 changed files with 49 additions and 48 deletions

37
api.py
View file

@ -357,6 +357,8 @@ class LigneDevis(BaseModel):
class DevisRequest(BaseModel): class DevisRequest(BaseModel):
client_id: str client_id: str
date_devis: Optional[date] = None date_devis: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
reference: Optional[str] = None reference: Optional[str] = None
lignes: List[LigneDevis] lignes: List[LigneDevis]
@ -564,6 +566,8 @@ class DevisUpdateRequest(BaseModel):
"""Modèle pour modification d'un devis existant""" """Modèle pour modification d'un devis existant"""
date_devis: Optional[date] = None date_devis: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
reference: Optional[str] = None reference: Optional[str] = None
lignes: Optional[List[LigneDevis]] = None lignes: Optional[List[LigneDevis]] = None
statut: Optional[int] = Field(None, ge=0, le=6) statut: Optional[int] = Field(None, ge=0, le=6)
@ -572,6 +576,8 @@ class DevisUpdateRequest(BaseModel):
json_schema_extra = { json_schema_extra = {
"example": { "example": {
"date_devis": "2024-01-15", "date_devis": "2024-01-15",
"date_livraison": "2024-01-15",
"date_expedition": "2024-01-15",
"reference": "DEV-001", "reference": "DEV-001",
"lignes": [ "lignes": [
{ {
@ -604,8 +610,10 @@ class CommandeCreateRequest(BaseModel):
client_id: str client_id: str
date_commande: Optional[date] = None date_commande: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
lignes: List[LigneCommande] lignes: List[LigneCommande]
reference: Optional[str] = None # Référence externe reference: Optional[str] = None
class Config: class Config:
json_schema_extra = { json_schema_extra = {
@ -629,6 +637,8 @@ class CommandeUpdateRequest(BaseModel):
"""Modification d'une commande existante""" """Modification d'une commande existante"""
date_commande: Optional[date] = None date_commande: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
lignes: Optional[List[LigneCommande]] = None lignes: Optional[List[LigneCommande]] = None
statut: Optional[int] = Field(None, ge=0, le=6) statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None reference: Optional[str] = None
@ -637,6 +647,8 @@ class CommandeUpdateRequest(BaseModel):
json_schema_extra = { json_schema_extra = {
"example": { "example": {
"date_commande": "2024-01-15", "date_commande": "2024-01-15",
"date_livraison": "2024-01-15",
"date_expedition": "2024-01-15",
"reference": "CMD-EXT-001", "reference": "CMD-EXT-001",
"lignes": [ "lignes": [
{ {
@ -668,6 +680,8 @@ class LivraisonCreateRequest(BaseModel):
client_id: str client_id: str
date_livraison: Optional[date] = None date_livraison: Optional[date] = None
date_livraison_prevue: Optional[date] = None
date_expedition: Optional[date] = None
lignes: List[LigneLivraison] lignes: List[LigneLivraison]
reference: Optional[str] = None reference: Optional[str] = None
@ -693,6 +707,8 @@ class LivraisonUpdateRequest(BaseModel):
"""Modification d'une livraison existante""" """Modification d'une livraison existante"""
date_livraison: Optional[date] = None date_livraison: Optional[date] = None
date_livraison_prevue: Optional[date] = None
date_expedition: Optional[date] = None
lignes: Optional[List[LigneLivraison]] = None lignes: Optional[List[LigneLivraison]] = None
statut: Optional[int] = Field(None, ge=0, le=6) statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None reference: Optional[str] = None
@ -700,6 +716,10 @@ class LivraisonUpdateRequest(BaseModel):
class Config: class Config:
json_schema_extra = { json_schema_extra = {
"example": { "example": {
"date_livraison": "2024-01-15",
"date_livraison_prevue": "2024-01-15",
"date_expedition": "2024-01-15",
"reference": "BL-EXT-001",
"lignes": [ "lignes": [
{ {
"article_code": "ART001", "article_code": "ART001",
@ -730,6 +750,8 @@ class AvoirCreateRequest(BaseModel):
client_id: str client_id: str
date_avoir: Optional[date] = None date_avoir: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
lignes: List[LigneAvoir] lignes: List[LigneAvoir]
reference: Optional[str] = None reference: Optional[str] = None
@ -755,6 +777,8 @@ class AvoirUpdateRequest(BaseModel):
"""Modification d'un avoir existant""" """Modification d'un avoir existant"""
date_avoir: Optional[date] = None date_avoir: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
lignes: Optional[List[LigneAvoir]] = None lignes: Optional[List[LigneAvoir]] = None
statut: Optional[int] = Field(None, ge=0, le=6) statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None reference: Optional[str] = None
@ -762,6 +786,10 @@ class AvoirUpdateRequest(BaseModel):
class Config: class Config:
json_schema_extra = { json_schema_extra = {
"example": { "example": {
"date_avoir": "2024-01-15",
"date_livraison": "2024-01-15",
"date_expedition": "2024-01-15",
"reference": "AV-EXT-001",
"lignes": [ "lignes": [
{ {
"article_code": "ART001", "article_code": "ART001",
@ -792,6 +820,8 @@ class FactureCreateRequest(BaseModel):
client_id: str client_id: str
date_facture: Optional[date] = None date_facture: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
lignes: List[LigneFacture] lignes: List[LigneFacture]
reference: Optional[str] = None reference: Optional[str] = None
@ -817,6 +847,8 @@ class FactureUpdateRequest(BaseModel):
"""Modification d'une facture existante""" """Modification d'une facture existante"""
date_facture: Optional[date] = None date_facture: Optional[date] = None
date_livraison: Optional[date] = None
date_expedition: Optional[date] = None
lignes: Optional[List[LigneFacture]] = None lignes: Optional[List[LigneFacture]] = None
statut: Optional[int] = Field(None, ge=0, le=6) statut: Optional[int] = Field(None, ge=0, le=6)
reference: Optional[str] = None reference: Optional[str] = None
@ -824,6 +856,9 @@ class FactureUpdateRequest(BaseModel):
class Config: class Config:
json_schema_extra = { json_schema_extra = {
"example": { "example": {
"date_facture": "2024-01-15",
"date_livraison": "2024-01-15",
"date_expedition": "2024-01-15",
"lignes": [ "lignes": [
{ {
"article_code": "ART001", "article_code": "ART001",

View file

@ -7,10 +7,6 @@ logger = logging.getLogger(__name__)
class SageGatewayClient: class SageGatewayClient:
"""
Client HTTP pour communiquer avec la gateway Sage Windows
"""
def __init__(self): def __init__(self):
self.url = settings.sage_gateway_url.rstrip("/") self.url = settings.sage_gateway_url.rstrip("/")
self.headers = { self.headers = {
@ -264,9 +260,6 @@ class SageGatewayClient:
"""Lecture d'une livraison avec ses lignes""" """Lecture d'une livraison avec ses lignes"""
return self._post("/sage/livraisons/get", {"code": numero}).get("data") return self._post("/sage/livraisons/get", {"code": numero}).get("data")
# =====================================================
# CACHE (ADMIN)
# =====================================================
def refresh_cache(self) -> Dict: def refresh_cache(self) -> Dict:
"""Force le rafraîchissement du cache Windows""" """Force le rafraîchissement du cache Windows"""
return self._post("/sage/cache/refresh") return self._post("/sage/cache/refresh")
@ -275,9 +268,6 @@ class SageGatewayClient:
"""Récupère les infos du cache Windows""" """Récupère les infos du cache Windows"""
return self._get("/sage/cache/info").get("data", {}) return self._get("/sage/cache/info").get("data", {})
# =====================================================
# HEALTH
# =====================================================
def health(self) -> dict: def health(self) -> dict:
"""Health check de la gateway Windows""" """Health check de la gateway Windows"""
try: try:
@ -336,12 +326,11 @@ class SageGatewayClient:
try: try:
logger.info(f"📄 Demande génération PDF: doc_id={doc_id}, type={type_doc}") logger.info(f"📄 Demande génération PDF: doc_id={doc_id}, type={type_doc}")
# Appel HTTP vers la gateway Windows
r = requests.post( r = requests.post(
f"{self.url}/sage/documents/generate-pdf", f"{self.url}/sage/documents/generate-pdf",
json={"doc_id": doc_id, "type_doc": type_doc}, json={"doc_id": doc_id, "type_doc": type_doc},
headers=self.headers, headers=self.headers,
timeout=60, # Timeout élevé pour génération PDF timeout=60,
) )
r.raise_for_status() r.raise_for_status()
@ -350,7 +339,6 @@ class SageGatewayClient:
response_data = r.json() response_data = r.json()
# Vérifier que la réponse contient bien le PDF
if not response_data.get("success"): if not response_data.get("success"):
error_msg = response_data.get("error", "Erreur inconnue") error_msg = response_data.get("error", "Erreur inconnue")
raise RuntimeError(f"Gateway a retourné une erreur: {error_msg}") raise RuntimeError(f"Gateway a retourné une erreur: {error_msg}")
@ -362,7 +350,6 @@ class SageGatewayClient:
f"PDF vide retourné par la gateway pour {doc_id} (type {type_doc})" f"PDF vide retourné par la gateway pour {doc_id} (type {type_doc})"
) )
# Décoder le base64
pdf_bytes = base64.b64decode(pdf_base64) pdf_bytes = base64.b64decode(pdf_base64)
logger.info(f"✅ PDF décodé: {len(pdf_bytes)} octets") logger.info(f"✅ PDF décodé: {len(pdf_bytes)} octets")
@ -410,15 +397,12 @@ class SageGatewayClient:
def get_stats_familles(self) -> Dict: def get_stats_familles(self) -> Dict:
return self._get("/sage/familles/stats").get("data", {}) return self._get("/sage/familles/stats").get("data", {})
def creer_entree_stock(self, entree_data: Dict) -> Dict: def creer_entree_stock(self, entree_data: Dict) -> Dict:
return self._post("/sage/stock/entree", entree_data).get("data", {}) return self._post("/sage/stock/entree", entree_data).get("data", {})
def creer_sortie_stock(self, sortie_data: Dict) -> Dict: def creer_sortie_stock(self, sortie_data: Dict) -> Dict:
return self._post("/sage/stock/sortie", sortie_data).get("data", {}) return self._post("/sage/stock/sortie", sortie_data).get("data", {})
def lire_mouvement_stock(self, numero: str) -> Optional[Dict]: def lire_mouvement_stock(self, numero: str) -> Optional[Dict]:
try: try:
response = self._get(f"/sage/stock/mouvement/{numero}") response = self._get(f"/sage/stock/mouvement/{numero}")
@ -427,14 +411,11 @@ class SageGatewayClient:
logger.error(f"Erreur lecture mouvement {numero}: {e}") logger.error(f"Erreur lecture mouvement {numero}: {e}")
return None return None
def lister_modeles_disponibles(self) -> Dict: def lister_modeles_disponibles(self) -> Dict:
"""Liste les modèles Crystal Reports disponibles""" """Liste les modèles Crystal Reports disponibles"""
try: try:
r = requests.get( r = requests.get(
f"{self.url}/sage/modeles/list", f"{self.url}/sage/modeles/list", headers=self.headers, timeout=30
headers=self.headers,
timeout=30
) )
r.raise_for_status() r.raise_for_status()
return r.json().get("data", {}) return r.json().get("data", {})
@ -442,26 +423,11 @@ class SageGatewayClient:
logger.error(f"❌ Erreur listage modèles: {e}") logger.error(f"❌ Erreur listage modèles: {e}")
raise raise
def generer_pdf_document( def generer_pdf_document(
self, self, numero: str, type_doc: int, modele: str = None, base64_encode: bool = True
numero: str,
type_doc: int,
modele: str = None,
base64_encode: bool = True
) -> Union[bytes, str, Dict]: ) -> Union[bytes, str, Dict]:
"""
Génère un PDF d'un document Sage
Returns:
Dict: Avec pdf_base64 si base64_encode=True
bytes: Contenu PDF brut si base64_encode=False
"""
try: try:
params = { params = {"type_doc": type_doc, "base64_encode": base64_encode}
"type_doc": type_doc,
"base64_encode": base64_encode
}
if modele: if modele:
params["modele"] = modele params["modele"] = modele
@ -470,7 +436,7 @@ class SageGatewayClient:
f"{self.url}/sage/documents/{numero}/pdf", f"{self.url}/sage/documents/{numero}/pdf",
params=params, params=params,
headers=self.headers, headers=self.headers,
timeout=60 # PDF peut prendre du temps timeout=60,
) )
r.raise_for_status() r.raise_for_status()