Simple cleaning of some files
This commit is contained in:
parent
fd60bd3bc7
commit
9ffad8287d
11 changed files with 44 additions and 164 deletions
|
|
@ -1,14 +1,9 @@
|
||||||
# ============================================================================
|
|
||||||
# SAGE 100 CLOUD - CONNEXION BOI/COM
|
|
||||||
# ============================================================================
|
|
||||||
CHEMIN_BASE=<CHEMIN_VERS_LE_FICHIER_GCM>
|
CHEMIN_BASE=<CHEMIN_VERS_LE_FICHIER_GCM>
|
||||||
UTILISATEUR=<UTILISATEUR_SAGE100>
|
UTILISATEUR=<UTILISATEUR_SAGE100>
|
||||||
MOT_DE_PASSE=<MOT_DE_PASSE_SAGE100>
|
MOT_DE_PASSE=<MOT_DE_PASSE_SAGE100>
|
||||||
|
|
||||||
SAGE_GATEWAY_TOKEN=<TOKEN_SAGE_GATEWAY>
|
SAGE_GATEWAY_TOKEN=<TOKEN_SAGE_GATEWAY>
|
||||||
|
|
||||||
# ============================================================================
|
|
||||||
# API - CONFIGURATION SERVEUR
|
|
||||||
# ============================================================================
|
|
||||||
API_HOST=0.0.0.0
|
API_HOST=0.0.0.0
|
||||||
API_PORT=8000
|
API_PORT=8000
|
||||||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -1,7 +1,3 @@
|
||||||
# ================================
|
|
||||||
# Python / FastAPI
|
|
||||||
# ================================
|
|
||||||
|
|
||||||
# Environnements virtuels
|
# Environnements virtuels
|
||||||
venv/
|
venv/
|
||||||
.env
|
.env
|
||||||
|
|
|
||||||
2
main.py
2
main.py
|
|
@ -1491,7 +1491,7 @@ def regler_factures_client_endpoint(req: ReglementMultipleRequest):
|
||||||
date_reglement=date_reg,
|
date_reglement=date_reg,
|
||||||
reference=req.reference or "",
|
reference=req.reference or "",
|
||||||
libelle=req.libelle or "",
|
libelle=req.libelle or "",
|
||||||
code_journal=req.code_journal, # None = auto
|
code_journal=req.code_journal,
|
||||||
numeros_factures=req.numeros_factures,
|
numeros_factures=req.numeros_factures,
|
||||||
devise_code=req.devise_code,
|
devise_code=req.devise_code,
|
||||||
cours_devise=req.cours_devise,
|
cours_devise=req.cours_devise,
|
||||||
|
|
|
||||||
|
|
@ -3714,9 +3714,6 @@ class SageConnector:
|
||||||
|
|
||||||
client = win32com.client.CastTo(persist, "IBOClient3")
|
client = win32com.client.CastTo(persist, "IBOClient3")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# DEBUG TEMPORAIRE : Lister les méthodes disponibles
|
|
||||||
# ============================================================
|
|
||||||
methodes_client = [m for m in dir(client) if not m.startswith("_")]
|
methodes_client = [m for m in dir(client) if not m.startswith("_")]
|
||||||
logger.info(
|
logger.info(
|
||||||
f" [DEBUG] Méthodes disponibles sur client: {methodes_client}"
|
f" [DEBUG] Méthodes disponibles sur client: {methodes_client}"
|
||||||
|
|
@ -3732,11 +3729,6 @@ class SageConnector:
|
||||||
]
|
]
|
||||||
logger.info(f" [DEBUG] Méthodes lock/read/write: {lock_methods}")
|
logger.info(f" [DEBUG] Méthodes lock/read/write: {lock_methods}")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# VERROUILLAGE : Tenter plusieurs approches
|
|
||||||
# ============================================================
|
|
||||||
import time
|
|
||||||
|
|
||||||
max_retries = 3
|
max_retries = 3
|
||||||
retry_delay = 1.0
|
retry_delay = 1.0
|
||||||
locked = False
|
locked = False
|
||||||
|
|
@ -3811,9 +3803,6 @@ class SageConnector:
|
||||||
f" Client chargé: {getattr(client, 'CT_Intitule', '')} (via {lock_method_used})"
|
f" Client chargé: {getattr(client, 'CT_Intitule', '')} (via {lock_method_used})"
|
||||||
)
|
)
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 2: IDENTIFICATION
|
|
||||||
# ============================================================
|
|
||||||
logger.info("[ETAPE 2] IDENTIFICATION")
|
logger.info("[ETAPE 2] IDENTIFICATION")
|
||||||
|
|
||||||
if "intitule" in client_data:
|
if "intitule" in client_data:
|
||||||
|
|
@ -3871,9 +3860,6 @@ class SageConnector:
|
||||||
):
|
):
|
||||||
champs_modifies.append("code_naf")
|
champs_modifies.append("code_naf")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 3: ADRESSE
|
|
||||||
# ============================================================
|
|
||||||
adresse_keys = [
|
adresse_keys = [
|
||||||
"contact",
|
"contact",
|
||||||
"adresse",
|
"adresse",
|
||||||
|
|
@ -3947,9 +3933,6 @@ class SageConnector:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f" Adresse erreur: {e}")
|
logger.error(f" Adresse erreur: {e}")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 4: TELECOM
|
|
||||||
# ============================================================
|
|
||||||
telecom_keys = [
|
telecom_keys = [
|
||||||
"telephone",
|
"telephone",
|
||||||
"telecopie",
|
"telecopie",
|
||||||
|
|
@ -4010,9 +3993,6 @@ class SageConnector:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f" Telecom erreur: {e}")
|
logger.error(f" Telecom erreur: {e}")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 5: COMPTE GENERAL
|
|
||||||
# ============================================================
|
|
||||||
if "compte_general" in client_data:
|
if "compte_general" in client_data:
|
||||||
logger.info("[ETAPE 5] COMPTE GENERAL")
|
logger.info("[ETAPE 5] COMPTE GENERAL")
|
||||||
|
|
||||||
|
|
@ -4039,9 +4019,6 @@ class SageConnector:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f" CompteGPrinc erreur: {e}")
|
logger.warning(f" CompteGPrinc erreur: {e}")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 6: CATEGORIES
|
|
||||||
# ============================================================
|
|
||||||
if (
|
if (
|
||||||
"categorie_tarifaire" in client_data
|
"categorie_tarifaire" in client_data
|
||||||
or "categorie_comptable" in client_data
|
or "categorie_comptable" in client_data
|
||||||
|
|
@ -4086,9 +4063,6 @@ class SageConnector:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f" CatCompta erreur: {e}")
|
logger.warning(f" CatCompta erreur: {e}")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 7: TAUX
|
|
||||||
# ============================================================
|
|
||||||
taux_modifies = False
|
taux_modifies = False
|
||||||
for i in range(1, 5):
|
for i in range(1, 5):
|
||||||
key = f"taux{i:02d}"
|
key = f"taux{i:02d}"
|
||||||
|
|
@ -4101,9 +4075,6 @@ class SageConnector:
|
||||||
if try_set_attribute(client, f"CT_Taux{i:02d}", val):
|
if try_set_attribute(client, f"CT_Taux{i:02d}", val):
|
||||||
champs_modifies.append(key)
|
champs_modifies.append(key)
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 8: STATISTIQUES
|
|
||||||
# ============================================================
|
|
||||||
stat_modifies = False
|
stat_modifies = False
|
||||||
|
|
||||||
stat01 = client_data.get("statistique01") or client_data.get("secteur")
|
stat01 = client_data.get("statistique01") or client_data.get("secteur")
|
||||||
|
|
@ -4131,9 +4102,6 @@ class SageConnector:
|
||||||
):
|
):
|
||||||
champs_modifies.append(key)
|
champs_modifies.append(key)
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 9: COMMERCIAL
|
|
||||||
# ============================================================
|
|
||||||
commercial_keys = [
|
commercial_keys = [
|
||||||
"encours_autorise",
|
"encours_autorise",
|
||||||
"assurance_credit",
|
"assurance_credit",
|
||||||
|
|
@ -4185,9 +4153,6 @@ class SageConnector:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f" Collaborateur erreur: {e}")
|
logger.warning(f" Collaborateur erreur: {e}")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 10: FACTURATION
|
|
||||||
# ============================================================
|
|
||||||
facturation_keys = [
|
facturation_keys = [
|
||||||
"lettrage_auto",
|
"lettrage_auto",
|
||||||
"est_actif",
|
"est_actif",
|
||||||
|
|
@ -4250,9 +4215,6 @@ class SageConnector:
|
||||||
):
|
):
|
||||||
champs_modifies.append(key)
|
champs_modifies.append(key)
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 11: LOGISTIQUE
|
|
||||||
# ============================================================
|
|
||||||
logistique_keys = [
|
logistique_keys = [
|
||||||
"priorite_livraison",
|
"priorite_livraison",
|
||||||
"livraison_partielle",
|
"livraison_partielle",
|
||||||
|
|
@ -4277,9 +4239,6 @@ class SageConnector:
|
||||||
):
|
):
|
||||||
champs_modifies.append(key)
|
champs_modifies.append(key)
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 12: COMMENTAIRE
|
|
||||||
# ============================================================
|
|
||||||
if "commentaire" in client_data:
|
if "commentaire" in client_data:
|
||||||
logger.info("[ETAPE 12] COMMENTAIRE")
|
logger.info("[ETAPE 12] COMMENTAIRE")
|
||||||
if try_set_attribute(
|
if try_set_attribute(
|
||||||
|
|
@ -4289,9 +4248,6 @@ class SageConnector:
|
||||||
):
|
):
|
||||||
champs_modifies.append("commentaire")
|
champs_modifies.append("commentaire")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 13: ANALYTIQUE
|
|
||||||
# ============================================================
|
|
||||||
if "section_analytique" in client_data:
|
if "section_analytique" in client_data:
|
||||||
logger.info("[ETAPE 13] ANALYTIQUE")
|
logger.info("[ETAPE 13] ANALYTIQUE")
|
||||||
if try_set_attribute(
|
if try_set_attribute(
|
||||||
|
|
@ -4301,9 +4257,6 @@ class SageConnector:
|
||||||
):
|
):
|
||||||
champs_modifies.append("section_analytique")
|
champs_modifies.append("section_analytique")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# ETAPE 14: ORGANISATION & SURVEILLANCE
|
|
||||||
# ============================================================
|
|
||||||
organisation_keys = [
|
organisation_keys = [
|
||||||
"mode_reglement_code",
|
"mode_reglement_code",
|
||||||
"surveillance_active",
|
"surveillance_active",
|
||||||
|
|
@ -4411,9 +4364,6 @@ class SageConnector:
|
||||||
):
|
):
|
||||||
champs_modifies.append("sv_resultat")
|
champs_modifies.append("sv_resultat")
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# VERIFICATION AVANT WRITE
|
|
||||||
# ============================================================
|
|
||||||
if not champs_modifies:
|
if not champs_modifies:
|
||||||
logger.warning("Aucun champ à modifier")
|
logger.warning("Aucun champ à modifier")
|
||||||
# Déverrouiller si nécessaire
|
# Déverrouiller si nécessaire
|
||||||
|
|
@ -4432,10 +4382,6 @@ class SageConnector:
|
||||||
for i, champ in enumerate(champs_modifies, 1):
|
for i, champ in enumerate(champs_modifies, 1):
|
||||||
logger.info(f" {i}. {champ}")
|
logger.info(f" {i}. {champ}")
|
||||||
logger.info("=" * 80)
|
logger.info("=" * 80)
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# WRITE AVEC GESTION DU DEVERROUILLAGE
|
|
||||||
# ============================================================
|
|
||||||
try:
|
try:
|
||||||
client.Write()
|
client.Write()
|
||||||
logger.info("[OK] Write réussi")
|
logger.info("[OK] Write réussi")
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,7 @@
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, validator, EmailStr, field_validator
|
|
||||||
from typing import Optional, List, Dict
|
|
||||||
from enum import Enum, IntEnum
|
|
||||||
from datetime import datetime, date
|
|
||||||
|
|
||||||
class FamilleCreate(BaseModel):
|
class FamilleCreate(BaseModel):
|
||||||
"""Modèle pour créer une famille d'articles"""
|
"""Modèle pour créer une famille d'articles"""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,3 @@
|
||||||
"""
|
|
||||||
Schémas Pydantic pour les règlements de factures
|
|
||||||
Module: schemas/reglements.py
|
|
||||||
"""
|
|
||||||
|
|
||||||
from pydantic import BaseModel, Field, field_validator
|
from pydantic import BaseModel, Field, field_validator
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
|
||||||
|
|
@ -929,10 +929,6 @@ def enrichir_conditionnements(articles: List[Dict], cursor) -> List[Dict]:
|
||||||
|
|
||||||
|
|
||||||
def _mapper_article_depuis_row(row_data: Dict, colonnes_config: Dict) -> Dict:
|
def _mapper_article_depuis_row(row_data: Dict, colonnes_config: Dict) -> Dict:
|
||||||
"""
|
|
||||||
Mappe les données brutes de la DB vers le format ArticleResponse
|
|
||||||
avec normalisation des types et génération des libellés
|
|
||||||
"""
|
|
||||||
article = {}
|
article = {}
|
||||||
|
|
||||||
def get_val(sql_col, default=None, convert_type=None):
|
def get_val(sql_col, default=None, convert_type=None):
|
||||||
|
|
@ -1492,12 +1488,6 @@ def enrichir_tva_articles(articles: List[Dict], cursor) -> List[Dict]:
|
||||||
return articles
|
return articles
|
||||||
|
|
||||||
|
|
||||||
def _get_type_article_libelle(type_val: int) -> str:
|
|
||||||
"""Retourne le libellé du type d'article"""
|
|
||||||
types = {0: "Article", 1: "Prestation", 2: "Divers / Frais", 3: "Nomenclature"}
|
|
||||||
return types.get(type_val, f"Type {type_val}")
|
|
||||||
|
|
||||||
|
|
||||||
def _cast_article(persist_obj):
|
def _cast_article(persist_obj):
|
||||||
try:
|
try:
|
||||||
obj = win32com.client.CastTo(persist_obj, "IBOArticle3")
|
obj = win32com.client.CastTo(persist_obj, "IBOArticle3")
|
||||||
|
|
|
||||||
|
|
@ -1369,43 +1369,66 @@ def regler_factures_client(
|
||||||
reference="",
|
reference="",
|
||||||
libelle="",
|
libelle="",
|
||||||
numeros_factures=None,
|
numeros_factures=None,
|
||||||
|
code_journal=None,
|
||||||
|
devise_code=0,
|
||||||
|
cours_devise=1.0,
|
||||||
|
tva_encaissement=False,
|
||||||
):
|
):
|
||||||
|
"""Règle plusieurs factures d'un client"""
|
||||||
if not self.cial:
|
if not self.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
if montant_total <= 0:
|
if montant_total <= 0:
|
||||||
raise ValueError("Le montant total doit être positif")
|
raise ValueError("Le montant total doit être positif")
|
||||||
|
|
||||||
date_reglement = date_reglement or datetime.now()
|
date_reglement = date_reglement or datetime.now()
|
||||||
|
|
||||||
|
# Déduction automatique du journal si non fourni
|
||||||
|
if not code_journal:
|
||||||
|
code_journal = _get_journal_auto(self, mode_reglement)
|
||||||
|
|
||||||
factures = _get_factures_non_soldees_client_sql(self, client_code, numeros_factures)
|
factures = _get_factures_non_soldees_client_sql(self, client_code, numeros_factures)
|
||||||
if not factures:
|
if not factures:
|
||||||
raise ValueError(f"Aucune facture à régler pour {client_code}")
|
raise ValueError(f"Aucune facture à régler pour {client_code}")
|
||||||
|
|
||||||
solde_total = sum(f["solde"] for f in factures)
|
solde_total = sum(f["solde"] for f in factures)
|
||||||
if montant_total > solde_total + 0.01:
|
if montant_total > solde_total + 0.01:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Montant ({montant_total}€) supérieur au solde ({solde_total:.2f}€)"
|
f"Montant ({montant_total}€) supérieur au solde ({solde_total:.2f}€)"
|
||||||
)
|
)
|
||||||
|
|
||||||
reglements = []
|
reglements = []
|
||||||
restant = montant_total
|
restant = montant_total
|
||||||
|
|
||||||
for fac in factures:
|
for fac in factures:
|
||||||
if restant < 0.01:
|
if restant < 0.01:
|
||||||
break
|
break
|
||||||
|
|
||||||
a_regler = min(restant, fac["solde"])
|
a_regler = min(restant, fac["solde"])
|
||||||
|
|
||||||
try:
|
try:
|
||||||
res = regler_facture(
|
res = regler_facture(
|
||||||
self,
|
self,
|
||||||
fac["numero"],
|
fac["numero"],
|
||||||
a_regler,
|
a_regler,
|
||||||
mode_reglement,
|
mode_reglement=mode_reglement,
|
||||||
date_reglement,
|
date_reglement=date_reglement,
|
||||||
reference,
|
reference=reference,
|
||||||
libelle,
|
libelle=libelle,
|
||||||
|
code_journal=code_journal,
|
||||||
|
devise_code=devise_code,
|
||||||
|
cours_devise=cours_devise,
|
||||||
|
tva_encaissement=tva_encaissement,
|
||||||
|
compte_general=None, # Optionnel, peut être ajouté si nécessaire
|
||||||
)
|
)
|
||||||
reglements.append(res)
|
reglements.append(res)
|
||||||
restant -= a_regler
|
restant -= a_regler
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Erreur {fac['numero']}: {e}")
|
logger.error(f"Erreur règlement {fac['numero']}: {e}")
|
||||||
break
|
break
|
||||||
|
|
||||||
if not reglements:
|
if not reglements:
|
||||||
raise RuntimeError("Aucun règlement effectué")
|
raise RuntimeError("Aucun règlement effectué")
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"client_code": client_code,
|
"client_code": client_code,
|
||||||
"montant_demande": montant_total,
|
"montant_demande": montant_total,
|
||||||
|
|
@ -1416,6 +1439,11 @@ def regler_factures_client(
|
||||||
"mode_reglement": mode_reglement,
|
"mode_reglement": mode_reglement,
|
||||||
"mode_reglement_libelle": ModeReglement.get_libelle(mode_reglement),
|
"mode_reglement_libelle": ModeReglement.get_libelle(mode_reglement),
|
||||||
"reference": reference,
|
"reference": reference,
|
||||||
|
"libelle": libelle,
|
||||||
|
"code_journal": code_journal,
|
||||||
|
"devise_code": devise_code,
|
||||||
|
"cours_devise": cours_devise,
|
||||||
|
"tva_encaissement": tva_encaissement,
|
||||||
"reglements": reglements,
|
"reglements": reglements,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,10 @@
|
||||||
"""
|
from typing import Dict
|
||||||
Validation de factures Sage 100c
|
|
||||||
Module: utils/documents/validation.py (Windows Server)
|
|
||||||
|
|
||||||
Version diagnostic - Introspection complète pour trouver la méthode de validation
|
|
||||||
"""
|
|
||||||
|
|
||||||
from typing import Dict, List
|
|
||||||
import win32com.client
|
import win32com.client
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# FONCTIONS SQL (LECTURE)
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
|
|
||||||
def get_statut_validation(connector, numero_facture: str) -> Dict:
|
def get_statut_validation(connector, numero_facture: str) -> Dict:
|
||||||
"""Retourne le statut de validation d'une facture (SQL)"""
|
"""Retourne le statut de validation d'une facture (SQL)"""
|
||||||
with connector._get_sql_connection() as conn:
|
with connector._get_sql_connection() as conn:
|
||||||
|
|
@ -95,16 +83,7 @@ def _get_facture_info_sql(connector, numero_facture: str) -> Dict:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# INTROSPECTION COMPLÈTE
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
|
|
||||||
def introspecter_document_complet(connector, numero_facture: str) -> Dict:
|
def introspecter_document_complet(connector, numero_facture: str) -> Dict:
|
||||||
"""
|
|
||||||
Introspection COMPLÈTE d'un document pour découvrir toutes les méthodes
|
|
||||||
et propriétés disponibles.
|
|
||||||
"""
|
|
||||||
if not connector.cial:
|
if not connector.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
|
@ -174,7 +153,7 @@ def introspecter_document_complet(connector, numero_facture: str) -> Dict:
|
||||||
val = getattr(doc, attr, None)
|
val = getattr(doc, attr, None)
|
||||||
if callable(val):
|
if callable(val):
|
||||||
result["IBODocumentVente3"]["methods"].append(attr)
|
result["IBODocumentVente3"]["methods"].append(attr)
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Chercher DO_* properties
|
# Chercher DO_* properties
|
||||||
|
|
@ -249,9 +228,6 @@ def introspecter_document_complet(connector, numero_facture: str) -> Dict:
|
||||||
|
|
||||||
|
|
||||||
def introspecter_validation(connector, numero_facture: str = None) -> Dict:
|
def introspecter_validation(connector, numero_facture: str = None) -> Dict:
|
||||||
"""
|
|
||||||
Introspection pour découvrir les méthodes de validation.
|
|
||||||
"""
|
|
||||||
if not connector.cial:
|
if not connector.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
|
@ -292,7 +268,7 @@ def introspecter_validation(connector, numero_facture: str = None) -> Dict:
|
||||||
|
|
||||||
|
|
||||||
def valider_facture(connector, numero_facture: str) -> Dict:
|
def valider_facture(connector, numero_facture: str) -> Dict:
|
||||||
logger.info(f"🔒 Validation facture {numero_facture} (SQL direct)")
|
logger.info(f" Validation facture {numero_facture} (SQL direct)")
|
||||||
|
|
||||||
# Vérifications préalables
|
# Vérifications préalables
|
||||||
with connector._get_sql_connection() as conn:
|
with connector._get_sql_connection() as conn:
|
||||||
|
|
@ -357,13 +333,10 @@ def valider_facture(connector, numero_facture: str) -> Dict:
|
||||||
|
|
||||||
|
|
||||||
def devalider_facture(connector, numero_facture: str) -> Dict:
|
def devalider_facture(connector, numero_facture: str) -> Dict:
|
||||||
"""
|
|
||||||
Dévalide une facture (retire le cadenas)
|
|
||||||
"""
|
|
||||||
if not connector.cial:
|
if not connector.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
logger.info(f"🔓 Dévalidation facture {numero_facture}")
|
logger.info(f" Dévalidation facture {numero_facture}")
|
||||||
|
|
||||||
info = _get_facture_info_sql(connector, numero_facture)
|
info = _get_facture_info_sql(connector, numero_facture)
|
||||||
if not info:
|
if not info:
|
||||||
|
|
@ -395,7 +368,7 @@ def devalider_facture(connector, numero_facture: str) -> Dict:
|
||||||
if not success:
|
if not success:
|
||||||
raise RuntimeError("La dévalidation COM a échoué")
|
raise RuntimeError("La dévalidation COM a échoué")
|
||||||
|
|
||||||
logger.info(f"✅ Facture {numero_facture} dévalidée")
|
logger.info(f" Facture {numero_facture} dévalidée")
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
raise
|
raise
|
||||||
|
|
@ -415,9 +388,6 @@ def devalider_facture(connector, numero_facture: str) -> Dict:
|
||||||
|
|
||||||
|
|
||||||
def _valider_document_com(connector, numero_facture: str, valider: bool = True) -> bool:
|
def _valider_document_com(connector, numero_facture: str, valider: bool = True) -> bool:
|
||||||
"""
|
|
||||||
Tente de valider/dévalider un document via COM.
|
|
||||||
"""
|
|
||||||
erreurs = []
|
erreurs = []
|
||||||
action = "validation" if valider else "dévalidation"
|
action = "validation" if valider else "dévalidation"
|
||||||
valeur_cible = 1 if valider else 0
|
valeur_cible = 1 if valider else 0
|
||||||
|
|
@ -452,7 +422,7 @@ def _valider_document_com(connector, numero_facture: str, valider: bool = True)
|
||||||
logger.info(f" DO_Valide après: {valeur_apres}")
|
logger.info(f" DO_Valide après: {valeur_apres}")
|
||||||
|
|
||||||
if valeur_apres == valeur_cible:
|
if valeur_apres == valeur_cible:
|
||||||
logger.info(f" ✅ DO_Valide modifié avec succès!")
|
logger.info(" DO_Valide modifié avec succès!")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
erreurs.append(
|
erreurs.append(
|
||||||
|
|
@ -534,9 +504,6 @@ def _valider_document_com(connector, numero_facture: str, valider: bool = True)
|
||||||
|
|
||||||
def explorer_toutes_interfaces_validation(connector, numero_facture: str) -> Dict:
|
def explorer_toutes_interfaces_validation(connector, numero_facture: str) -> Dict:
|
||||||
"""Explorer TOUTES les interfaces possibles pour trouver un setter DO_Valide"""
|
"""Explorer TOUTES les interfaces possibles pour trouver un setter DO_Valide"""
|
||||||
import win32com.client
|
|
||||||
import pythoncom
|
|
||||||
|
|
||||||
result = {"numero_facture": numero_facture, "interfaces": {}}
|
result = {"numero_facture": numero_facture, "interfaces": {}}
|
||||||
|
|
||||||
with connector._com_context(), connector._lock_com:
|
with connector._com_context(), connector._lock_com:
|
||||||
|
|
@ -597,17 +564,12 @@ def explorer_toutes_interfaces_validation(connector, numero_facture: str) -> Dic
|
||||||
for a in factory_attrs
|
for a in factory_attrs
|
||||||
if any(x in a.lower() for x in ["valid", "lock", "confirm", "imprim"])
|
if any(x in a.lower() for x in ["valid", "lock", "confirm", "imprim"])
|
||||||
]
|
]
|
||||||
except:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
|
||||||
# FONCTIONS UTILITAIRES
|
|
||||||
# ============================================================
|
|
||||||
|
|
||||||
|
|
||||||
def _build_response_sql(
|
def _build_response_sql(
|
||||||
connector, numero_facture: str, deja_valide: bool, action: str
|
connector, numero_facture: str, deja_valide: bool, action: str
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
|
|
|
||||||
|
|
@ -425,9 +425,6 @@ def modifier_document_vente(
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self._com_context(), self._lock_com:
|
with self._com_context(), self._lock_com:
|
||||||
# ==========================================
|
|
||||||
# 1. CHARGEMENT DOCUMENT
|
|
||||||
# ==========================================
|
|
||||||
logger.info("📂 Chargement document...")
|
logger.info("📂 Chargement document...")
|
||||||
factory = self.cial.FactoryDocumentVente
|
factory = self.cial.FactoryDocumentVente
|
||||||
persist = None
|
persist = None
|
||||||
|
|
@ -458,9 +455,6 @@ def modifier_document_vente(
|
||||||
if statut_actuel == 6:
|
if statut_actuel == 6:
|
||||||
raise ValueError(f"Le {config.nom_document} est annulé")
|
raise ValueError(f"Le {config.nom_document} est annulé")
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 2. SAUVEGARDE CLIENT INITIAL
|
|
||||||
# ==========================================
|
|
||||||
client_code_initial = ""
|
client_code_initial = ""
|
||||||
try:
|
try:
|
||||||
client_obj = getattr(doc, "Client", None)
|
client_obj = getattr(doc, "Client", None)
|
||||||
|
|
@ -474,9 +468,6 @@ def modifier_document_vente(
|
||||||
if not client_code_initial:
|
if not client_code_initial:
|
||||||
raise ValueError("Client introuvable dans le document")
|
raise ValueError("Client introuvable dans le document")
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 3. COMPTAGE LIGNES EXISTANTES
|
|
||||||
# ==========================================
|
|
||||||
nb_lignes_initial = 0
|
nb_lignes_initial = 0
|
||||||
try:
|
try:
|
||||||
factory_lignes = getattr(doc, "FactoryDocumentLigne", None) or getattr(
|
factory_lignes = getattr(doc, "FactoryDocumentLigne", None) or getattr(
|
||||||
|
|
@ -496,9 +487,6 @@ def modifier_document_vente(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f" Erreur comptage lignes: {e}")
|
logger.warning(f" Erreur comptage lignes: {e}")
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 4. ANALYSE MODIFICATIONS
|
|
||||||
# ==========================================
|
|
||||||
champs_modifies = []
|
champs_modifies = []
|
||||||
|
|
||||||
modif_date = config.champ_date_principale in doc_data
|
modif_date = config.champ_date_principale in doc_data
|
||||||
|
|
@ -531,9 +519,6 @@ def modifier_document_vente(
|
||||||
statut_a_modifier = doc_data_temp.pop("statut")
|
statut_a_modifier = doc_data_temp.pop("statut")
|
||||||
modif_statut = False
|
modif_statut = False
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 5. TEST WRITE BASIQUE
|
|
||||||
# ==========================================
|
|
||||||
logger.info("🔍 Test Write() basique...")
|
logger.info("🔍 Test Write() basique...")
|
||||||
try:
|
try:
|
||||||
doc.Write()
|
doc.Write()
|
||||||
|
|
@ -543,9 +528,6 @@ def modifier_document_vente(
|
||||||
logger.error(f" Document verrouillé: {e}")
|
logger.error(f" Document verrouillé: {e}")
|
||||||
raise ValueError(f"Document verrouillé: {e}")
|
raise ValueError(f"Document verrouillé: {e}")
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 6. MODIFICATIONS SIMPLES (sans lignes)
|
|
||||||
# ==========================================
|
|
||||||
if not modif_lignes and (
|
if not modif_lignes and (
|
||||||
modif_date or modif_date_sec or modif_statut or modif_ref
|
modif_date or modif_date_sec or modif_statut or modif_ref
|
||||||
):
|
):
|
||||||
|
|
@ -576,16 +558,12 @@ def modifier_document_vente(
|
||||||
doc.DO_Ref = doc_data_temp["reference"]
|
doc.DO_Ref = doc_data_temp["reference"]
|
||||||
champs_modifies.append("reference")
|
champs_modifies.append("reference")
|
||||||
|
|
||||||
# 🔥 CONFIGURATION SPÉCIFIQUE FACTURE
|
|
||||||
if type_document == TypeDocumentVente.FACTURE:
|
if type_document == TypeDocumentVente.FACTURE:
|
||||||
_configurer_facture(self, doc)
|
_configurer_facture(self, doc)
|
||||||
|
|
||||||
doc.Write()
|
doc.Write()
|
||||||
logger.info(" ✓ Modifications appliquées")
|
logger.info(" ✓ Modifications appliquées")
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 7. REMPLACEMENT LIGNES
|
|
||||||
# ==========================================
|
|
||||||
elif modif_lignes:
|
elif modif_lignes:
|
||||||
logger.info("🔄 REMPLACEMENT COMPLET DES LIGNES...")
|
logger.info("🔄 REMPLACEMENT COMPLET DES LIGNES...")
|
||||||
|
|
||||||
|
|
@ -655,9 +633,6 @@ def modifier_document_vente(
|
||||||
|
|
||||||
champs_modifies.append("lignes")
|
champs_modifies.append("lignes")
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 8. MODIFICATIONS REPORTÉES
|
|
||||||
# ==========================================
|
|
||||||
if reference_a_modifier is not None:
|
if reference_a_modifier is not None:
|
||||||
try:
|
try:
|
||||||
logger.info(
|
logger.info(
|
||||||
|
|
@ -684,9 +659,6 @@ def modifier_document_vente(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f" Statut: {e}")
|
logger.warning(f" Statut: {e}")
|
||||||
|
|
||||||
# ==========================================
|
|
||||||
# 9. RELECTURE FINALE
|
|
||||||
# ==========================================
|
|
||||||
resultat = _relire_document_final(
|
resultat = _relire_document_final(
|
||||||
self, config, numero, doc_data, client_code_fallback=client_code_initial
|
self, config, numero, doc_data, client_code_fallback=client_code_initial
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
def _build_tiers_select_query():
|
def _build_tiers_select_query():
|
||||||
"""Construit la partie SELECT de la requête avec tous les champs tiers + collaborateur"""
|
|
||||||
return """
|
return """
|
||||||
SELECT
|
SELECT
|
||||||
-- IDENTIFICATION TIERS (9)
|
-- IDENTIFICATION TIERS (9)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue