Added contact handling

This commit is contained in:
Fanilo-Nantenaina 2025-12-28 21:20:15 +03:00
parent e9e4aff0db
commit 18699a8673
2 changed files with 220 additions and 5 deletions

167
api.py
View file

@ -130,8 +130,8 @@ class Contact(BaseModel):
Tous les champs de F_CONTACTT
"""
ct_num: Optional[str] = Field(None, description="Code du tiers parent (CT_Num)")
ct_no: Optional[int] = Field(None, description="Numéro unique du contact (CT_No)")
numero: Optional[str] = Field(None, description="Code du tiers parent (CT_Num)")
contact_numero: Optional[int] = Field(None, description="Numéro unique du contact (CT_No)")
n_contact: Optional[int] = Field(None, description="Numéro de référence contact (N_Contact)")
civilite: Optional[str] = Field(None, description="Civilité : M., Mme, Mlle (CT_Civilite)")
@ -150,6 +150,11 @@ class Contact(BaseModel):
linkedin: Optional[str] = Field(None, description="Profil LinkedIn (CT_LinkedIn)")
skype: Optional[str] = Field(None, description="Identifiant Skype (CT_Skype)")
est_defaut: Optional[bool] = Field(
False,
description="True si ce contact est le contact par défaut du client"
)
civilite_map: ClassVar[dict] = {
0: "M.",
1: "Mme",
@ -168,8 +173,8 @@ class Contact(BaseModel):
class Config:
json_schema_extra = {
"example": {
"ct_num": "CLI000001",
"ct_no": 1,
"numero": "CLI000001",
"contact_numero": 1,
"n_contact": 1,
"civilite": "M.",
"nom": "Dupont",
@ -2578,6 +2583,67 @@ class MouvementStockResponse(BaseModel):
nb_lignes: int = Field(..., description="Nombre de lignes")
class ContactCreate(BaseModel):
"""Données pour créer ou modifier un contact"""
numero: str = Field(..., description="Code du client parent (obligatoire)")
civilite: Optional[str] = Field(None, description="M., Mme, Mlle, Société")
nom: str = Field(..., description="Nom de famille (obligatoire)")
prenom: Optional[str] = Field(None, description="Prénom")
fonction: Optional[str] = Field(None, description="Fonction/Titre")
est_defaut: Optional[bool] = Field(False, description="Définir comme contact par défaut du client")
service_code: Optional[int] = Field(None, description="Code du service")
telephone: Optional[str] = Field(None, description="Téléphone fixe")
portable: Optional[str] = Field(None, description="Téléphone mobile")
telecopie: Optional[str] = Field(None, description="Fax")
email: Optional[str] = Field(None, description="Email")
facebook: Optional[str] = Field(None, description="URL Facebook")
linkedin: Optional[str] = Field(None, description="URL LinkedIn")
skype: Optional[str] = Field(None, description="Identifiant Skype")
@validator("civilite")
def validate_civilite(cls, v):
if v and v not in ["M.", "Mme", "Mlle", "Société"]:
raise ValueError("Civilité doit être: M., Mme, Mlle ou Société")
return v
class Config:
json_schema_extra = {
"example": {
"numero": "CLI000001",
"civilite": "M.",
"nom": "Dupont",
"prenom": "Jean",
"fonction": "Directeur Commercial",
"telephone": "0123456789",
"portable": "0612345678",
"email": "j.dupont@exemple.fr",
"linkedin": "https://linkedin.com/in/jeandupont",
"est_defaut": True
}
}
class ContactUpdate(BaseModel):
"""Données pour modifier un contact (tous champs optionnels)"""
civilite: Optional[str] = None
nom: Optional[str] = None
prenom: Optional[str] = None
fonction: Optional[str] = None
service_code: Optional[int] = None
telephone: Optional[str] = None
portable: Optional[str] = None
telecopie: Optional[str] = None
email: Optional[str] = None
facebook: Optional[str] = None
linkedin: Optional[str] = None
skype: Optional[str] = None
est_defaut: Optional[bool] = None
templates_signature_email = {
"demande_signature": {
"id": "demande_signature",
@ -3218,7 +3284,7 @@ app.include_router(auth_router)
@app.get("/clients", response_model=List[ClientDetails], tags=["Clients"])
async def rechercher_clients(query: Optional[str] = Query(None)):
async def obtenir_clients(query: Optional[str] = Query(None)):
try:
clients = sage_client.lister_clients(filtre=query or "")
return [ClientDetails(**c) for c in clients]
@ -5926,6 +5992,97 @@ async def get_document_pdf(
@app.post("/clients/{numero}/contacts", response_model=Contact, tags=["Contacts"])
async def creer_contact(numero: str, contact: ContactCreate):
try:
try:
sage_client.obtenir_client(numero)
except:
raise HTTPException(404, f"Client {numero} non trouvé")
if contact.numero != numero:
contact.numero = numero
resultat = sage_client.creer_contact(contact.dict())
return Contact(**resultat)
except HTTPException:
raise
except Exception as e:
logger.error(f"Erreur création contact: {e}")
raise HTTPException(500, str(e))
@app.get("/clients/{numero}/contacts", response_model=List[Contact], tags=["Contacts"])
async def lister_contacts_client(numero: str):
try:
contacts = sage_client.lister_contacts(numero)
return [Contact(**c) for c in contacts]
except Exception as e:
logger.error(f"Erreur liste contacts: {e}")
raise HTTPException(500, str(e))
@app.get("/clients/{numero}/contacts/{contact_numero}", response_model=Contact, tags=["Contacts"])
async def obtenir_contact(numero: str, contact_numero: int):
try:
contact = sage_client.obtenir_contact(numero, contact_numero)
if not contact:
raise HTTPException(404, f"Contact {contact_numero} non trouvé pour client {numero}")
return Contact(**contact)
except HTTPException:
raise
except Exception as e:
logger.error(f"Erreur récupération contact: {e}")
raise HTTPException(500, str(e))
@app.put("/clients/{numero}/contacts/{contact_numero}", response_model=Contact, tags=["Contacts"])
async def modifier_contact(numero: str, contact_numero: int, contact: ContactUpdate):
try:
contact_existant = sage_client.obtenir_contact(numero, contact_numero)
if not contact_existant:
raise HTTPException(404, f"Contact {contact_numero} non trouvé")
updates = {k: v for k, v in contact.dict().items() if v is not None}
if not updates:
raise HTTPException(400, "Aucune modification fournie")
resultat = sage_client.modifier_contact(numero, contact_numero, updates)
return Contact(**resultat)
except HTTPException:
raise
except Exception as e:
logger.error(f"Erreur modification contact: {e}")
raise HTTPException(500, str(e))
@app.delete("/clients/{numero}/contacts/{contact_numero}", tags=["Contacts"])
async def supprimer_contact(numero: str, contact_numero: int):
try:
resultat = sage_client.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}")
raise HTTPException(500, str(e))
@app.post("/clients/{numero}/contacts/{contact_numero}/definir-defaut", tags=["Contacts"])
async def definir_contact_defaut(numero: str, contact_numero: int):
try:
resultat = sage_client.definir_contact_defaut(numero, contact_numero)
return {
"success": True,
"message": f"Contact {contact_numero} défini comme contact par défaut",
"data": resultat
}
except Exception as e:
logger.error(f"Erreur définition contact par défaut: {e}")
raise HTTPException(500, str(e))
if __name__ == "__main__":
uvicorn.run(
"api:app",

View file

@ -450,4 +450,62 @@ class SageGatewayClient:
raise
def creer_contact(self, contact_data: Dict) -> Dict:
return self._post("/sage/contacts/create", contact_data)
def lister_contacts(self, numero: str) -> List[Dict]:
return self._post("/sage/contacts/list", {"numero": numero}).get("data", [])
def obtenir_contact(self, numero: str, contact_numero: int) -> Dict:
result = self._post("/sage/contacts/get", {
"numero": numero,
"contact_numero": contact_numero
})
return result.get("data") if result.get("success") else None
def modifier_contact(self, numero: str, contact_numero: int, updates: Dict) -> Dict:
return self._post("/sage/contacts/update", {
"numero": numero,
"contact_numero": contact_numero,
"updates": updates
})
def supprimer_contact(self, numero: str, contact_numero: int) -> Dict:
"""
Supprime un contact
Args:
numero: Code du client
contact_numero: Numéro unique du contact
Returns:
Dictionnaire avec le statut de la suppression
"""
return self._post("/sage/contacts/delete", {
"numero": numero,
"contact_numero": contact_numero
})
def definir_contact_defaut(self, numero: str, contact_numero: int) -> Dict:
"""
Définit un contact comme contact par défaut du client
Args:
numero: Code du client
contact_numero: Numéro unique du contact à définir comme par défaut
Returns:
Dictionnaire avec les données du client mis à jour
"""
return self._post("/sage/contacts/set-default", {
"numero": numero,
"contact_numero": contact_numero
})
sage_client = SageGatewayClient()