Integrate create and update for livraison
This commit is contained in:
parent
35807542a3
commit
204b792015
2 changed files with 271 additions and 0 deletions
254
api.py
254
api.py
|
|
@ -347,6 +347,64 @@ class CommandeUpdateRequest(BaseModel):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class LigneLivraison(BaseModel):
|
||||||
|
"""Ligne de livraison"""
|
||||||
|
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()
|
||||||
|
|
||||||
|
|
||||||
|
class LivraisonCreateRequest(BaseModel):
|
||||||
|
"""Création d'une livraison"""
|
||||||
|
client_id: str
|
||||||
|
date_livraison: Optional[date] = None
|
||||||
|
lignes: List[LigneLivraison]
|
||||||
|
reference: Optional[str] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
json_schema_extra = {
|
||||||
|
"example": {
|
||||||
|
"client_id": "CLI000001",
|
||||||
|
"date_livraison": "2024-01-15",
|
||||||
|
"reference": "BL-EXT-001",
|
||||||
|
"lignes": [
|
||||||
|
{
|
||||||
|
"article_code": "ART001",
|
||||||
|
"quantite": 10.0,
|
||||||
|
"prix_unitaire_ht": 50.0,
|
||||||
|
"remise_pourcentage": 5.0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class LivraisonUpdateRequest(BaseModel):
|
||||||
|
"""Modification d'une livraison existante"""
|
||||||
|
date_livraison: Optional[date] = None
|
||||||
|
lignes: Optional[List[LigneLivraison]] = None
|
||||||
|
statut: Optional[int] = Field(None, ge=0, le=6)
|
||||||
|
reference: Optional[str] = None
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
json_schema_extra = {
|
||||||
|
"example": {
|
||||||
|
"lignes": [
|
||||||
|
{
|
||||||
|
"article_code": "ART001",
|
||||||
|
"quantite": 15.0,
|
||||||
|
"prix_unitaire_ht": 45.0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"statut": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# =====================================================
|
# =====================================================
|
||||||
# SERVICES EXTERNES (Universign)
|
# SERVICES EXTERNES (Universign)
|
||||||
# =====================================================
|
# =====================================================
|
||||||
|
|
@ -2448,6 +2506,202 @@ async def lire_livraison(numero: str):
|
||||||
logger.error(f"Erreur lecture livraison: {e}")
|
logger.error(f"Erreur lecture livraison: {e}")
|
||||||
raise HTTPException(500, str(e))
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
@app.post("/livraisons", status_code=201, tags=["Livraisons"])
|
||||||
|
async def creer_livraison(
|
||||||
|
livraison: LivraisonCreateRequest,
|
||||||
|
session: AsyncSession = Depends(get_session)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
➕ Création d'une nouvelle livraison (Bon de livraison)
|
||||||
|
|
||||||
|
**Workflow typique:**
|
||||||
|
1. Création d'une commande → transformation en livraison (automatique)
|
||||||
|
2. OU création directe d'une livraison (cette route)
|
||||||
|
|
||||||
|
**Champs obligatoires:**
|
||||||
|
- `client_id`: Code du client
|
||||||
|
- `lignes`: Liste des lignes (min 1)
|
||||||
|
|
||||||
|
**Champs optionnels:**
|
||||||
|
- `date_livraison`: Date de la livraison (par défaut: aujourd'hui)
|
||||||
|
- `reference`: Référence externe (ex: numéro de commande client)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Vérifier que le client existe
|
||||||
|
client = sage_client.lire_client(livraison.client_id)
|
||||||
|
if not client:
|
||||||
|
raise HTTPException(404, f"Client {livraison.client_id} introuvable")
|
||||||
|
|
||||||
|
# Préparer les données pour la gateway
|
||||||
|
livraison_data = {
|
||||||
|
"client_id": livraison.client_id,
|
||||||
|
"date_livraison": (
|
||||||
|
livraison.date_livraison.isoformat()
|
||||||
|
if livraison.date_livraison
|
||||||
|
else None
|
||||||
|
),
|
||||||
|
"reference": livraison.reference,
|
||||||
|
"lignes": [
|
||||||
|
{
|
||||||
|
"article_code": l.article_code,
|
||||||
|
"quantite": l.quantite,
|
||||||
|
"prix_unitaire_ht": l.prix_unitaire_ht,
|
||||||
|
"remise_pourcentage": l.remise_pourcentage,
|
||||||
|
}
|
||||||
|
for l in livraison.lignes
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
# Appel à la gateway Windows
|
||||||
|
resultat = sage_client.creer_livraison(livraison_data)
|
||||||
|
|
||||||
|
logger.info(f"✅ Livraison créée: {resultat.get('numero_livraison')}")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": "Livraison créée avec succès",
|
||||||
|
"data": {
|
||||||
|
"numero_livraison": resultat["numero_livraison"],
|
||||||
|
"client_id": livraison.client_id,
|
||||||
|
"date_livraison": resultat["date_livraison"],
|
||||||
|
"total_ht": resultat["total_ht"],
|
||||||
|
"total_ttc": resultat["total_ttc"],
|
||||||
|
"nb_lignes": resultat["nb_lignes"],
|
||||||
|
"reference": livraison.reference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur création livraison: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.put("/livraisons/{id}", tags=["Livraisons"])
|
||||||
|
async def modifier_livraison(
|
||||||
|
id: str,
|
||||||
|
livraison_update: LivraisonUpdateRequest,
|
||||||
|
session: AsyncSession = Depends(get_session)
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
✏️ Modification d'une livraison existante
|
||||||
|
|
||||||
|
**Champs modifiables:**
|
||||||
|
- `date_livraison`: Nouvelle date
|
||||||
|
- `lignes`: Nouvelles lignes (remplace toutes les lignes existantes)
|
||||||
|
- `statut`: Nouveau statut
|
||||||
|
- `reference`: Référence externe
|
||||||
|
|
||||||
|
**Restrictions:**
|
||||||
|
- Une livraison transformée (statut=5) ne peut plus être modifiée
|
||||||
|
- Une livraison annulée (statut=6) ne peut plus être modifiée
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Vérifier que la livraison existe
|
||||||
|
livraison_existante = sage_client.lire_livraison(id)
|
||||||
|
|
||||||
|
if not livraison_existante:
|
||||||
|
raise HTTPException(404, f"Livraison {id} introuvable")
|
||||||
|
|
||||||
|
# Vérifier le statut
|
||||||
|
statut_actuel = livraison_existante.get("statut", 0)
|
||||||
|
|
||||||
|
if statut_actuel == 5:
|
||||||
|
raise HTTPException(
|
||||||
|
400,
|
||||||
|
f"La livraison {id} a déjà été transformée et ne peut plus être modifiée"
|
||||||
|
)
|
||||||
|
|
||||||
|
if statut_actuel == 6:
|
||||||
|
raise HTTPException(
|
||||||
|
400,
|
||||||
|
f"La livraison {id} est annulée et ne peut plus être modifiée"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Construire les données de mise à jour
|
||||||
|
update_data = {}
|
||||||
|
|
||||||
|
if livraison_update.date_livraison:
|
||||||
|
update_data["date_livraison"] = livraison_update.date_livraison.isoformat()
|
||||||
|
|
||||||
|
if livraison_update.lignes is not None:
|
||||||
|
update_data["lignes"] = [
|
||||||
|
{
|
||||||
|
"article_code": l.article_code,
|
||||||
|
"quantite": l.quantite,
|
||||||
|
"prix_unitaire_ht": l.prix_unitaire_ht,
|
||||||
|
"remise_pourcentage": l.remise_pourcentage,
|
||||||
|
}
|
||||||
|
for l in livraison_update.lignes
|
||||||
|
]
|
||||||
|
|
||||||
|
if livraison_update.statut is not None:
|
||||||
|
update_data["statut"] = livraison_update.statut
|
||||||
|
|
||||||
|
if livraison_update.reference is not None:
|
||||||
|
update_data["reference"] = livraison_update.reference
|
||||||
|
|
||||||
|
# Appel à la gateway Windows
|
||||||
|
resultat = sage_client.modifier_livraison(id, update_data)
|
||||||
|
|
||||||
|
logger.info(f"✅ Livraison {id} modifiée avec succès")
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"message": f"Livraison {id} modifiée avec succès",
|
||||||
|
"livraison": resultat
|
||||||
|
}
|
||||||
|
|
||||||
|
except HTTPException:
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur modification livraison {id}: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.post("/workflow/livraison/{id}/to-facture", tags=["US-A2"])
|
||||||
|
async def livraison_vers_facture(id: str, session: AsyncSession = Depends(get_session)):
|
||||||
|
"""
|
||||||
|
🔧 Transformation Livraison → Facture
|
||||||
|
✅ Utilise les VRAIS types Sage (30 → 60)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
resultat = sage_client.transformer_document(
|
||||||
|
numero_source=id,
|
||||||
|
type_source=settings.SAGE_TYPE_BON_LIVRAISON, # = 30
|
||||||
|
type_cible=settings.SAGE_TYPE_FACTURE, # = 60
|
||||||
|
)
|
||||||
|
|
||||||
|
workflow_log = WorkflowLog(
|
||||||
|
id=str(uuid.uuid4()),
|
||||||
|
document_source=id,
|
||||||
|
type_source=TypeDocument.BON_LIVRAISON,
|
||||||
|
document_cible=resultat.get("document_cible", ""),
|
||||||
|
type_cible=TypeDocument.FACTURE,
|
||||||
|
nb_lignes=resultat.get("nb_lignes", 0),
|
||||||
|
date_transformation=datetime.now(),
|
||||||
|
succes=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
session.add(workflow_log)
|
||||||
|
await session.commit()
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"✅ Transformation: Livraison {id} → Facture {resultat['document_cible']}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"success": True,
|
||||||
|
"document_source": id,
|
||||||
|
"document_cible": resultat["document_cible"],
|
||||||
|
"nb_lignes": resultat["nb_lignes"],
|
||||||
|
}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur transformation: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
@app.get("/debug/users", response_model=List[UserResponse], tags=["Debug"])
|
@app.get("/debug/users", response_model=List[UserResponse], tags=["Debug"])
|
||||||
async def lister_utilisateurs_debug(
|
async def lister_utilisateurs_debug(
|
||||||
|
|
|
||||||
|
|
@ -443,6 +443,23 @@ class SageGatewayClient:
|
||||||
"numero": numero,
|
"numero": numero,
|
||||||
"commande_data": commande_data
|
"commande_data": commande_data
|
||||||
}).get("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", {})
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue