Added create client logics

This commit is contained in:
Fanilo-Nantenaina 2025-12-05 19:12:45 +03:00
parent cc56821c70
commit 2e96cec20d
2 changed files with 271 additions and 0 deletions

188
main.py
View file

@ -76,6 +76,19 @@ class StatutRequest(BaseModel):
nouveau_statut: int nouveau_statut: int
class ClientCreateRequest(BaseModel):
intitule: str = Field(..., description="Nom du client (CT_Intitule)")
compte_collectif: str = Field("411000", description="Compte général rattaché")
num: Optional[str] = Field(None, description="Laisser vide pour numérotation auto")
adresse: Optional[str] = None
code_postal: Optional[str] = None
ville: Optional[str] = None
pays: Optional[str] = None
email: Optional[str] = None
telephone: Optional[str] = None
siret: Optional[str] = None
tva_intra: Optional[str] = None
# ===================================================== # =====================================================
# SÉCURITÉ # SÉCURITÉ
# ===================================================== # =====================================================
@ -185,6 +198,20 @@ def client_get(req: CodeRequest):
raise HTTPException(500, str(e)) raise HTTPException(500, str(e))
@app.post("/sage/clients/create", dependencies=[Depends(verify_token)])
def create_client_endpoint(req: ClientCreateRequest):
"""Création d'un client dans Sage"""
try:
# Transformation du modèle Pydantic en dict pour le connecteur
resultat = sage.creer_client(req.dict())
return {"success": True, "data": resultat}
except ValueError as e:
logger.warning(f"Erreur métier création client: {e}")
raise HTTPException(400, str(e))
except Exception as e:
logger.error(f"Erreur technique création client: {e}")
raise HTTPException(500, str(e))
# ===================================================== # =====================================================
# ENDPOINTS - ARTICLES # ENDPOINTS - ARTICLES
# ===================================================== # =====================================================
@ -2566,7 +2593,168 @@ def livraison_get(req: CodeRequest):
logger.error(f"Erreur lecture livraison: {e}") logger.error(f"Erreur lecture livraison: {e}")
raise HTTPException(500, str(e)) raise HTTPException(500, str(e))
# À ajouter dans main.py (Windows Gateway)
@app.get("/sage/diagnostic/fournisseurs-detection", dependencies=[Depends(verify_token)])
def diagnostiquer_detection_fournisseurs():
"""
🔍 DIAGNOSTIC : Découvre comment identifier les fournisseurs dans votre Sage
Teste plusieurs méthodes :
- CT_Type = 1 (méthode classique)
- CT_Qualite (méthode moderne : 0=Aucune, 1=Client, 2=Fournisseur, 3=Client+Fournisseur)
- CT_TypeTiers
- Présence dans FactoryFournisseur
"""
try:
if not sage or not sage.cial:
raise HTTPException(503, "Service Sage indisponible")
with sage._com_context(), sage._lock_com:
factory_client = sage.cial.CptaApplication.FactoryClient
resultats = {
"methodes_detectees": [],
"tiers_analyses": [],
"recommandation": None
}
# Scanner les 50 premiers tiers
index = 1
while index <= 50:
try:
persist = factory_client.List(index)
if persist is None:
break
tiers = sage._cast_client(persist)
if not tiers:
index += 1
continue
analyse = {
"index": index,
"numero": getattr(tiers, "CT_Num", ""),
"intitule": getattr(tiers, "CT_Intitule", ""),
"ct_type": getattr(tiers, "CT_Type", None),
"ct_prospect": getattr(tiers, "CT_Prospect", None),
"methodes_identifiees": []
}
# Méthode 1 : CT_Qualite (la plus courante aujourd'hui)
try:
qualite = getattr(tiers, "CT_Qualite", None)
if qualite is not None:
analyse["ct_qualite"] = qualite
analyse["ct_qualite_libelle"] = {
0: "Aucune",
1: "Client uniquement",
2: "Fournisseur uniquement",
3: "Client ET Fournisseur"
}.get(qualite, f"Inconnu ({qualite})")
if qualite in [2, 3]:
analyse["methodes_identifiees"].append("CT_Qualite (2 ou 3)")
except:
pass
# Méthode 2 : CT_TypeTiers
try:
type_tiers = getattr(tiers, "CT_TypeTiers", None)
if type_tiers is not None:
analyse["ct_type_tiers"] = type_tiers
except:
pass
# Méthode 3 : Vérifier si accessible via FactoryFournisseur
try:
factory_fourn = sage.cial.CptaApplication.FactoryFournisseur
persist_fourn = factory_fourn.ReadNumero(analyse["numero"])
if persist_fourn:
analyse["methodes_identifiees"].append("FactoryFournisseur.ReadNumero()")
analyse["accessible_via_factory_fournisseur"] = True
except:
analyse["accessible_via_factory_fournisseur"] = False
# Méthode 4 : CT_Type = 1 (ancienne méthode)
if analyse["ct_type"] == 1:
analyse["methodes_identifiees"].append("CT_Type = 1")
resultats["tiers_analyses"].append(analyse)
index += 1
except Exception as e:
logger.debug(f"Erreur analyse tiers {index}: {e}")
index += 1
# Analyser les méthodes détectées
fournisseurs_via_qualite = [
t for t in resultats["tiers_analyses"]
if t.get("ct_qualite") in [2, 3]
]
fournisseurs_via_type = [
t for t in resultats["tiers_analyses"]
if t.get("ct_type") == 1
]
fournisseurs_via_factory = [
t for t in resultats["tiers_analyses"]
if t.get("accessible_via_factory_fournisseur") == True
]
resultats["statistiques"] = {
"total_tiers_scannes": len(resultats["tiers_analyses"]),
"fournisseurs_via_ct_qualite": len(fournisseurs_via_qualite),
"fournisseurs_via_ct_type": len(fournisseurs_via_type),
"fournisseurs_via_factory": len(fournisseurs_via_factory)
}
# Exemples de fournisseurs détectés
if fournisseurs_via_qualite:
resultats["exemples_fournisseurs_qualite"] = fournisseurs_via_qualite[:5]
if fournisseurs_via_factory:
resultats["exemples_fournisseurs_factory"] = fournisseurs_via_factory[:5]
# Recommandation
if fournisseurs_via_qualite:
resultats["recommandation"] = {
"methode": "CT_Qualite",
"condition": "CT_Qualite IN (2, 3)",
"description": "Votre Sage utilise le champ CT_Qualite pour distinguer clients/fournisseurs"
}
elif fournisseurs_via_factory:
resultats["recommandation"] = {
"methode": "FactoryFournisseur",
"condition": "Accessible via FactoryFournisseur.ReadNumero()",
"description": "Utilisez FactoryFournisseur au lieu de FactoryClient"
}
elif fournisseurs_via_type:
resultats["recommandation"] = {
"methode": "CT_Type",
"condition": "CT_Type = 1",
"description": "Méthode classique (rare aujourd'hui)"
}
else:
resultats["recommandation"] = {
"methode": "AUCUNE",
"description": "Aucun fournisseur détecté dans les 50 premiers tiers",
"suggestion": "Vérifiez si des fournisseurs existent dans Sage, ou augmentez le scan"
}
logger.info(f"[DIAG] Fournisseurs détectés: {resultats['statistiques']}")
return {
"success": True,
"diagnostic": resultats
}
except Exception as e:
logger.error(f"[DIAG] Erreur diagnostic fournisseurs: {e}", exc_info=True)
raise HTTPException(500, str(e))
# ===================================================== # =====================================================
# LANCEMENT # LANCEMENT
# ===================================================== # =====================================================

View file

@ -2370,3 +2370,86 @@ class SageConnector:
except Exception as e: except Exception as e:
logger.error(f"❌ Erreur lecture livraison {numero}: {e}") logger.error(f"❌ Erreur lecture livraison {numero}: {e}")
return None return None
# =========================================================================
# CREATION CLIENT (US-A8 ?)
# =========================================================================
def creer_client(self, client_data: Dict) -> Dict:
"""
Crée un nouveau client dans Sage via CptaApplication.FactoryClient
"""
if not self.cial:
raise RuntimeError("Connexion Sage non établie")
try:
with self._com_context(), self._lock_com:
# 1. Accès à la Factory Client (Module Comptabilité)
factory_client = self.cial.CptaApplication.FactoryClient
# 2. Création de l'objet en mémoire
client = factory_client.Create() # Ou CreateNew() selon version, Create() est plus standard
# 3. Remplissage des Champs OBLIGATOIRES
# Si 'num' est fourni, on l'utilise, sinon Sage utilisera la souche par défaut
if client_data.get("num"):
client.CT_Num = client_data["num"]
client.CT_Intitule = client_data["intitule"]
client.CT_Type = 0 # 0 = Client
# Compte Collectif (Obligatoire, ex: 411000)
if client_data.get("compte_collectif"):
client.CT_CompteA = client_data["compte_collectif"]
# 4. Remplissage des Champs OPTIONNELS
# --- Adresse principale ---
try:
client.Adresse.Adresse = client_data.get("adresse", "")
client.Adresse.CodePostal = client_data.get("code_postal", "")
client.Adresse.Ville = client_data.get("ville", "")
client.Adresse.Pays = client_data.get("pays", "")
except Exception as e:
logger.warning(f"Erreur remplissage adresse: {e}")
# --- Contact / Télécom ---
try:
client.Telecom.Telephone = client_data.get("telephone", "")
client.Telecom.EMail = client_data.get("email", "")
except Exception as e:
logger.warning(f"Erreur remplissage telecom: {e}")
# --- Identifiants ---
if client_data.get("siret"):
try: client.CT_Siret = client_data["siret"]
except: pass
if client_data.get("tva_intra"):
try: client.CT_Identifiant = client_data["tva_intra"]
except: pass
# 5. Écriture en base
client.Write()
# Récupération du numéro généré (surtout si auto-incrément)
num_final = client.CT_Num
# Mise à jour du cache local immédiate pour qu'il soit trouvable tout de suite
with self._lock_clients:
self._cache_clients.append(self._extraire_client(client))
self._cache_clients_dict[num_final] = self._extraire_client(client)
logger.info(f"✅ Client créé avec succès : {num_final} - {client.CT_Intitule}")
return {
"numero": num_final,
"intitule": client.CT_Intitule,
"compte_collectif": getattr(client, "CT_CompteA", "")
}
except Exception as e:
logger.error(f"❌ Erreur création client : {e}", exc_info=True)
# Gestion d'erreur spécifique pour les doublons
if "doublon" in str(e).lower() or "existe déjà" in str(e).lower():
raise ValueError(f"Le client ou le numéro existe déjà.")
raise RuntimeError(f"Erreur technique Sage: {str(e)}")