From 8f4c4f97a7f0894b7f4a5a4826621600fac60b18 Mon Sep 17 00:00:00 2001 From: Fanilo-Nantenaina Date: Tue, 9 Dec 2025 11:20:01 +0300 Subject: [PATCH] refactor(models): improve client models structure and documentation --- api.py | 214 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 152 insertions(+), 62 deletions(-) diff --git a/api.py b/api.py index 0176513..9fdeade 100644 --- a/api.py +++ b/api.py @@ -111,59 +111,125 @@ class StatutEmail(str, Enum): # MODÈLES PYDANTIC # ===================================================== class ClientResponse(BaseModel): + """Modèle de réponse client simplifié (pour listes)""" numero: Optional[str] = None intitule: Optional[str] = None adresse: Optional[str] = None code_postal: Optional[str] = None ville: Optional[str] = None email: Optional[str] = None - telephone: Optional[str] = None + telephone: Optional[str] = None # Téléphone principal (fixe ou mobile) -class ClientDetails(ClientResponse): - type: Optional[int] = None - qualite: Optional[str] = None - est_prospect: Optional[bool] = None - est_fournisseur: Optional[bool] = None - est_actif: Optional[bool] = None - est_en_sommeil: Optional[bool] = None - - civilite: Optional[str] = None - nom: Optional[str] = None - prenom: Optional[str] = None - nom_complet: Optional[str] = None - contact: Optional[str] = None - - complement: Optional[str] = None - region: Optional[str] = None - pays: Optional[str] = None - - portable: Optional[str] = None - telecopie: Optional[str] = None - site_web: Optional[str] = None - - siret: Optional[str] = None - siren: Optional[str] = None - tva_intra: Optional[str] = None - code_naf: Optional[str] = None - forme_juridique: Optional[str] = None - - secteur: Optional[str] = None - effectif: Optional[int] = None - ca_annuel: Optional[float] = None - commercial_code: Optional[str] = None - commercial_nom: Optional[str] = None - - categorie_tarifaire: Optional[int] = None - categorie_comptable: Optional[int] = None - - encours_autorise: Optional[float] = None - assurance_credit: Optional[float] = None - compte_general: Optional[str] = None - - date_creation: Optional[str] = None - date_modification: Optional[str] = None - +class ClientDetails(BaseModel): + """Modèle de réponse client complet (pour GET /clients/{code})""" + + # === IDENTIFICATION === + numero: Optional[str] = Field(None, description="Code client (CT_Num)") + intitule: Optional[str] = Field(None, description="Raison sociale ou Nom complet (CT_Intitule)") + + # === TYPE DE TIERS === + type_tiers: Optional[str] = Field( + None, + description="Type : 'client', 'prospect', 'fournisseur' ou 'client_fournisseur'" + ) + qualite: Optional[str] = Field( + None, + description="Qualité Sage : CLI (Client), FOU (Fournisseur), PRO (Prospect)" + ) + est_prospect: Optional[bool] = Field(None, description="True si prospect (CT_Prospect=1)") + est_fournisseur: Optional[bool] = Field(None, description="True si fournisseur (CT_Qualite=2 ou 3)") + + # === TYPE DE PERSONNE (ENTREPRISE VS PARTICULIER) === + forme_juridique: Optional[str] = Field( + None, + description="Forme juridique (SA, SARL, SAS, EI, etc.) - Vide si particulier" + ) + est_entreprise: Optional[bool] = Field( + None, + description="True si entreprise (forme_juridique renseignée)" + ) + est_particulier: Optional[bool] = Field( + None, + description="True si particulier (pas de forme juridique)" + ) + + # === STATUT === + est_actif: Optional[bool] = Field(None, description="True si actif (CT_Sommeil=0)") + est_en_sommeil: Optional[bool] = Field(None, description="True si en sommeil (CT_Sommeil=1)") + + # === IDENTITÉ (POUR PARTICULIERS) === + civilite: Optional[str] = Field(None, description="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)") + nom_complet: Optional[str] = Field( + None, + description="Nom complet formaté : 'Civilité Prénom Nom'" + ) + + # === CONTACT === + contact: Optional[str] = Field(None, description="Nom du contact principal (CT_Contact)") + + # === ADRESSE === + adresse: Optional[str] = Field(None, description="Adresse ligne 1") + complement: Optional[str] = Field(None, description="Complément d'adresse") + code_postal: Optional[str] = Field(None, description="Code postal") + ville: Optional[str] = Field(None, description="Ville") + region: Optional[str] = Field(None, description="Région/État") + pays: Optional[str] = Field(None, description="Pays") + + # === TÉLÉCOMMUNICATIONS === + 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 principal") + site_web: Optional[str] = Field(None, description="Site web") + + # === INFORMATIONS JURIDIQUES (ENTREPRISES) === + siret: Optional[str] = Field(None, description="N° SIRET (14 chiffres)") + siren: Optional[str] = Field(None, description="N° SIREN (9 chiffres)") + tva_intra: Optional[str] = Field(None, description="N° TVA intracommunautaire") + code_naf: Optional[str] = Field(None, description="Code NAF/APE") + + # === INFORMATIONS COMMERCIALES === + secteur: Optional[str] = Field(None, description="Secteur d'activité") + effectif: Optional[int] = Field(None, description="Nombre d'employés") + ca_annuel: Optional[float] = Field(None, description="Chiffre d'affaires annuel") + commercial_code: Optional[str] = Field(None, description="Code du commercial rattaché") + commercial_nom: Optional[str] = Field(None, description="Nom du commercial") + + # === CATÉGORIES === + categorie_tarifaire: Optional[int] = Field(None, description="Catégorie tarifaire (N_CatTarif)") + categorie_comptable: Optional[int] = Field(None, description="Catégorie comptable (N_CatCompta)") + + # === INFORMATIONS FINANCIÈRES === + encours_autorise: Optional[float] = Field(None, description="Encours maximum autorisé") + assurance_credit: Optional[float] = Field(None, description="Montant assurance crédit") + compte_general: Optional[str] = Field(None, description="Compte général principal") + + # === DATES === + date_creation: Optional[str] = Field(None, description="Date de création") + date_modification: Optional[str] = Field(None, description="Date de dernière modification") + + class Config: + json_schema_extra = { + "example": { + "numero": "CLI000001", + "intitule": "SARL EXEMPLE", + "type_tiers": "client", + "qualite": "CLI", + "est_entreprise": True, + "forme_juridique": "SARL", + "adresse": "123 Rue de la Paix", + "code_postal": "75001", + "ville": "Paris", + "telephone": "0123456789", + "portable": "0612345678", + "email": "contact@exemple.fr", + "siret": "12345678901234", + "tva_intra": "FR12345678901" + } + } class ArticleResponse(BaseModel): reference: str @@ -229,22 +295,47 @@ class BaremeRemiseResponse(BaseModel): class ClientCreateAPIRequest(BaseModel): - intitule: str = Field(..., min_length=1, description="Raison sociale ou Nom") - compte_collectif: str = Field("411000", description="Compte Comptable (ex: 411000)") - num: Optional[str] = Field(None, description="Code client souhaité (optionnel)") - adresse: Optional[str] = None - code_postal: Optional[str] = None - ville: Optional[str] = None - pays: Optional[str] = None + """Modèle pour création d'un nouveau client""" + + intitule: str = Field(..., min_length=1, max_length=69, description="Raison sociale ou Nom complet") + compte_collectif: str = Field("411000", description="Compte comptable (411000 par défaut)") + num: Optional[str] = Field(None, max_length=17, description="Code client souhaité (auto si vide)") + + # Adresse + adresse: Optional[str] = Field(None, max_length=35) + code_postal: Optional[str] = Field(None, max_length=9) + ville: Optional[str] = Field(None, max_length=35) + pays: Optional[str] = Field(None, max_length=35) + + # Contact email: Optional[EmailStr] = None - telephone: Optional[str] = None - siret: Optional[str] = None - tva_intra: Optional[str] = None - + telephone: Optional[str] = Field(None, max_length=21, description="Téléphone fixe") + portable: Optional[str] = Field(None, max_length=21, description="Téléphone mobile") + + # Juridique + forme_juridique: Optional[str] = Field(None, max_length=50, description="SARL, SA, SAS, EI, etc.") + siret: Optional[str] = Field(None, max_length=14) + tva_intra: Optional[str] = Field(None, max_length=25) + + class Config: + json_schema_extra = { + "example": { + "intitule": "SARL NOUVELLE ENTREPRISE", + "forme_juridique": "SARL", + "adresse": "10 Avenue des Champs", + "code_postal": "75008", + "ville": "Paris", + "telephone": "0123456789", + "portable": "0612345678", + "email": "contact@nouvelle-entreprise.fr", + "siret": "12345678901234", + "tva_intra": "FR12345678901" + } + } class ClientUpdateRequest(BaseModel): """Modèle pour modification d'un client existant""" - + intitule: Optional[str] = Field(None, min_length=1, max_length=69) adresse: Optional[str] = Field(None, max_length=35) code_postal: Optional[str] = Field(None, max_length=9) @@ -252,18 +343,17 @@ class ClientUpdateRequest(BaseModel): pays: Optional[str] = Field(None, max_length=35) email: Optional[EmailStr] = None telephone: Optional[str] = Field(None, max_length=21) + portable: Optional[str] = Field(None, max_length=21) + forme_juridique: Optional[str] = Field(None, max_length=50) siret: Optional[str] = Field(None, max_length=14) tva_intra: Optional[str] = Field(None, max_length=25) - + class Config: json_schema_extra = { "example": { - "intitule": "SARL TEST MODIFIÉ", - "adresse": "456 Avenue des Champs", - "code_postal": "75008", - "ville": "Paris", "email": "nouveau@email.fr", "telephone": "0198765432", + "portable": "0687654321" } }