From 5c80a5e912b66b374e764510cab5283a12d27a8f Mon Sep 17 00:00:00 2001 From: fanilo Date: Thu, 15 Jan 2026 12:22:04 +0100 Subject: [PATCH] validation method par SQL, dangereux actuellement mais "seem" functionnal --- utils/documents/validations.py | 137 +++++++++++---------------------- 1 file changed, 47 insertions(+), 90 deletions(-) diff --git a/utils/documents/validations.py b/utils/documents/validations.py index 770060b..c12eee0 100644 --- a/utils/documents/validations.py +++ b/utils/documents/validations.py @@ -293,113 +293,70 @@ def introspecter_validation(connector, numero_facture: str = None) -> Dict: def valider_facture(connector, numero_facture: str) -> Dict: """ - Valide via late binding forcé + invocation COM correcte + Valide une facture via SQL direct + ⚠️ Contourne les règles métier Sage - à utiliser avec précaution """ - import win32com.client - import win32com.client.dynamic - import pythoncom + logger.info(f"🔒 Validation facture {numero_facture} (SQL direct)") - if not connector.cial: - raise RuntimeError("Connexion Sage non établie") + # Vérifications préalables + with connector._get_sql_connection() as conn: + cursor = conn.cursor() - logger.info(f"🔒 Validation facture {numero_facture} (v5)") + # Vérifier que la facture existe et peut être validée + cursor.execute( + """ + SELECT DO_Valide, DO_Statut, DO_TotalTTC, DO_MontantRegle + FROM F_DOCENTETE + WHERE DO_Piece = ? AND DO_Type = 6 + """, + (numero_facture,), + ) - with connector._com_context(), connector._lock_com: - factory = connector.cial.FactoryDocumentVente - - if not factory.ExistPiece(60, numero_facture): + row = cursor.fetchone() + if not row: raise ValueError(f"Facture {numero_facture} introuvable") - persist = factory.ReadPiece(60, numero_facture) - doc = win32com.client.CastTo(persist, "IBODocumentVente3") - doc.Read() + valide_avant, statut, total_ttc, montant_regle = row - # Lecture via getattr - valide_avant = getattr(doc, "DO_Valide", None) - imprim_avant = getattr(doc, "DO_Imprim", None) - logger.info(f" Avant: DO_Imprim={imprim_avant}, DO_Valide={valide_avant}") - - if valide_avant == True: + if valide_avant == 1: return {"numero_facture": numero_facture, "deja_valide": True} - oleobj = doc._oleobj_ + if statut == 6: # Annulé + raise ValueError("Facture annulée, validation impossible") - # Explorer les DISPID - type_info = oleobj.GetTypeInfo() - type_attr = type_info.GetTypeAttr() + # Valider via SQL + cursor.execute( + """ + UPDATE F_DOCENTETE + SET DO_Valide = 1, DO_Imprim = 1 + WHERE DO_Piece = ? AND DO_Type = 6 + """, + (numero_facture,), + ) - dispids = {} - for i in range(type_attr.cFuncs): - func_desc = type_info.GetFuncDesc(i) - names = type_info.GetNames(func_desc.memid) - if names: - name = names[0] - if name in ("DO_Valide", "DO_Imprim"): - invkind = func_desc.invkind - logger.info( - f" {name}: memid={func_desc.memid}, invkind={invkind}, cParams={func_desc.cParamsOpt}" - ) - dispids[name] = { - "memid": func_desc.memid, - "invkind": invkind, - "cParams": func_desc.cParamsOpt, - } + conn.commit() - logger.info(f" DISPIDs trouvés: {dispids}") + # Vérifier + cursor.execute( + """ + SELECT DO_Valide, DO_Imprim + FROM F_DOCENTETE + WHERE DO_Piece = ? AND DO_Type = 6 + """, + (numero_facture,), + ) - errors = [] + valide_apres, imprim_apres = cursor.fetchone() - # Méthode A: Invoke PROPERTYPUT - if "DO_Valide" in dispids: - memid = dispids["DO_Valide"]["memid"] - try: - oleobj.Invoke(memid, 0, pythoncom.DISPATCH_PROPERTYPUT, False, True) - doc.Write() - logger.info(f" ✅ Méthode A: Invoke PROPERTYPUT OK") - except Exception as e: - errors.append(f"Invoke PROPERTYPUT: {e}") - logger.warning(f" Méthode A échouée: {e}") - - # Méthode B: DumbDispatch - try: - raw_dispatch = win32com.client.dynamic.DumbDispatch(oleobj) - raw_dispatch.DO_Valide = True - doc.Write() - logger.info(f" ✅ Méthode B: DumbDispatch OK") - except Exception as e: - errors.append(f"DumbDispatch: {e}") - logger.warning(f" Méthode B échouée: {e}") - - # Méthode C: Dispatch dynamique combiné - try: - if "DO_Valide" in dispids: - memid = dispids["DO_Valide"]["memid"] - oleobj.Invoke( - memid, - 0, - pythoncom.DISPATCH_PROPERTYPUT | pythoncom.DISPATCH_METHOD, - False, - True, - ) - doc.Write() - logger.info(f" ✅ Méthode C: Combined flags OK") - except Exception as e: - errors.append(f"Combined flags: {e}") - logger.warning(f" Méthode C échouée: {e}") - - # Vérification - doc.Read() - valide_apres = getattr(doc, "DO_Valide", None) - imprim_apres = getattr(doc, "DO_Imprim", None) - logger.info(f" Après: DO_Imprim={imprim_apres}, DO_Valide={valide_apres}") + logger.info(f" SQL: DO_Valide={valide_apres}, DO_Imprim={imprim_apres}") return { "numero_facture": numero_facture, - "avant": {"DO_Imprim": imprim_avant, "DO_Valide": valide_avant}, - "apres": {"DO_Imprim": imprim_apres, "DO_Valide": valide_apres}, - "dispids": dispids, - "errors": errors, - "success": valide_apres == True, + "methode": "SQL_DIRECT", + "DO_Valide": valide_apres == 1, + "DO_Imprim": imprim_apres == 1, + "success": valide_apres == 1, + "warning": "Validation SQL directe - règles métier Sage contournées", }