From f414a2889e13637cb79d5ff2559046d135e31098 Mon Sep 17 00:00:00 2001 From: Fanilo-Nantenaina Date: Fri, 26 Dec 2025 18:51:36 +0300 Subject: [PATCH] feat(client): add Contact model and contacts field to ClientDetails --- api.py | 65 +++++++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/api.py b/api.py index 04f7e9a..182eac1 100644 --- a/api.py +++ b/api.py @@ -124,13 +124,60 @@ class ClientResponse(BaseModel): telephone: Optional[str] = None # Téléphone principal (fixe ou mobile) +class Contact(BaseModel): + """ + Contact associé à un tiers (client/fournisseur) + 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)") + 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)") + nom: Optional[str] = Field(None, description="Nom de famille (CT_Nom)") + prenom: Optional[str] = Field(None, description="Prénom (CT_Prenom)") + fonction: Optional[str] = Field(None, description="Fonction/Titre (CT_Fonction)") + + service_code: Optional[int] = Field(None, description="Code du service (N_Service)") + + telephone: Optional[str] = Field(None, description="Téléphone fixe (CT_Telephone)") + portable: Optional[str] = Field(None, description="Téléphone mobile (CT_TelPortable)") + telecopie: Optional[str] = Field(None, description="Fax (CT_Telecopie)") + email: Optional[str] = Field(None, description="Adresse email (CT_EMail)") + + facebook: Optional[str] = Field(None, description="Profil Facebook (CT_Facebook)") + linkedin: Optional[str] = Field(None, description="Profil LinkedIn (CT_LinkedIn)") + skype: Optional[str] = Field(None, description="Identifiant Skype (CT_Skype)") + + class Config: + json_schema_extra = { + "example": { + "ct_num": "CLI000001", + "ct_no": 1, + "n_contact": 1, + "civilite": "M.", + "nom": "Dupont", + "prenom": "Jean", + "fonction": "Directeur Commercial", + "service_code": 1, + "telephone": "0123456789", + "portable": "0612345678", + "telecopie": "0123456788", + "email": "j.dupont@exemple.fr", + "facebook": "https://facebook.com/jean.dupont", + "linkedin": "https://linkedin.com/in/jeandupont", + "skype": "jean.dupont.pro" + } + } + + class ClientDetails(BaseModel): """ Modèle de réponse client complet (GET /clients/{code}) Strictement aligné avec les champs retournés par lister_tous_clients """ - # IDENTIFICATION (9 champs) numero: Optional[str] = Field(None, description="Code client (CT_Num)") intitule: Optional[str] = Field(None, description="Raison sociale ou Nom complet (CT_Intitule)") type_tiers: Optional[int] = Field(None, description="Type : 0=Client, 1=Fournisseur (CT_Type)") @@ -141,7 +188,6 @@ class ClientDetails(BaseModel): tva_intra: Optional[str] = Field(None, description="N° TVA intracommunautaire (CT_Identifiant)") code_naf: Optional[str] = Field(None, description="Code NAF/APE (CT_Ape)") - # ADRESSE (7 champs) contact: Optional[str] = Field(None, description="Nom du contact principal (CT_Contact)") adresse: Optional[str] = Field(None, description="Adresse ligne 1 (CT_Adresse)") complement: Optional[str] = Field(None, description="Complément d'adresse (CT_Complement)") @@ -150,7 +196,6 @@ class ClientDetails(BaseModel): region: Optional[str] = Field(None, description="Région/État (CT_CodeRegion)") pays: Optional[str] = Field(None, description="Pays (CT_Pays)") - # TELECOM (6 champs - pas de portable dans le SQL) telephone: Optional[str] = Field(None, description="Téléphone fixe (CT_Telephone)") telecopie: Optional[str] = Field(None, description="Fax (CT_Telecopie)") email: Optional[str] = Field(None, description="Email principal (CT_EMail)") @@ -158,13 +203,11 @@ class ClientDetails(BaseModel): facebook: Optional[str] = Field(None, description="Profil Facebook (CT_Facebook)") linkedin: Optional[str] = Field(None, description="Profil LinkedIn (CT_LinkedIn)") - # TAUX (4 champs) taux01: Optional[float] = Field(None, description="Taux personnalisé 1 (CT_Taux01)") taux02: Optional[float] = Field(None, description="Taux personnalisé 2 (CT_Taux02)") taux03: Optional[float] = Field(None, description="Taux personnalisé 3 (CT_Taux03)") taux04: Optional[float] = Field(None, description="Taux personnalisé 4 (CT_Taux04)") - # STATISTIQUES (10 champs - utiliser les noms exacts du SQL) statistique01: Optional[str] = Field(None, description="Statistique 1 (CT_Statistique01)") statistique02: Optional[str] = Field(None, description="Statistique 2 (CT_Statistique02)") statistique03: Optional[str] = Field(None, description="Statistique 3 (CT_Statistique03)") @@ -176,13 +219,11 @@ class ClientDetails(BaseModel): statistique09: Optional[str] = Field(None, description="Statistique 9 (CT_Statistique09)") statistique10: Optional[str] = Field(None, description="Statistique 10 (CT_Statistique10)") - # COMMERCIAL (4 champs) encours_autorise: Optional[float] = Field(None, description="Encours maximum autorisé (CT_Encours)") assurance_credit: Optional[float] = Field(None, description="Montant assurance crédit (CT_Assurance)") langue: Optional[int] = Field(None, description="Code langue 0=FR, 1=EN (CT_Langue)") commercial_code: Optional[int] = Field(None, description="Code du commercial (CO_No)") - # FACTURATION (11 champs) lettrage_auto: Optional[bool] = Field(None, description="Lettrage automatique (CT_Lettrage)") est_actif: Optional[bool] = Field(None, description="True si actif (CT_Sommeil=0)") type_facture: Optional[int] = Field(None, description="Type facture 0=Facture, 1=BL (CT_Facture)") @@ -195,19 +236,15 @@ class ClientDetails(BaseModel): exclure_penalites: Optional[bool] = Field(None, description="Exclure des pénalités (CT_NotPenal)") bon_a_payer: Optional[int] = Field(None, description="Bon à payer obligatoire (CT_BonAPayer)") - # LOGISTIQUE (4 champs) priorite_livraison: Optional[int] = Field(None, description="Priorité livraison (CT_PrioriteLivr)") livraison_partielle: Optional[int] = Field(None, description="Livraison partielle (CT_LivrPartielle)") delai_transport: Optional[int] = Field(None, description="Délai transport jours (CT_DelaiTransport)") delai_appro: Optional[int] = Field(None, description="Délai appro jours (CT_DelaiAppro)") - # COMMENTAIRE (1 champ) commentaire: Optional[str] = Field(None, description="Commentaire libre (CT_Commentaire)") - # ANALYTIQUE (1 champ) section_analytique: Optional[str] = Field(None, description="Section analytique (CA_Num)") - # ORGANISATION / SURVEILLANCE (10 champs) mode_reglement_code: Optional[int] = Field(None, description="Code mode règlement (MR_No)") surveillance_active: Optional[bool] = Field(None, description="Surveillance financière (CT_Surveillance)") coface: Optional[str] = Field(None, description="Code Coface 25 car. (CT_Coface)") @@ -219,10 +256,14 @@ class ClientDetails(BaseModel): sv_chiffre_affaires: Optional[float] = Field(None, description="Chiffre d'affaires (CT_SvCA)") sv_resultat: Optional[float] = Field(None, description="Résultat financier (CT_SvResultat)") - # COMPTE GENERAL ET CATEGORIES (3 champs) compte_general: Optional[str] = Field(None, description="Compte général principal (CG_NumPrinc)") categorie_tarif: Optional[int] = Field(None, description="Catégorie tarifaire (N_CatTarif)") categorie_compta: Optional[int] = Field(None, description="Catégorie comptable (N_CatCompta)") + + contacts: Optional[List[Contact]] = Field( + default_factory=list, + description="Liste des contacts du client" + ) class Config: json_schema_extra = {