refactor(api): simplify ClientDetails model by removing unused fields and reorganizing structure

This commit is contained in:
Fanilo-Nantenaina 2025-12-26 17:49:14 +03:00
parent ca532fc890
commit 61869f3293

350
api.py
View file

@ -127,257 +127,115 @@ class ClientResponse(BaseModel):
class ClientDetails(BaseModel): class ClientDetails(BaseModel):
""" """
Modèle de réponse client complet (GET /clients/{code}) Modèle de réponse client complet (GET /clients/{code})
Aligné avec tous les champs gérés par creer_client et lister_tous_clients Strictement aligné avec les champs retournés par lister_tous_clients
""" """
# IDENTIFICATION (9 champs)
numero: Optional[str] = Field(None, description="Code client (CT_Num)") numero: Optional[str] = Field(None, description="Code client (CT_Num)")
intitule: Optional[str] = Field( intitule: Optional[str] = Field(None, description="Raison sociale ou Nom complet (CT_Intitule)")
None, description="Raison sociale ou Nom complet (CT_Intitule)" type_tiers: Optional[int] = Field(None, description="Type : 0=Client, 1=Fournisseur (CT_Type)")
) qualite: Optional[str] = Field(None, description="Qualité Sage : CLI, FOU, PRO (CT_Qualite)")
type_tiers: Optional[str] = Field( classement: Optional[str] = Field(None, description="Code de classement (CT_Classement)")
None, raccourci: Optional[str] = Field(None, description="Code raccourci 7 car. (CT_Raccourci)")
description="Type : 'client', 'prospect', 'fournisseur' ou 'client_fournisseur'", siret: Optional[str] = Field(None, description="N° SIRET 14 chiffres (CT_Siret)")
) tva_intra: Optional[str] = Field(None, description="N° TVA intracommunautaire (CT_Identifiant)")
qualite: Optional[str] = Field( code_naf: Optional[str] = Field(None, description="Code NAF/APE (CT_Ape)")
None,
description="Qualité Sage : CLI (Client), FOU (Fournisseur), PRO (Prospect)",
)
classement: Optional[str] = Field(
None, description="Code de classement personnalisé (CT_Classement)"
)
raccourci: Optional[str] = Field(
None, description="Code raccourci (7 car. max) (CT_Raccourci)"
)
est_prospect: Optional[bool] = Field(
None, description="True si prospect (CT_Prospect=1)"
)
est_fournisseur: Optional[bool] = Field(
None, description="True si fournisseur (CT_Type=1 ou CT_Qualite contient FOU)"
)
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)"
)
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: Optional[str] = Field(
None, description="Nom du contact principal (CT_Contact)"
)
# 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)") adresse: Optional[str] = Field(None, description="Adresse ligne 1 (CT_Adresse)")
complement: Optional[str] = Field( complement: Optional[str] = Field(None, description="Complément d'adresse (CT_Complement)")
None, description="Complément d'adresse (CT_Complement)"
)
code_postal: Optional[str] = Field(None, description="Code postal (CT_CodePostal)") code_postal: Optional[str] = Field(None, description="Code postal (CT_CodePostal)")
ville: Optional[str] = Field(None, description="Ville (CT_Ville)") ville: Optional[str] = Field(None, description="Ville (CT_Ville)")
region: Optional[str] = Field(None, description="Région/État (CT_CodeRegion)") region: Optional[str] = Field(None, description="Région/État (CT_CodeRegion)")
pays: Optional[str] = Field(None, description="Pays (CT_Pays)") 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)") telephone: Optional[str] = Field(None, description="Téléphone fixe (CT_Telephone)")
portable: Optional[str] = Field(None, description="Téléphone mobile")
telecopie: Optional[str] = Field(None, description="Fax (CT_Telecopie)") telecopie: Optional[str] = Field(None, description="Fax (CT_Telecopie)")
email: Optional[str] = Field(None, description="Email principal (CT_EMail)") email: Optional[str] = Field(None, description="Email principal (CT_EMail)")
site_web: Optional[str] = Field(None, description="Site web (CT_Site)") site_web: Optional[str] = Field(None, description="Site web (CT_Site)")
facebook: Optional[str] = Field( facebook: Optional[str] = Field(None, description="Profil Facebook (CT_Facebook)")
None, description="Profil Facebook (CT_Facebook)" linkedin: Optional[str] = Field(None, description="Profil LinkedIn (CT_LinkedIn)")
)
linkedin: Optional[str] = Field(
None, description="Profil LinkedIn (CT_LinkedIn)"
)
forme_juridique: Optional[str] = Field(
None,
description="Forme juridique (SA, SARL, SAS, EI, etc.) (CT_SvFormeJuri)",
)
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)"
)
siret: Optional[str] = Field(None, description="N° SIRET 14 chiffres (CT_Siret)")
siren: Optional[str] = Field(
None, description="N° SIREN 9 chiffres (extrait du SIRET)"
)
tva_intra: Optional[str] = Field(
None, description="N° TVA intracommunautaire (CT_Identifiant)"
)
code_naf: Optional[str] = Field(None, description="Code NAF/APE (CT_Ape)")
# TAUX (4 champs)
taux01: Optional[float] = Field(None, description="Taux personnalisé 1 (CT_Taux01)") taux01: Optional[float] = Field(None, description="Taux personnalisé 1 (CT_Taux01)")
taux02: Optional[float] = Field(None, description="Taux personnalisé 2 (CT_Taux02)") taux02: Optional[float] = Field(None, description="Taux personnalisé 2 (CT_Taux02)")
taux03: Optional[float] = Field(None, description="Taux personnalisé 3 (CT_Taux03)") taux03: Optional[float] = Field(None, description="Taux personnalisé 3 (CT_Taux03)")
taux04: Optional[float] = Field(None, description="Taux personnalisé 4 (CT_Taux04)") taux04: Optional[float] = Field(None, description="Taux personnalisé 4 (CT_Taux04)")
secteur: Optional[str] = Field( # STATISTIQUES (10 champs - utiliser les noms exacts du SQL)
None, description="Secteur d'activité (CT_Statistique01)" statistique01: Optional[str] = Field(None, description="Statistique 1 (CT_Statistique01)")
) statistique02: Optional[str] = Field(None, description="Statistique 2 (CT_Statistique02)")
statistique02: Optional[str] = Field( statistique03: Optional[str] = Field(None, description="Statistique 3 (CT_Statistique03)")
None, description="Statistique 2 (CT_Statistique02)" statistique04: Optional[str] = Field(None, description="Statistique 4 (CT_Statistique04)")
) statistique05: Optional[str] = Field(None, description="Statistique 5 (CT_Statistique05)")
statistique03: Optional[str] = Field( statistique06: Optional[str] = Field(None, description="Statistique 6 (CT_Statistique06)")
None, description="Statistique 3 (CT_Statistique03)" statistique07: Optional[str] = Field(None, description="Statistique 7 (CT_Statistique07)")
) statistique08: Optional[str] = Field(None, description="Statistique 8 (CT_Statistique08)")
statistique04: Optional[str] = Field( statistique09: Optional[str] = Field(None, description="Statistique 9 (CT_Statistique09)")
None, description="Statistique 4 (CT_Statistique04)" statistique10: Optional[str] = Field(None, description="Statistique 10 (CT_Statistique10)")
)
statistique05: Optional[str] = Field(
None, description="Statistique 5 (CT_Statistique05)"
)
statistique06: Optional[str] = Field(
None, description="Statistique 6 (CT_Statistique06)"
)
statistique07: Optional[str] = Field(
None, description="Statistique 7 (CT_Statistique07)"
)
statistique08: Optional[str] = Field(
None, description="Statistique 8 (CT_Statistique08)"
)
statistique09: Optional[str] = Field(
None, description="Statistique 9 (CT_Statistique09)"
)
statistique10: Optional[str] = Field(
None, description="Statistique 10 (CT_Statistique10)"
)
effectif: Optional[str] = Field( # COMMERCIAL (4 champs)
None, description="Nombre d'employés (CT_SvEffectif)" 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)")
ca_annuel: Optional[float] = Field( langue: Optional[int] = Field(None, description="Code langue 0=FR, 1=EN (CT_Langue)")
None, description="Chiffre d'affaires annuel (CT_SvCA)" commercial_code: Optional[int] = Field(None, description="Code du commercial (CO_No)")
)
commercial_code: Optional[int] = Field(
None, description="Code du commercial rattaché (CO_No)"
)
commercial_nom: Optional[str] = Field(None, description="Nom du commercial")
langue: Optional[int] = Field(
None, description="Code langue (0=Français, 1=Anglais...) (CT_Langue)"
)
categorie_tarifaire: Optional[int] = Field( # FACTURATION (11 champs)
None, description="Catégorie tarifaire (N_CatTarif)" lettrage_auto: Optional[bool] = Field(None, description="Lettrage automatique (CT_Lettrage)")
) est_actif: Optional[bool] = Field(None, description="True si actif (CT_Sommeil=0)")
categorie_comptable: Optional[int] = Field( type_facture: Optional[int] = Field(None, description="Type facture 0=Facture, 1=BL (CT_Facture)")
None, description="Catégorie comptable (N_CatCompta)" est_prospect: Optional[bool] = Field(None, description="True si prospect (CT_Prospect=1)")
) bl_en_facture: Optional[int] = Field(None, description="Imprimer BL en facture (CT_BLFact)")
compte_general: Optional[str] = Field( saut_page: Optional[int] = Field(None, description="Saut de page sur documents (CT_Saut)")
None, description="Compte général principal (CG_NumPrinc)" validation_echeance: Optional[int] = Field(None, description="Valider les échéances (CT_ValidEch)")
) controle_encours: Optional[int] = Field(None, description="Contrôler l'encours (CT_ControlEnc)")
exclure_relance: Optional[bool] = Field(None, description="Exclure des relances (CT_NotRappel)")
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)")
lettrage_auto: Optional[bool] = Field( # LOGISTIQUE (4 champs)
None, description="Lettrage automatique (CT_Lettrage)" priorite_livraison: Optional[int] = Field(None, description="Priorité livraison (CT_PrioriteLivr)")
) livraison_partielle: Optional[int] = Field(None, description="Livraison partielle (CT_LivrPartielle)")
type_facture: Optional[int] = Field( delai_transport: Optional[int] = Field(None, description="Délai transport jours (CT_DelaiTransport)")
None, description="Type de facture (0=Facture, 1=BL facturant) (CT_Facture)" delai_appro: Optional[int] = Field(None, description="Délai appro jours (CT_DelaiAppro)")
)
bl_en_facture: Optional[int] = Field(
None, description="Imprimer BL en facture (CT_BLFact)"
)
saut_page: Optional[int] = Field(
None, description="Saut de page sur documents (CT_Saut)"
)
validation_echeance: Optional[int] = Field(
None, description="Valider les échéances (CT_ValidEch)"
)
controle_encours: Optional[int] = Field(
None, description="Contrôler l'encours (CT_ControlEnc)"
)
exclure_relance: Optional[bool] = Field(
None, description="Exclure des relances (CT_NotRappel)"
)
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)"
)
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)"
)
priorite_livraison: Optional[int] = Field( # COMMENTAIRE (1 champ)
None, description="Priorité de livraison (CT_PrioriteLivr)" commentaire: Optional[str] = Field(None, description="Commentaire libre (CT_Commentaire)")
)
livraison_partielle: Optional[int] = Field(
None, description="Autoriser livraison partielle (CT_LivrPartielle)"
)
delai_transport: Optional[int] = Field(
None, description="Délai de transport (jours) (CT_DelaiTransport)"
)
delai_appro: Optional[int] = Field(
None, description="Délai d'approvisionnement (jours) (CT_DelaiAppro)"
)
commentaire: Optional[str] = Field( # ANALYTIQUE (1 champ)
None, description="Commentaire libre (CT_Commentaire)" section_analytique: Optional[str] = Field(None, description="Section analytique (CA_Num)")
)
section_analytique: Optional[str] = Field( # ORGANISATION / SURVEILLANCE (10 champs)
None, description="Section analytique (CA_Num)" 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)")
forme_juridique: Optional[str] = Field(None, description="Forme juridique SA, SARL (CT_SvFormeJuri)")
effectif: Optional[str] = Field(None, description="Nombre d'employés (CT_SvEffectif)")
sv_regularite: Optional[str] = Field(None, description="Régularité paiements (CT_SvRegul)")
sv_cotation: Optional[str] = Field(None, description="Cotation crédit (CT_SvCotation)")
sv_objet_maj: Optional[str] = Field(None, description="Objet dernière MAJ (CT_SvObjetMaj)")
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)")
mode_reglement_code: Optional[int] = Field( # COMPTE GENERAL ET CATEGORIES (3 champs)
None, description="Code mode de règlement (MR_No)" 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)")
surveillance_active: Optional[bool] = Field( categorie_compta: Optional[int] = Field(None, description="Catégorie comptable (N_CatCompta)")
None, description="Surveillance financière active (CT_Surveillance)"
)
coface: Optional[str] = Field(
None, description="Code Coface (25 car.) (CT_Coface)"
)
sv_regularite: Optional[str] = Field(
None, description="Régularité paiements (CT_SvRegul)"
)
sv_cotation: Optional[str] = Field(
None, description="Cotation crédit (CT_SvCotation)"
)
sv_objet_maj: Optional[str] = Field(
None, description="Objet dernière MAJ surveillance (CT_SvObjetMaj)"
)
sv_resultat: Optional[float] = Field(
None, description="Résultat financier (CT_SvResultat)"
)
date_creation: Optional[str] = Field(None, description="Date de création")
date_modification: Optional[str] = Field(
None, description="Date de dernière modification (CT_DateMAJ)"
)
@field_validator("type_tiers", mode="before")
@classmethod
def convertir_type_tiers(cls, v):
if v is None:
return None
if isinstance(v, int):
mapping = {
0: "client",
1: "fournisseur",
2: "prospect",
}
return mapping.get(v)
return v
class Config: class Config:
json_schema_extra = { json_schema_extra = {
"example": { "example": {
"numero": "CLI000001", "numero": "CLI000001",
"intitule": "SARL EXEMPLE", "intitule": "SARL EXEMPLE",
"type_tiers": "client", "type_tiers": 0,
"qualite": "CLI", "qualite": "CLI",
"classement": "A", "classement": "A",
"raccourci": "EXEMPL", "raccourci": "EXEMPL",
"est_entreprise": True, "siret": "12345678901234",
"est_actif": True, "tva_intra": "FR12345678901",
"forme_juridique": "SARL", "code_naf": "6201Z",
"contact": "Jean Dupont", "contact": "Jean Dupont",
"adresse": "123 Rue de la Paix", "adresse": "123 Rue de la Paix",
"complement": "Bâtiment B", "complement": "Bâtiment B",
@ -386,41 +244,63 @@ class ClientDetails(BaseModel):
"region": "Île-de-France", "region": "Île-de-France",
"pays": "France", "pays": "France",
"telephone": "0123456789", "telephone": "0123456789",
"portable": "0612345678", "telecopie": "0123456788",
"email": "contact@exemple.fr", "email": "contact@exemple.fr",
"site_web": "https://www.exemple.fr", "site_web": "https://www.exemple.fr",
"facebook": "https://facebook.com/exemple", "facebook": "https://facebook.com/exemple",
"linkedin": "https://linkedin.com/company/exemple", "linkedin": "https://linkedin.com/company/exemple",
"siret": "12345678901234", "taux01": 0.0,
"siren": "123456789", "taux02": 0.0,
"tva_intra": "FR12345678901", "taux03": 0.0,
"code_naf": "6201Z", "taux04": 0.0,
"secteur": "Informatique", "statistique01": "Informatique",
"effectif": "50-99", "statistique02": "",
"ca_annuel": 2500000.0, "statistique03": "",
"commercial_code": 1, "statistique04": "",
"langue": 0, "statistique05": "",
"categorie_tarifaire": 0, "statistique06": "",
"categorie_comptable": 0, "statistique07": "",
"compte_general": "4110000", "statistique08": "",
"lettrage_auto": True, "statistique09": "",
"type_facture": 1, "statistique10": "",
"controle_encours": 1,
"exclure_relance": False,
"encours_autorise": 50000.0, "encours_autorise": 50000.0,
"assurance_credit": 40000.0, "assurance_credit": 40000.0,
"langue": 0,
"commercial_code": 1,
"lettrage_auto": True,
"est_actif": True,
"type_facture": 1,
"est_prospect": False,
"bl_en_facture": 0,
"saut_page": 0,
"validation_echeance": 0,
"controle_encours": 1,
"exclure_relance": False,
"exclure_penalites": False,
"bon_a_payer": 0,
"priorite_livraison": 1, "priorite_livraison": 1,
"livraison_partielle": 1, "livraison_partielle": 1,
"delai_transport": 2, "delai_transport": 2,
"delai_appro": 0,
"commentaire": "Client important", "commentaire": "Client important",
"section_analytique": "",
"mode_reglement_code": 1, "mode_reglement_code": 1,
"surveillance_active": True, "surveillance_active": True,
"coface": "COF12345", "coface": "COF12345",
"date_creation": "2024-01-15T10:30:00", "forme_juridique": "SARL",
"date_modification": "2024-12-20T14:22:00", "effectif": "50-99",
"sv_regularite": "",
"sv_cotation": "",
"sv_objet_maj": "",
"sv_chiffre_affaires": 2500000.0,
"sv_resultat": 150000.0,
"compte_general": "4110000",
"categorie_tarif": 0,
"categorie_compta": 0,
} }
} }
class ArticleResponse(BaseModel): class ArticleResponse(BaseModel):
""" """
Modèle de réponse pour un article Sage Modèle de réponse pour un article Sage