feat(articles): add enum support and field normalization for article schema
This commit is contained in:
parent
bd432a15b6
commit
1d4ea92e86
3 changed files with 253 additions and 126 deletions
|
|
@ -2,6 +2,9 @@ from pydantic import BaseModel, Field, validator, field_validator
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from datetime import date, datetime
|
from datetime import date, datetime
|
||||||
|
|
||||||
|
from utils import NomenclatureType, SuiviStockType, TypeArticle
|
||||||
|
from utils.enums import normalize_enum_to_int, normalize_string_field
|
||||||
|
|
||||||
|
|
||||||
class EmplacementStockModel(BaseModel):
|
class EmplacementStockModel(BaseModel):
|
||||||
"""Détail du stock dans un emplacement spécifique"""
|
"""Détail du stock dans un emplacement spécifique"""
|
||||||
|
|
@ -419,18 +422,28 @@ class ArticleResponse(BaseModel):
|
||||||
None, description="Stock disponible = réel - réservé"
|
None, description="Stock disponible = réel - réservé"
|
||||||
)
|
)
|
||||||
|
|
||||||
emplacements: List[EmplacementStockModel] = Field(
|
emplacements: List[dict] = Field(
|
||||||
default_factory=list,
|
default_factory=list, description="Détail du stock par emplacement"
|
||||||
description="Détail du stock par emplacement (F_ARTSTOCKEMPL + F_DEPOT + F_DEPOTEMPL)",
|
|
||||||
)
|
)
|
||||||
nb_emplacements: int = Field(0, description="Nombre d'emplacements")
|
nb_emplacements: int = Field(0, description="Nombre d'emplacements")
|
||||||
|
|
||||||
suivi_stock: Optional[bool] = Field(
|
# Champs énumérés normalisés
|
||||||
None, description="Suivi de stock activé (AR_SuiviStock)"
|
suivi_stock: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
description="Type de suivi de stock (AR_SuiviStock): 0=Aucun, 1=CMUP, 2=FIFO/LIFO, 3=Sérialisé",
|
||||||
)
|
)
|
||||||
nomenclature: Optional[bool] = Field(
|
suivi_stock_libelle: Optional[str] = Field(
|
||||||
None, description="Article avec nomenclature (AR_Nomencl)"
|
None, description="Libellé du type de suivi de stock"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
nomenclature: Optional[int] = Field(
|
||||||
|
None,
|
||||||
|
description="Type de nomenclature (AR_Nomencl): 0=Non, 1=Fabrication, 2=Commerciale",
|
||||||
|
)
|
||||||
|
nomenclature_libelle: Optional[str] = Field(
|
||||||
|
None, description="Libellé du type de nomenclature"
|
||||||
|
)
|
||||||
|
|
||||||
qte_composant: Optional[float] = Field(
|
qte_composant: Optional[float] = Field(
|
||||||
None, description="Quantité de composant (AR_QteComp)"
|
None, description="Quantité de composant (AR_QteComp)"
|
||||||
)
|
)
|
||||||
|
|
@ -454,52 +467,44 @@ class ArticleResponse(BaseModel):
|
||||||
gamme_1: Optional[str] = Field(None, description="Énumération gamme 1 (AR_Gamme1)")
|
gamme_1: Optional[str] = Field(None, description="Énumération gamme 1 (AR_Gamme1)")
|
||||||
gamme_2: Optional[str] = Field(None, description="Énumération gamme 2 (AR_Gamme2)")
|
gamme_2: Optional[str] = Field(None, description="Énumération gamme 2 (AR_Gamme2)")
|
||||||
|
|
||||||
gammes: List[GammeArticleModel] = Field(
|
gammes: List[dict] = Field(default_factory=list, description="Détail des gammes")
|
||||||
default_factory=list,
|
|
||||||
description="Détail des gammes (F_ARTGAMME + F_ENUMGAMME + P_GAMME)",
|
|
||||||
)
|
|
||||||
nb_gammes: int = Field(0, description="Nombre de gammes")
|
nb_gammes: int = Field(0, description="Nombre de gammes")
|
||||||
|
|
||||||
tarifs_clients: List[TarifClientModel] = Field(
|
tarifs_clients: List[dict] = Field(
|
||||||
default_factory=list,
|
default_factory=list, description="Tarifs spécifiques par client/catégorie"
|
||||||
description="Tarifs spécifiques par client/catégorie (F_ARTCLIENT)",
|
|
||||||
)
|
)
|
||||||
nb_tarifs_clients: int = Field(0, description="Nombre de tarifs clients")
|
nb_tarifs_clients: int = Field(0, description="Nombre de tarifs clients")
|
||||||
|
|
||||||
composants: List[ComposantModel] = Field(
|
composants: List[dict] = Field(
|
||||||
default_factory=list,
|
default_factory=list, description="Composants/Opérations de production"
|
||||||
description="Composants/Opérations de production (F_ARTCOMPO)",
|
|
||||||
)
|
)
|
||||||
nb_composants: int = Field(0, description="Nombre de composants")
|
nb_composants: int = Field(0, description="Nombre de composants")
|
||||||
|
|
||||||
compta_vente: List[ComptaArticleModel] = Field(
|
compta_vente: List[dict] = Field(
|
||||||
default_factory=list, description="Comptabilité vente (F_ARTCOMPTA type 0)"
|
default_factory=list, description="Comptabilité vente"
|
||||||
)
|
)
|
||||||
compta_achat: List[ComptaArticleModel] = Field(
|
compta_achat: List[dict] = Field(
|
||||||
default_factory=list, description="Comptabilité achat (F_ARTCOMPTA type 1)"
|
default_factory=list, description="Comptabilité achat"
|
||||||
)
|
)
|
||||||
compta_stock: List[ComptaArticleModel] = Field(
|
compta_stock: List[dict] = Field(
|
||||||
default_factory=list, description="Comptabilité stock (F_ARTCOMPTA type 2)"
|
default_factory=list, description="Comptabilité stock"
|
||||||
)
|
)
|
||||||
|
|
||||||
fournisseurs: List[FournisseurArticleModel] = Field(
|
fournisseurs: List[dict] = Field(
|
||||||
default_factory=list,
|
default_factory=list, description="Tous les fournisseurs de l'article"
|
||||||
description="Tous les fournisseurs de l'article (F_ARTFOURNISS)",
|
|
||||||
)
|
)
|
||||||
nb_fournisseurs: int = Field(0, description="Nombre de fournisseurs")
|
nb_fournisseurs: int = Field(0, description="Nombre de fournisseurs")
|
||||||
|
|
||||||
refs_enumerees: List[ReferenceEnumereeModel] = Field(
|
refs_enumerees: List[dict] = Field(
|
||||||
default_factory=list, description="Références énumérées (F_ARTENUMREF)"
|
default_factory=list, description="Références énumérées"
|
||||||
)
|
)
|
||||||
nb_refs_enumerees: int = Field(0, description="Nombre de références énumérées")
|
nb_refs_enumerees: int = Field(0, description="Nombre de références énumérées")
|
||||||
|
|
||||||
medias: List[MediaArticleModel] = Field(
|
medias: List[dict] = Field(default_factory=list, description="Médias attachés")
|
||||||
default_factory=list, description="Médias attachés (F_ARTICLEMEDIA)"
|
|
||||||
)
|
|
||||||
nb_medias: int = Field(0, description="Nombre de médias")
|
nb_medias: int = Field(0, description="Nombre de médias")
|
||||||
|
|
||||||
prix_gammes: List[PrixGammeModel] = Field(
|
prix_gammes: List[dict] = Field(
|
||||||
default_factory=list, description="Prix par combinaison de gammes (F_ARTPRIX)"
|
default_factory=list, description="Prix par combinaison de gammes"
|
||||||
)
|
)
|
||||||
nb_prix_gammes: int = Field(0, description="Nombre de prix par gammes")
|
nb_prix_gammes: int = Field(0, description="Nombre de prix par gammes")
|
||||||
|
|
||||||
|
|
@ -516,51 +521,35 @@ class ArticleResponse(BaseModel):
|
||||||
famille_code: Optional[str] = Field(
|
famille_code: Optional[str] = Field(
|
||||||
None, max_length=20, description="Code famille (FA_CodeFamille)"
|
None, max_length=20, description="Code famille (FA_CodeFamille)"
|
||||||
)
|
)
|
||||||
famille_libelle: Optional[str] = Field(
|
famille_libelle: Optional[str] = Field(None, description="Libellé de la famille")
|
||||||
None, description="Libellé de la famille (F_FAMILLE.FA_Intitule)"
|
|
||||||
)
|
|
||||||
famille_type: Optional[int] = Field(
|
famille_type: Optional[int] = Field(
|
||||||
None, description="Type de famille : 0=Détail, 1=Total (F_FAMILLE.FA_Type)"
|
None, description="Type de famille : 0=Détail, 1=Total"
|
||||||
)
|
)
|
||||||
famille_unite_vente: Optional[str] = Field(
|
famille_unite_vente: Optional[str] = Field(
|
||||||
None, description="Unité de vente de la famille (F_FAMILLE.FA_UniteVen)"
|
None, description="Unité de vente de la famille"
|
||||||
)
|
|
||||||
famille_coef: Optional[float] = Field(
|
|
||||||
None, description="Coefficient de la famille (F_FAMILLE.FA_Coef)"
|
|
||||||
)
|
)
|
||||||
|
famille_coef: Optional[float] = Field(None, description="Coefficient de la famille")
|
||||||
famille_suivi_stock: Optional[bool] = Field(
|
famille_suivi_stock: Optional[bool] = Field(
|
||||||
None, description="Suivi stock de la famille (F_FAMILLE.FA_SuiviStock)"
|
None, description="Suivi stock de la famille"
|
||||||
)
|
|
||||||
famille_garantie: Optional[int] = Field(
|
|
||||||
None, description="Garantie de la famille (F_FAMILLE.FA_Garantie)"
|
|
||||||
)
|
)
|
||||||
|
famille_garantie: Optional[int] = Field(None, description="Garantie de la famille")
|
||||||
famille_unite_poids: Optional[str] = Field(
|
famille_unite_poids: Optional[str] = Field(
|
||||||
None, description="Unité de poids de la famille (F_FAMILLE.FA_UnitePoids)"
|
None, description="Unité de poids de la famille"
|
||||||
)
|
|
||||||
famille_delai: Optional[int] = Field(
|
|
||||||
None, description="Délai de la famille (F_FAMILLE.FA_Delai)"
|
|
||||||
)
|
)
|
||||||
|
famille_delai: Optional[int] = Field(None, description="Délai de la famille")
|
||||||
famille_nb_colis: Optional[int] = Field(
|
famille_nb_colis: Optional[int] = Field(
|
||||||
None, description="Nombre de colis de la famille (F_FAMILLE.FA_NbColis)"
|
None, description="Nombre de colis de la famille"
|
||||||
)
|
)
|
||||||
famille_code_fiscal: Optional[str] = Field(
|
famille_code_fiscal: Optional[str] = Field(
|
||||||
None, description="Code fiscal de la famille (F_FAMILLE.FA_CodeFiscal)"
|
None, description="Code fiscal de la famille"
|
||||||
)
|
|
||||||
famille_escompte: Optional[bool] = Field(
|
|
||||||
None, description="Escompte de la famille (F_FAMILLE.FA_Escompte)"
|
|
||||||
)
|
|
||||||
famille_centrale: Optional[bool] = Field(
|
|
||||||
None, description="Famille centrale (F_FAMILLE.FA_Central)"
|
|
||||||
)
|
|
||||||
famille_nature: Optional[int] = Field(
|
|
||||||
None, description="Nature de la famille (F_FAMILLE.FA_Nature)"
|
|
||||||
)
|
)
|
||||||
|
famille_escompte: Optional[bool] = Field(None, description="Escompte de la famille")
|
||||||
|
famille_centrale: Optional[bool] = Field(None, description="Famille centrale")
|
||||||
|
famille_nature: Optional[int] = Field(None, description="Nature de la famille")
|
||||||
famille_hors_stat: Optional[bool] = Field(
|
famille_hors_stat: Optional[bool] = Field(
|
||||||
None, description="Hors statistique famille (F_FAMILLE.FA_HorsStat)"
|
None, description="Hors statistique famille"
|
||||||
)
|
|
||||||
famille_pays: Optional[str] = Field(
|
|
||||||
None, description="Pays de la famille (F_FAMILLE.FA_Pays)"
|
|
||||||
)
|
)
|
||||||
|
famille_pays: Optional[str] = Field(None, description="Pays de la famille")
|
||||||
|
|
||||||
nature: Optional[int] = Field(None, description="Nature de l'article (AR_Nature)")
|
nature: Optional[int] = Field(None, description="Nature de l'article (AR_Nature)")
|
||||||
garantie: Optional[int] = Field(
|
garantie: Optional[int] = Field(
|
||||||
|
|
@ -572,21 +561,20 @@ class ArticleResponse(BaseModel):
|
||||||
pays: Optional[str] = Field(None, description="Pays d'origine (AR_Pays)")
|
pays: Optional[str] = Field(None, description="Pays d'origine (AR_Pays)")
|
||||||
|
|
||||||
fournisseur_principal: Optional[int] = Field(
|
fournisseur_principal: Optional[int] = Field(
|
||||||
None,
|
None, description="N° compte du fournisseur principal"
|
||||||
description="N° compte du fournisseur principal (CO_No → F_COMPTET.CT_Num)",
|
|
||||||
)
|
)
|
||||||
fournisseur_nom: Optional[str] = Field(
|
fournisseur_nom: Optional[str] = Field(
|
||||||
None, description="Nom du fournisseur principal (F_COMPTET.CT_Intitule)"
|
None, description="Nom du fournisseur principal"
|
||||||
)
|
)
|
||||||
|
|
||||||
conditionnement: Optional[str] = Field(
|
conditionnement: Optional[str] = Field(
|
||||||
None, description="Conditionnement d'achat (AR_Condition)"
|
None, description="Conditionnement d'achat (AR_Condition)"
|
||||||
)
|
)
|
||||||
conditionnement_qte: Optional[float] = Field(
|
conditionnement_qte: Optional[float] = Field(
|
||||||
None, description="Quantité conditionnement (F_ENUMCOND.EC_Quantite)"
|
None, description="Quantité conditionnement"
|
||||||
)
|
)
|
||||||
conditionnement_edi: Optional[str] = Field(
|
conditionnement_edi: Optional[str] = Field(
|
||||||
None, description="Code EDI conditionnement (F_ENUMCOND.EC_EdiCode)"
|
None, description="Code EDI conditionnement"
|
||||||
)
|
)
|
||||||
|
|
||||||
nb_colis: Optional[int] = Field(
|
nb_colis: Optional[int] = Field(
|
||||||
|
|
@ -669,13 +657,13 @@ class ArticleResponse(BaseModel):
|
||||||
langue_2: Optional[str] = Field(None, description="Texte en langue 2 (AR_Langue2)")
|
langue_2: Optional[str] = Field(None, description="Texte en langue 2 (AR_Langue2)")
|
||||||
|
|
||||||
frais_01_denomination: Optional[str] = Field(
|
frais_01_denomination: Optional[str] = Field(
|
||||||
None, description="Dénomination frais 1 (AR_Frais01FR_Denomination)"
|
None, description="Dénomination frais 1"
|
||||||
)
|
)
|
||||||
frais_02_denomination: Optional[str] = Field(
|
frais_02_denomination: Optional[str] = Field(
|
||||||
None, description="Dénomination frais 2 (AR_Frais02FR_Denomination)"
|
None, description="Dénomination frais 2"
|
||||||
)
|
)
|
||||||
frais_03_denomination: Optional[str] = Field(
|
frais_03_denomination: Optional[str] = Field(
|
||||||
None, description="Dénomination frais 3 (AR_Frais03FR_Denomination)"
|
None, description="Dénomination frais 3"
|
||||||
)
|
)
|
||||||
|
|
||||||
tva_code: Optional[str] = Field(None, description="Code TVA (F_TAXE.TA_Code)")
|
tva_code: Optional[str] = Field(None, description="Code TVA (F_TAXE.TA_Code)")
|
||||||
|
|
@ -706,40 +694,54 @@ class ArticleResponse(BaseModel):
|
||||||
None, description="Date de dernière modification (AR_DateModif)"
|
None, description="Date de dernière modification (AR_DateModif)"
|
||||||
)
|
)
|
||||||
|
|
||||||
marque_commerciale: Optional[str] = Field(
|
marque_commerciale: Optional[str] = Field(None, description="Marque commerciale")
|
||||||
None, description="Marque commerciale (champ personnalisé)"
|
|
||||||
)
|
|
||||||
objectif_qtes_vendues: Optional[str] = Field(
|
objectif_qtes_vendues: Optional[str] = Field(
|
||||||
None, description="Objectif / Quantités vendues (champ personnalisé)"
|
None, description="Objectif / Quantités vendues"
|
||||||
)
|
|
||||||
pourcentage_or: Optional[str] = Field(
|
|
||||||
None, description="Pourcentage teneur en or (champ personnalisé)"
|
|
||||||
)
|
)
|
||||||
|
pourcentage_or: Optional[str] = Field(None, description="Pourcentage teneur en or")
|
||||||
premiere_commercialisation: Optional[str] = Field(
|
premiere_commercialisation: Optional[str] = Field(
|
||||||
None, description="Date de 1ère commercialisation (champ personnalisé)"
|
None, description="Date de 1ère commercialisation"
|
||||||
)
|
)
|
||||||
interdire_commande: Optional[bool] = Field(
|
interdire_commande: Optional[bool] = Field(
|
||||||
None, description="Interdire la commande (champ personnalisé)"
|
None, description="Interdire la commande"
|
||||||
)
|
)
|
||||||
exclure: Optional[bool] = Field(
|
exclure: Optional[bool] = Field(None, description="Exclure de certains traitements")
|
||||||
None, description="Exclure de certains traitements (champ personnalisé)"
|
|
||||||
|
# ===== VALIDATEURS =====
|
||||||
|
|
||||||
|
@field_validator(
|
||||||
|
"unite_vente",
|
||||||
|
"unite_poids",
|
||||||
|
"gamme_1",
|
||||||
|
"gamme_2",
|
||||||
|
"conditionnement",
|
||||||
|
"code_fiscal",
|
||||||
|
"pays",
|
||||||
|
"article_substitut",
|
||||||
|
"reprise_code_defaut",
|
||||||
|
mode="before",
|
||||||
)
|
)
|
||||||
|
|
||||||
@field_validator('unite_vente', 'unite_poids', 'gamme_1', 'gamme_2', 'conditionnement', mode='before')
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert_int_to_str(cls, v):
|
def convert_string_fields(cls, v):
|
||||||
if v is None:
|
"""Convertit les champs string qui peuvent venir comme int depuis la DB"""
|
||||||
return None
|
return normalize_string_field(v)
|
||||||
if v == 0:
|
|
||||||
return ""
|
|
||||||
return str(v)
|
|
||||||
|
|
||||||
@field_validator('suivi_stock', mode='before')
|
@field_validator("suivi_stock", "nomenclature", mode="before")
|
||||||
@classmethod
|
@classmethod
|
||||||
def convert_int_to_bool(cls, v):
|
def convert_enum_fields(cls, v):
|
||||||
if v is None:
|
"""Convertit les champs énumérés en int"""
|
||||||
return None
|
return normalize_enum_to_int(v)
|
||||||
return bool(v)
|
|
||||||
|
def model_post_init(self, __context):
|
||||||
|
"""Génère automatiquement les libellés après l'initialisation"""
|
||||||
|
if self.suivi_stock is not None:
|
||||||
|
self.suivi_stock_libelle = SuiviStockType.get_label(self.suivi_stock)
|
||||||
|
|
||||||
|
if self.nomenclature is not None:
|
||||||
|
self.nomenclature_libelle = NomenclatureType.get_label(self.nomenclature)
|
||||||
|
|
||||||
|
if self.type_article is not None:
|
||||||
|
self.type_article_libelle = TypeArticle.get_label(self.type_article)
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
json_schema_extra = {
|
json_schema_extra = {
|
||||||
|
|
@ -748,23 +750,10 @@ class ArticleResponse(BaseModel):
|
||||||
"designation": "Bague Or 18K Diamant",
|
"designation": "Bague Or 18K Diamant",
|
||||||
"prix_vente": 1299.00,
|
"prix_vente": 1299.00,
|
||||||
"stock_reel": 15.0,
|
"stock_reel": 15.0,
|
||||||
"stock_disponible": 13.0,
|
"suivi_stock": 1,
|
||||||
"nb_emplacements": 2,
|
"suivi_stock_libelle": "CMUP",
|
||||||
"nb_gammes": 2,
|
"nomenclature": 0,
|
||||||
"nb_tarifs_clients": 3,
|
"nomenclature_libelle": "Non",
|
||||||
"nb_fournisseurs": 2,
|
|
||||||
"nb_medias": 2,
|
|
||||||
"emplacements": [
|
|
||||||
{
|
|
||||||
"depot": "01",
|
|
||||||
"emplacement": "A1-01",
|
|
||||||
"qte_stockee": 10.0,
|
|
||||||
"depot_nom": "Dépôt principal",
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"gammes": [
|
|
||||||
{"numero_gamme": 1, "enumere": "001", "gamme_nom": "Taille"}
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -785,18 +774,6 @@ class ArticleListResponse(BaseModel):
|
||||||
False, description="Indique si tous les enrichissements sont activés"
|
False, description="Indique si tous les enrichissements sont activés"
|
||||||
)
|
)
|
||||||
|
|
||||||
class Config:
|
|
||||||
json_schema_extra = {
|
|
||||||
"example": {
|
|
||||||
"total": 1250,
|
|
||||||
"filtre_applique": "bague",
|
|
||||||
"avec_stock": True,
|
|
||||||
"avec_famille": True,
|
|
||||||
"avec_enrichissements_complets": True,
|
|
||||||
"articles": [],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class ArticleCreateRequest(BaseModel):
|
class ArticleCreateRequest(BaseModel):
|
||||||
"""Schéma pour création d'article"""
|
"""Schéma pour création d'article"""
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
from enums import (
|
||||||
|
TypeArticle,
|
||||||
|
TypeCompta,
|
||||||
|
TypeRessource,
|
||||||
|
TypeTiers,
|
||||||
|
TypeEmplacement,
|
||||||
|
TypeFamille,
|
||||||
|
NomenclatureType,
|
||||||
|
SuiviStockType,
|
||||||
|
)
|
||||||
|
|
||||||
|
__all__ = [
|
||||||
|
"TypeArticle",
|
||||||
|
"TypeCompta",
|
||||||
|
"TypeRessource",
|
||||||
|
"TypeTiers",
|
||||||
|
"TypeEmplacement",
|
||||||
|
"TypeFamille",
|
||||||
|
"NomenclatureType",
|
||||||
|
"SuiviStockType",
|
||||||
|
]
|
||||||
129
utils/enums.py
Normal file
129
utils/enums.py
Normal file
|
|
@ -0,0 +1,129 @@
|
||||||
|
from enum import IntEnum
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
|
class SuiviStockType(IntEnum):
|
||||||
|
AUCUN = 0
|
||||||
|
CMUP = 1
|
||||||
|
FIFO_LIFO = 2
|
||||||
|
SERIALISE = 3
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {0: "Aucun", 1: "CMUP", 2: "FIFO/LIFO", 3: "Sérialisé"}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
class NomenclatureType(IntEnum):
|
||||||
|
NON = 0
|
||||||
|
FABRICATION = 1
|
||||||
|
COMMERCIALE = 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {0: "Non", 1: "Fabrication", 2: "Commerciale/Composé"}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
class TypeArticle(IntEnum):
|
||||||
|
ARTICLE = 0
|
||||||
|
PRESTATION = 1
|
||||||
|
DIVERS = 2
|
||||||
|
NOMENCLATURE = 3
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {
|
||||||
|
0: "Article",
|
||||||
|
1: "Prestation de service",
|
||||||
|
2: "Divers / Frais",
|
||||||
|
3: "Nomenclature",
|
||||||
|
}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
class TypeFamille(IntEnum):
|
||||||
|
DETAIL = 0
|
||||||
|
TOTAL = 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {0: "Détail", 1: "Total"}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
class TypeCompta(IntEnum):
|
||||||
|
VENTE = 0
|
||||||
|
ACHAT = 1
|
||||||
|
STOCK = 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {0: "Vente", 1: "Achat", 2: "Stock"}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
class TypeRessource(IntEnum):
|
||||||
|
MAIN_OEUVRE = 0
|
||||||
|
MACHINE = 1
|
||||||
|
SOUS_TRAITANCE = 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {0: "Main d'œuvre", 1: "Machine", 2: "Sous-traitance"}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
class TypeTiers(IntEnum):
|
||||||
|
CLIENT = 0
|
||||||
|
FOURNISSEUR = 1
|
||||||
|
SALARIE = 2
|
||||||
|
AUTRE = 3
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {0: "Client", 1: "Fournisseur", 2: "Salarié", 3: "Autre"}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
class TypeEmplacement(IntEnum):
|
||||||
|
NORMAL = 0
|
||||||
|
QUARANTAINE = 1
|
||||||
|
REBUT = 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_label(cls, value: Optional[int]) -> Optional[str]:
|
||||||
|
labels = {0: "Normal", 1: "Quarantaine", 2: "Rebut"}
|
||||||
|
return labels.get(value) if value is not None else None
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_enum_to_string(value, default="0") -> Optional[str]:
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
if value == 0:
|
||||||
|
return None
|
||||||
|
return str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_enum_to_int(value, default=0) -> Optional[int]:
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return int(value)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
return default
|
||||||
|
|
||||||
|
|
||||||
|
def normalize_string_field(value) -> Optional[str]:
|
||||||
|
if value is None:
|
||||||
|
return None
|
||||||
|
if isinstance(value, int):
|
||||||
|
if value == 0:
|
||||||
|
return None
|
||||||
|
return str(value)
|
||||||
|
if isinstance(value, str):
|
||||||
|
stripped = value.strip()
|
||||||
|
if stripped in ("", "0"):
|
||||||
|
return None
|
||||||
|
return stripped
|
||||||
|
return str(value)
|
||||||
Loading…
Reference in a new issue