Added create client logics
This commit is contained in:
parent
cc56821c70
commit
2e96cec20d
2 changed files with 271 additions and 0 deletions
188
main.py
188
main.py
|
|
@ -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
|
||||||
# =====================================================
|
# =====================================================
|
||||||
|
|
|
||||||
|
|
@ -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)}")
|
||||||
Loading…
Reference in a new issue