validation facture et règlement effectuées avec succès, mais approche dangereuse !
This commit is contained in:
parent
7dc5d03c4c
commit
f5c5a87d0d
4 changed files with 679 additions and 70 deletions
101
main.py
101
main.py
|
|
@ -1457,6 +1457,11 @@ def regler_facture_endpoint(
|
||||||
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
|
||||||
|
devise_code=req.devise_code,
|
||||||
|
cours_devise=req.cours_devise,
|
||||||
|
tva_encaissement=req.tva_encaissement,
|
||||||
|
compte_general=req.compte_general,
|
||||||
)
|
)
|
||||||
return {
|
return {
|
||||||
"success": True,
|
"success": True,
|
||||||
|
|
@ -1474,15 +1479,23 @@ def regler_facture_endpoint(
|
||||||
@app.post("/sage/reglements/multiple", dependencies=[Depends(verify_token)])
|
@app.post("/sage/reglements/multiple", dependencies=[Depends(verify_token)])
|
||||||
def regler_factures_client_endpoint(req: ReglementMultipleRequest):
|
def regler_factures_client_endpoint(req: ReglementMultipleRequest):
|
||||||
try:
|
try:
|
||||||
|
date_reg = (
|
||||||
|
datetime.combine(req.date_reglement, datetime.min.time())
|
||||||
|
if req.date_reglement
|
||||||
|
else None
|
||||||
|
)
|
||||||
resultat = sage.regler_factures_client(
|
resultat = sage.regler_factures_client(
|
||||||
client_code=req.client_code,
|
client_code=req.client_code,
|
||||||
montant_total=req.montant_total,
|
montant_total=req.montant_total,
|
||||||
mode_reglement=req.mode_reglement,
|
mode_reglement=req.mode_reglement,
|
||||||
date_reglement=req.date_reglement,
|
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,
|
code_journal=req.code_journal, # None = auto
|
||||||
numeros_factures=req.numeros_factures,
|
numeros_factures=req.numeros_factures,
|
||||||
|
devise_code=req.devise_code,
|
||||||
|
cours_devise=req.cours_devise,
|
||||||
|
tva_encaissement=req.tva_encaissement,
|
||||||
)
|
)
|
||||||
|
|
||||||
return {"success": True, "data": resultat}
|
return {"success": True, "data": resultat}
|
||||||
|
|
@ -1591,21 +1604,75 @@ def get_statut_validation_endpoint(numero_facture: str):
|
||||||
|
|
||||||
|
|
||||||
@app.get("/sage/reglements/modes", dependencies=[Depends(verify_token)])
|
@app.get("/sage/reglements/modes", dependencies=[Depends(verify_token)])
|
||||||
def get_modes_reglement():
|
def get_modes_reglement_endpoint():
|
||||||
return {
|
"""Récupère les modes de règlement depuis Sage"""
|
||||||
"success": True,
|
try:
|
||||||
"data": {
|
modes = sage.lire_modes_reglement()
|
||||||
"modes": [
|
return {"success": True, "data": {"modes": modes}}
|
||||||
{"code": 1, "libelle": "Virement"},
|
except Exception as e:
|
||||||
{"code": 2, "libelle": "Chèque"},
|
logger.error(f"Erreur lecture modes règlement: {e}")
|
||||||
{"code": 3, "libelle": "Traite"},
|
raise HTTPException(500, str(e))
|
||||||
{"code": 4, "libelle": "Carte bancaire"},
|
|
||||||
{"code": 5, "libelle": "LCR"},
|
|
||||||
{"code": 6, "libelle": "Prélèvement"},
|
@app.get("/sage/devises", dependencies=[Depends(verify_token)])
|
||||||
{"code": 7, "libelle": "Espèces"},
|
def get_devises_endpoint():
|
||||||
]
|
"""Récupère les devises disponibles depuis Sage"""
|
||||||
},
|
try:
|
||||||
}
|
devises = sage.lire_devises()
|
||||||
|
return {"success": True, "data": {"devises": devises}}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur lecture devises: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/sage/journaux/tresorerie", dependencies=[Depends(verify_token)])
|
||||||
|
def get_journaux_tresorerie_endpoint():
|
||||||
|
"""Récupère les journaux de trésorerie (banque + caisse)"""
|
||||||
|
try:
|
||||||
|
journaux = sage.lire_journaux_tresorerie()
|
||||||
|
return {"success": True, "data": {"journaux": journaux}}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur lecture journaux trésorerie: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/sage/comptes-generaux", dependencies=[Depends(verify_token)])
|
||||||
|
def get_comptes_generaux_endpoint(
|
||||||
|
prefixe: Optional[str] = Query(None, description="Filtre par préfixe (ex: 41, 51)"),
|
||||||
|
type_compte: Optional[str] = Query(
|
||||||
|
None,
|
||||||
|
description="Type: client, fournisseur, banque, caisse, tva, produit, charge",
|
||||||
|
),
|
||||||
|
):
|
||||||
|
"""Récupère les comptes généraux"""
|
||||||
|
try:
|
||||||
|
comptes = sage.lire_comptes_generaux(prefixe=prefixe, type_compte=type_compte)
|
||||||
|
return {"success": True, "data": {"comptes": comptes, "total": len(comptes)}}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur lecture comptes généraux: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/sage/tva/taux", dependencies=[Depends(verify_token)])
|
||||||
|
def get_tva_taux_endpoint():
|
||||||
|
"""Récupère les taux de TVA"""
|
||||||
|
try:
|
||||||
|
taux = sage.lire_tva_taux()
|
||||||
|
return {"success": True, "data": {"taux": taux}}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur lecture taux TVA: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/sage/parametres/encaissement", dependencies=[Depends(verify_token)])
|
||||||
|
def get_parametres_encaissement_endpoint():
|
||||||
|
"""Récupère les paramètres TVA sur encaissement"""
|
||||||
|
try:
|
||||||
|
params = sage.lire_parametres_encaissement()
|
||||||
|
return {"success": True, "data": params}
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Erreur lecture paramètres encaissement: {e}")
|
||||||
|
raise HTTPException(500, str(e))
|
||||||
|
|
||||||
|
|
||||||
@app.get("/sage/journaux")
|
@app.get("/sage/journaux")
|
||||||
|
|
|
||||||
|
|
@ -94,6 +94,13 @@ from utils.functions.society.societe_data import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from utils.documents.settle import (
|
from utils.documents.settle import (
|
||||||
|
lire_modes_reglement,
|
||||||
|
lire_devises,
|
||||||
|
lire_journaux_tresorerie,
|
||||||
|
lire_comptes_generaux,
|
||||||
|
lire_tva_taux,
|
||||||
|
lire_parametres_encaissement,
|
||||||
|
_get_modes_reglement_standards,
|
||||||
regler_facture as _regler_facture,
|
regler_facture as _regler_facture,
|
||||||
regler_factures_client as _regler_factures_client,
|
regler_factures_client as _regler_factures_client,
|
||||||
lire_reglements_client as _lire_reglements_client,
|
lire_reglements_client as _lire_reglements_client,
|
||||||
|
|
@ -8017,33 +8024,47 @@ class SageConnector:
|
||||||
|
|
||||||
def regler_facture(
|
def regler_facture(
|
||||||
self,
|
self,
|
||||||
numero_facture,
|
numero_facture: str,
|
||||||
montant,
|
montant: float,
|
||||||
mode_reglement=2,
|
mode_reglement: int = 0,
|
||||||
date_reglement=None,
|
date_reglement: datetime = None,
|
||||||
reference="",
|
reference: str = "",
|
||||||
libelle="",
|
libelle: str = "",
|
||||||
|
code_journal: str = None,
|
||||||
|
devise_code: int = 0,
|
||||||
|
cours_devise: float = 1.0,
|
||||||
|
tva_encaissement: bool = False,
|
||||||
|
compte_general: str = None,
|
||||||
):
|
):
|
||||||
|
"""Règle une facture"""
|
||||||
return _regler_facture(
|
return _regler_facture(
|
||||||
self,
|
self,
|
||||||
numero_facture,
|
numero_facture=numero_facture,
|
||||||
montant,
|
montant=montant,
|
||||||
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=compte_general,
|
||||||
)
|
)
|
||||||
|
|
||||||
def regler_factures_client(
|
def regler_factures_client(
|
||||||
self,
|
self,
|
||||||
client_code: str,
|
client_code: str,
|
||||||
montant_total: float,
|
montant_total: float,
|
||||||
mode_reglement: int = 2,
|
mode_reglement: int = 0,
|
||||||
date_reglement: datetime = None,
|
date_reglement: datetime = None,
|
||||||
reference: str = "",
|
reference: str = "",
|
||||||
libelle: str = "",
|
libelle: str = "",
|
||||||
code_journal: str = "BEU",
|
code_journal: str = None,
|
||||||
numeros_factures: List[str] = None,
|
numeros_factures: List[str] = None,
|
||||||
|
devise_code: int = 0,
|
||||||
|
cours_devise: float = 1.0,
|
||||||
|
tva_encaissement: bool = False,
|
||||||
):
|
):
|
||||||
"""Règle plusieurs factures d'un client"""
|
"""Règle plusieurs factures d'un client"""
|
||||||
return _regler_factures_client(
|
return _regler_factures_client(
|
||||||
|
|
@ -8056,6 +8077,9 @@ class SageConnector:
|
||||||
libelle=libelle,
|
libelle=libelle,
|
||||||
code_journal=code_journal,
|
code_journal=code_journal,
|
||||||
numeros_factures=numeros_factures,
|
numeros_factures=numeros_factures,
|
||||||
|
devise_code=devise_code,
|
||||||
|
cours_devise=cours_devise,
|
||||||
|
tva_encaissement=tva_encaissement,
|
||||||
)
|
)
|
||||||
|
|
||||||
def lire_reglements_facture(self, numero_facture: str):
|
def lire_reglements_facture(self, numero_facture: str):
|
||||||
|
|
@ -8102,3 +8126,21 @@ class SageConnector:
|
||||||
|
|
||||||
def introspecter_document_complet(self, numero_facture: str) -> dict:
|
def introspecter_document_complet(self, numero_facture: str) -> dict:
|
||||||
return _introspect_doc(self, numero_facture)
|
return _introspect_doc(self, numero_facture)
|
||||||
|
|
||||||
|
def lire_modes_reglement(self) -> dict:
|
||||||
|
return lire_modes_reglement(self)
|
||||||
|
|
||||||
|
def lire_devises(self) -> dict:
|
||||||
|
return lire_devises(self)
|
||||||
|
|
||||||
|
def lire_journaux_tresorerie(self) -> dict:
|
||||||
|
return lire_journaux_tresorerie(self)
|
||||||
|
|
||||||
|
def lire_comptes_generaux(self, prefixe, type_compte) -> dict:
|
||||||
|
return lire_comptes_generaux(self, prefixe, type_compte)
|
||||||
|
|
||||||
|
def lire_tva_taux(self) -> dict:
|
||||||
|
return lire_tva_taux(self)
|
||||||
|
|
||||||
|
def lire_parametres_encaissement(self) -> dict:
|
||||||
|
return lire_parametres_encaissement(self)
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,10 @@ class ReglementFactureRequest(BaseModel):
|
||||||
code_journal: str = Field(
|
code_journal: str = Field(
|
||||||
default="BEU", max_length=6, description="Code journal comptable"
|
default="BEU", max_length=6, description="Code journal comptable"
|
||||||
)
|
)
|
||||||
|
devise_code: Optional[int] = Field(0)
|
||||||
|
cours_devise: Optional[float] = Field(1.0)
|
||||||
|
tva_encaissement: Optional[bool] = Field(False)
|
||||||
|
compte_general: Optional[str] = Field(None)
|
||||||
|
|
||||||
@field_validator("montant")
|
@field_validator("montant")
|
||||||
def validate_montant(cls, v):
|
def validate_montant(cls, v):
|
||||||
|
|
@ -103,6 +107,9 @@ class ReglementMultipleRequest(BaseModel):
|
||||||
default=None,
|
default=None,
|
||||||
description="Liste des factures à régler (sinon: plus anciennes d'abord)",
|
description="Liste des factures à régler (sinon: plus anciennes d'abord)",
|
||||||
)
|
)
|
||||||
|
devise_code: Optional[int] = Field(0)
|
||||||
|
cours_devise: Optional[float] = Field(1.0)
|
||||||
|
tva_encaissement: Optional[bool] = Field(False)
|
||||||
|
|
||||||
@field_validator("client_code", mode="before")
|
@field_validator("client_code", mode="before")
|
||||||
def strip_client_code(cls, v):
|
def strip_client_code(cls, v):
|
||||||
|
|
|
||||||
|
|
@ -12,24 +12,112 @@ logger = logging.getLogger(__name__)
|
||||||
def _get_journal_auto(self, mode_reglement: int) -> str:
|
def _get_journal_auto(self, mode_reglement: int) -> str:
|
||||||
with self._get_sql_connection() as conn:
|
with self._get_sql_connection() as conn:
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
if mode_reglement == ModeReglement.ESPECES:
|
|
||||||
|
# Mode Espèces = 2 (selon l'image Sage fournie)
|
||||||
|
if mode_reglement == 2: # Espèces
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT TOP 1 JO_Num
|
||||||
|
FROM F_JOURNAUX
|
||||||
|
WHERE JO_Type = 2
|
||||||
|
AND JO_Reglement = 1
|
||||||
|
AND CG_Num LIKE '53%'
|
||||||
|
AND (JO_Sommeil = 0 OR JO_Sommeil IS NULL)
|
||||||
|
ORDER BY JO_Num
|
||||||
|
""")
|
||||||
|
else:
|
||||||
|
# Autres modes → Banque
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT TOP 1 JO_Num
|
||||||
|
FROM F_JOURNAUX
|
||||||
|
WHERE JO_Type = 2
|
||||||
|
AND JO_Reglement = 1
|
||||||
|
AND CG_Num LIKE '51%'
|
||||||
|
AND (JO_Sommeil = 0 OR JO_Sommeil IS NULL)
|
||||||
|
ORDER BY JO_Num
|
||||||
|
""")
|
||||||
|
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
return row[0].strip()
|
||||||
|
|
||||||
|
# Fallback: premier journal de trésorerie disponible
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT TOP 1 JO_Num
|
||||||
|
FROM F_JOURNAUX
|
||||||
|
WHERE JO_Type = 2
|
||||||
|
AND JO_Reglement = 1
|
||||||
|
AND (JO_Sommeil = 0 OR JO_Sommeil IS NULL)
|
||||||
|
ORDER BY JO_Num
|
||||||
|
""")
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
return row[0].strip()
|
||||||
|
|
||||||
|
raise ValueError("Aucun journal de trésorerie configuré")
|
||||||
|
|
||||||
|
|
||||||
|
def _valider_coherence_journal_mode(self, code_journal: str, mode_reglement: int):
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
cursor.execute(
|
cursor.execute(
|
||||||
"SELECT TOP 1 JO_Num FROM F_JOURNAUX WHERE JO_Type = 2 AND JO_Reglement = 1 AND CG_Num LIKE '53%' ORDER BY JO_Num"
|
"""
|
||||||
|
SELECT CG_Num
|
||||||
|
FROM F_JOURNAUX
|
||||||
|
WHERE JO_Num = ?
|
||||||
|
""",
|
||||||
|
(code_journal,),
|
||||||
|
)
|
||||||
|
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if not row:
|
||||||
|
raise ValueError(f"Journal {code_journal} introuvable")
|
||||||
|
|
||||||
|
compte_general = (row[0] or "").strip()
|
||||||
|
|
||||||
|
# Mode Espèces (2) doit utiliser un journal caisse (53x)
|
||||||
|
if mode_reglement == 2:
|
||||||
|
if not compte_general.startswith("53"):
|
||||||
|
logger.warning(
|
||||||
|
f"Mode Espèces avec journal non-caisse ({code_journal}, compte {compte_general})"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
cursor.execute(
|
# Autres modes doivent utiliser un journal banque (51x)
|
||||||
"SELECT TOP 1 JO_Num FROM F_JOURNAUX WHERE JO_Type = 2 AND JO_Reglement = 1 AND CG_Num LIKE '51%' ORDER BY JO_Num"
|
if compte_general.startswith("53"):
|
||||||
|
logger.warning(
|
||||||
|
f"Mode non-espèces avec journal caisse ({code_journal}, compte {compte_general})"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_mode_reglement_libelle(self, mode_reglement: int) -> str:
|
||||||
|
"""Récupère le libellé d'un mode de règlement"""
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute(
|
||||||
|
"""
|
||||||
|
SELECT R_Intitule
|
||||||
|
FROM P_REGLEMENT
|
||||||
|
WHERE cbIndice = ?
|
||||||
|
""",
|
||||||
|
(mode_reglement,),
|
||||||
|
)
|
||||||
|
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
if row:
|
if row:
|
||||||
return row[0].strip()
|
return (row[0] or "").strip()
|
||||||
cursor.execute(
|
|
||||||
"SELECT TOP 1 JO_Num FROM F_JOURNAUX WHERE JO_Type = 2 AND JO_Reglement = 1 ORDER BY JO_Num"
|
# Fallback sur les libellés standards
|
||||||
)
|
libelles = {
|
||||||
row = cursor.fetchone()
|
0: "Chèque",
|
||||||
if row:
|
1: "Virement",
|
||||||
return row[0].strip()
|
2: "Espèces",
|
||||||
raise ValueError("Aucun journal de trésorerie configuré")
|
3: "LCR Acceptée",
|
||||||
|
4: "LCR non acceptée",
|
||||||
|
5: "BOR",
|
||||||
|
6: "Prélèvement",
|
||||||
|
7: "Carte bancaire",
|
||||||
|
8: "Bon d'achat",
|
||||||
|
}
|
||||||
|
return libelles.get(mode_reglement, f"Mode {mode_reglement}")
|
||||||
|
|
||||||
|
|
||||||
def lire_journaux_banque(self) -> List[Dict]:
|
def lire_journaux_banque(self) -> List[Dict]:
|
||||||
|
|
@ -83,10 +171,15 @@ def regler_facture(
|
||||||
self,
|
self,
|
||||||
numero_facture: str,
|
numero_facture: str,
|
||||||
montant: float,
|
montant: float,
|
||||||
mode_reglement: int = ModeReglement.CHEQUE,
|
mode_reglement: int = 0, # 0 = Chèque par défaut
|
||||||
date_reglement: datetime = None,
|
date_reglement: datetime = None,
|
||||||
reference: str = "",
|
reference: str = "",
|
||||||
libelle: str = "",
|
libelle: str = "",
|
||||||
|
code_journal: str = None, # Si None, déduit automatiquement
|
||||||
|
devise_code: int = 0,
|
||||||
|
cours_devise: float = 1.0,
|
||||||
|
tva_encaissement: bool = False,
|
||||||
|
compte_general: str = None,
|
||||||
) -> Dict:
|
) -> Dict:
|
||||||
if not self.cial:
|
if not self.cial:
|
||||||
raise RuntimeError("Connexion Sage non établie")
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
@ -94,9 +187,17 @@ def regler_facture(
|
||||||
raise ValueError("Le montant du règlement doit être positif")
|
raise ValueError("Le montant du règlement 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)
|
code_journal = _get_journal_auto(self, mode_reglement)
|
||||||
|
else:
|
||||||
|
# Valider la cohérence journal/mode
|
||||||
|
_valider_coherence_journal_mode(self, code_journal, mode_reglement)
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
f"Règlement facture {numero_facture}: {montant}€ (mode: {mode_reglement}, journal: {code_journal})"
|
f"Règlement facture {numero_facture}: {montant}€ "
|
||||||
|
f"(mode: {mode_reglement}, journal: {code_journal}, devise: {devise_code})"
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -122,6 +223,7 @@ def regler_facture(
|
||||||
f"Montant ({montant}€) supérieur au solde ({solde_actuel:.2f}€)"
|
f"Montant ({montant}€) supérieur au solde ({solde_actuel:.2f}€)"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Récupérer le client
|
||||||
client_code = ""
|
client_code = ""
|
||||||
try:
|
try:
|
||||||
client_obj = getattr(doc, "Client", None)
|
client_obj = getattr(doc, "Client", None)
|
||||||
|
|
@ -131,22 +233,28 @@ def regler_facture(
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# Récupérer l'échéance
|
||||||
echeance = _get_premiere_echeance(doc)
|
echeance = _get_premiere_echeance(doc)
|
||||||
if not echeance:
|
if not echeance:
|
||||||
raise ValueError(f"Facture {numero_facture} sans échéance")
|
raise ValueError(f"Facture {numero_facture} sans échéance")
|
||||||
|
|
||||||
|
# Exécuter le règlement
|
||||||
numero_reglement = _executer_reglement_com(
|
numero_reglement = _executer_reglement_com(
|
||||||
self,
|
self,
|
||||||
doc,
|
doc=doc,
|
||||||
echeance,
|
echeance=echeance,
|
||||||
montant,
|
montant=montant,
|
||||||
mode_reglement,
|
mode_reglement=mode_reglement,
|
||||||
date_reglement,
|
date_reglement=date_reglement,
|
||||||
reference,
|
reference=reference,
|
||||||
libelle,
|
libelle=libelle,
|
||||||
code_journal,
|
code_journal=code_journal,
|
||||||
client_code,
|
client_code=client_code,
|
||||||
numero_facture,
|
numero_facture=numero_facture,
|
||||||
|
devise_code=devise_code,
|
||||||
|
cours_devise=cours_devise,
|
||||||
|
tva_encaissement=tva_encaissement,
|
||||||
|
compte_general=compte_general,
|
||||||
)
|
)
|
||||||
|
|
||||||
time.sleep(0.3)
|
time.sleep(0.3)
|
||||||
|
|
@ -161,16 +269,22 @@ def regler_facture(
|
||||||
nouveau_solde = total_ttc - nouveau_montant_regle
|
nouveau_solde = total_ttc - nouveau_montant_regle
|
||||||
logger.info(f"Règlement effectué - Solde restant: {nouveau_solde:.2f}€")
|
logger.info(f"Règlement effectué - Solde restant: {nouveau_solde:.2f}€")
|
||||||
|
|
||||||
|
# Récupérer le libellé du mode règlement
|
||||||
|
mode_libelle = _get_mode_reglement_libelle(self, mode_reglement)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"numero_facture": numero_facture,
|
"numero_facture": numero_facture,
|
||||||
"numero_reglement": numero_reglement,
|
"numero_reglement": numero_reglement,
|
||||||
"montant_regle": montant,
|
"montant_regle": montant,
|
||||||
"date_reglement": date_reglement.strftime("%Y-%m-%d"),
|
"date_reglement": date_reglement.strftime("%Y-%m-%d"),
|
||||||
"mode_reglement": mode_reglement,
|
"mode_reglement": mode_reglement,
|
||||||
"mode_reglement_libelle": ModeReglement.get_libelle(mode_reglement),
|
"mode_reglement_libelle": mode_libelle,
|
||||||
"reference": reference,
|
"reference": reference,
|
||||||
"libelle": libelle,
|
"libelle": libelle,
|
||||||
"code_journal": code_journal,
|
"code_journal": code_journal,
|
||||||
|
"devise_code": devise_code,
|
||||||
|
"cours_devise": cours_devise,
|
||||||
|
"tva_encaissement": tva_encaissement,
|
||||||
"total_facture": total_ttc,
|
"total_facture": total_ttc,
|
||||||
"solde_restant": nouveau_solde,
|
"solde_restant": nouveau_solde,
|
||||||
"facture_soldee": nouveau_solde < 0.01,
|
"facture_soldee": nouveau_solde < 0.01,
|
||||||
|
|
@ -217,6 +331,10 @@ def _executer_reglement_com(
|
||||||
code_journal,
|
code_journal,
|
||||||
client_code,
|
client_code,
|
||||||
numero_facture,
|
numero_facture,
|
||||||
|
devise_code=0,
|
||||||
|
cours_devise=1.0,
|
||||||
|
tva_encaissement=False,
|
||||||
|
compte_general=None,
|
||||||
):
|
):
|
||||||
erreurs = []
|
erreurs = []
|
||||||
|
|
||||||
|
|
@ -266,7 +384,6 @@ def _executer_reglement_com(
|
||||||
|
|
||||||
# 5. Mode de règlement via l'objet Reglement
|
# 5. Mode de règlement via l'objet Reglement
|
||||||
try:
|
try:
|
||||||
# Lire le mode de règlement depuis la base
|
|
||||||
mode_factory = getattr(
|
mode_factory = getattr(
|
||||||
self.cial.CptaApplication, "FactoryModeReglement", None
|
self.cial.CptaApplication, "FactoryModeReglement", None
|
||||||
)
|
)
|
||||||
|
|
@ -278,15 +395,59 @@ def _executer_reglement_com(
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.debug(f" Mode règlement via factory: {e}")
|
logger.debug(f" Mode règlement via factory: {e}")
|
||||||
|
|
||||||
|
# 6. Devise
|
||||||
|
if devise_code != 0:
|
||||||
|
try:
|
||||||
|
reg.RG_Devise = devise_code
|
||||||
|
logger.info(f" RG_Devise: {devise_code}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f" RG_Devise: {e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
reg.RG_Cours = cours_devise
|
||||||
|
logger.info(f" RG_Cours: {cours_devise}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f" RG_Cours: {e}")
|
||||||
|
|
||||||
|
# Montant en devise
|
||||||
|
try:
|
||||||
|
montant_devise = montant * cours_devise
|
||||||
|
reg.RG_MontantDev = montant_devise
|
||||||
|
logger.info(f" RG_MontantDev: {montant_devise}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f" RG_MontantDev: {e}")
|
||||||
|
|
||||||
|
# 7. TVA sur encaissement
|
||||||
|
if tva_encaissement:
|
||||||
|
try:
|
||||||
|
reg.RG_Encaissement = 1
|
||||||
|
logger.info(" RG_Encaissement: 1 (TVA sur encaissement)")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f" RG_Encaissement: {e}")
|
||||||
|
|
||||||
|
# 8. Compte général spécifique
|
||||||
|
if compte_general:
|
||||||
|
try:
|
||||||
|
cg_factory = self.cial.CptaApplication.FactoryCompteG
|
||||||
|
cg_persist = cg_factory.ReadNumero(compte_general)
|
||||||
|
if cg_persist:
|
||||||
|
reg.CompteG = cg_persist
|
||||||
|
logger.info(f" CompteG défini: {compte_general}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.debug(f" CompteG: {e}")
|
||||||
|
|
||||||
|
# 9. Référence et libellé
|
||||||
if reference:
|
if reference:
|
||||||
try:
|
try:
|
||||||
reg.RG_Reference = reference
|
reg.RG_Reference = reference
|
||||||
|
logger.info(f" RG_Reference: {reference}")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if libelle:
|
if libelle:
|
||||||
try:
|
try:
|
||||||
reg.RG_Libelle = libelle
|
reg.RG_Libelle = libelle
|
||||||
|
logger.info(f" RG_Libelle: {libelle}")
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
@ -300,12 +461,12 @@ def _executer_reglement_com(
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# 6. ÉCRIRE le règlement
|
# 10. ÉCRIRE le règlement
|
||||||
reg.Write()
|
reg.Write()
|
||||||
numero = getattr(reg, "RG_Piece", None)
|
numero = getattr(reg, "RG_Piece", None)
|
||||||
logger.info(f" Règlement écrit avec numéro: {numero}")
|
logger.info(f" Règlement écrit avec numéro: {numero}")
|
||||||
|
|
||||||
# 7. Créer le lien règlement-échéance via la factory DU RÈGLEMENT
|
# 11. Créer le lien règlement-échéance via la factory DU RÈGLEMENT
|
||||||
try:
|
try:
|
||||||
logger.info(" Création du lien règlement-échéance...")
|
logger.info(" Création du lien règlement-échéance...")
|
||||||
factory_reg_ech = getattr(reg, "FactoryDocumentReglementEcheance", None)
|
factory_reg_ech = getattr(reg, "FactoryDocumentReglementEcheance", None)
|
||||||
|
|
@ -325,7 +486,7 @@ def _executer_reglement_com(
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Définir l'échéance - le Reglement est déjà lié via la factory
|
# Définir l'échéance
|
||||||
try:
|
try:
|
||||||
reg_ech.Echeance = echeance
|
reg_ech.Echeance = echeance
|
||||||
logger.info(" Echeance définie")
|
logger.info(" Echeance définie")
|
||||||
|
|
@ -379,7 +540,6 @@ def _executer_reglement_com(
|
||||||
logger.info(" Process() réussi!")
|
logger.info(" Process() réussi!")
|
||||||
return str(numero) if numero else None
|
return str(numero) if numero else None
|
||||||
else:
|
else:
|
||||||
# Vérifier les erreurs
|
|
||||||
try:
|
try:
|
||||||
errors = process.Errors
|
errors = process.Errors
|
||||||
if errors:
|
if errors:
|
||||||
|
|
@ -400,18 +560,15 @@ def _executer_reglement_com(
|
||||||
try:
|
try:
|
||||||
logger.info("Tentative via modification directe de l'échéance...")
|
logger.info("Tentative via modification directe de l'échéance...")
|
||||||
|
|
||||||
# L'échéance a un attribut Reglement qui est le mode de règlement
|
|
||||||
mode_obj = getattr(echeance, "Reglement", None)
|
mode_obj = getattr(echeance, "Reglement", None)
|
||||||
if mode_obj:
|
if mode_obj:
|
||||||
attrs = [a for a in dir(mode_obj) if not a.startswith("_")]
|
attrs = [a for a in dir(mode_obj) if not a.startswith("_")]
|
||||||
logger.info(f" Attributs Reglement échéance: {attrs[:15]}...")
|
logger.info(f" Attributs Reglement échéance: {attrs[:15]}...")
|
||||||
|
|
||||||
# Vérifier si l'échéance a FactoryDocumentReglementEcheance
|
|
||||||
factory_reg_ech = getattr(echeance, "FactoryDocumentReglementEcheance", None)
|
factory_reg_ech = getattr(echeance, "FactoryDocumentReglementEcheance", None)
|
||||||
if factory_reg_ech:
|
if factory_reg_ech:
|
||||||
logger.info(" FactoryDocumentReglementEcheance trouvée sur échéance")
|
logger.info(" FactoryDocumentReglementEcheance trouvée sur échéance")
|
||||||
|
|
||||||
# Créer le lien depuis l'échéance
|
|
||||||
reg_ech = factory_reg_ech.Create()
|
reg_ech = factory_reg_ech.Create()
|
||||||
|
|
||||||
for iface in [
|
for iface in [
|
||||||
|
|
@ -425,15 +582,12 @@ def _executer_reglement_com(
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Ici, l'échéance devrait déjà être liée
|
|
||||||
# Il faut définir le règlement
|
|
||||||
try:
|
try:
|
||||||
# Créer un nouveau règlement pour ce lien
|
|
||||||
factory_reg = self.cial.FactoryDocumentReglement
|
factory_reg = self.cial.FactoryDocumentReglement
|
||||||
new_reg = factory_reg.Create()
|
new_reg = factory_reg.Create()
|
||||||
new_reg = win32com.client.CastTo(new_reg, "IBODocumentReglement")
|
new_reg = win32com.client.CastTo(new_reg, "IBODocumentReglement")
|
||||||
|
|
||||||
# Configurer minimalement
|
# Configurer
|
||||||
journal_factory = self.cial.CptaApplication.FactoryJournal
|
journal_factory = self.cial.CptaApplication.FactoryJournal
|
||||||
journal_persist = journal_factory.ReadNumero(code_journal)
|
journal_persist = journal_factory.ReadNumero(code_journal)
|
||||||
if journal_persist:
|
if journal_persist:
|
||||||
|
|
@ -449,14 +603,37 @@ def _executer_reglement_com(
|
||||||
new_reg.RG_Montant = montant
|
new_reg.RG_Montant = montant
|
||||||
new_reg.RG_Impute = 1
|
new_reg.RG_Impute = 1
|
||||||
|
|
||||||
# Écrire le règlement
|
# Devise si non EUR
|
||||||
|
if devise_code != 0:
|
||||||
|
try:
|
||||||
|
new_reg.RG_Devise = devise_code
|
||||||
|
new_reg.RG_Cours = cours_devise
|
||||||
|
new_reg.RG_MontantDev = montant * cours_devise
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# TVA encaissement
|
||||||
|
if tva_encaissement:
|
||||||
|
try:
|
||||||
|
new_reg.RG_Encaissement = 1
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Compte général
|
||||||
|
if compte_general:
|
||||||
|
try:
|
||||||
|
cg_factory = self.cial.CptaApplication.FactoryCompteG
|
||||||
|
cg_persist = cg_factory.ReadNumero(compte_general)
|
||||||
|
if cg_persist:
|
||||||
|
new_reg.CompteG = cg_persist
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
new_reg.Write()
|
new_reg.Write()
|
||||||
logger.info(
|
logger.info(
|
||||||
f" Nouveau règlement créé: {getattr(new_reg, 'RG_Piece', None)}"
|
f" Nouveau règlement créé: {getattr(new_reg, 'RG_Piece', None)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Assigner au lien - ici on doit peut-être utiliser un autre attribut
|
|
||||||
# Puisque reg_ech.Reglement n'est pas settable, essayons via SetDefault
|
|
||||||
try:
|
try:
|
||||||
reg_ech.SetDefault()
|
reg_ech.SetDefault()
|
||||||
except Exception:
|
except Exception:
|
||||||
|
|
@ -770,6 +947,315 @@ def lire_reglements_client(
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def lire_modes_reglement(self) -> List[Dict]:
|
||||||
|
if not self.cial:
|
||||||
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
cbIndice,
|
||||||
|
R_Intitule,
|
||||||
|
R_Code,
|
||||||
|
R_ModePaieDebit,
|
||||||
|
R_ModePaieCredit
|
||||||
|
FROM P_REGLEMENT
|
||||||
|
WHERE R_Intitule IS NOT NULL AND LTRIM(RTRIM(R_Intitule)) <> ''
|
||||||
|
ORDER BY cbIndice
|
||||||
|
""")
|
||||||
|
|
||||||
|
modes = []
|
||||||
|
for row in cursor.fetchall():
|
||||||
|
intitule = (row[1] or "").strip()
|
||||||
|
if intitule: # Ne garder que ceux avec un intitulé
|
||||||
|
modes.append(
|
||||||
|
{
|
||||||
|
"code": row[0], # cbIndice
|
||||||
|
"intitule": intitule,
|
||||||
|
"code_sage": (row[2] or "").strip(),
|
||||||
|
"mode_paie_debit": row[3] or 0,
|
||||||
|
"mode_paie_credit": row[4] or 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return modes
|
||||||
|
|
||||||
|
|
||||||
|
def _get_modes_reglement_standards() -> List[Dict]:
|
||||||
|
"""Modes de règlement standards Sage si P_REGLEMENT non configuré"""
|
||||||
|
return [
|
||||||
|
{"code": 0, "intitule": "Chèque", "type": "banque"},
|
||||||
|
{"code": 1, "intitule": "Virement", "type": "banque"},
|
||||||
|
{"code": 2, "intitule": "Espèces", "type": "caisse"},
|
||||||
|
{"code": 3, "intitule": "LCR Acceptée", "type": "banque"},
|
||||||
|
{"code": 4, "intitule": "LCR non acceptée", "type": "banque"},
|
||||||
|
{"code": 5, "intitule": "BOR", "type": "banque"},
|
||||||
|
{"code": 6, "intitule": "Prélèvement", "type": "banque"},
|
||||||
|
{"code": 7, "intitule": "Carte bancaire", "type": "banque"},
|
||||||
|
{"code": 8, "intitule": "Bon d'achat", "type": "autre"},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def lire_devises(self) -> List[Dict]:
|
||||||
|
if not self.cial:
|
||||||
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
# Vérifier d'abord si F_DEVISE existe
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES
|
||||||
|
WHERE TABLE_NAME = 'F_DEVISE'
|
||||||
|
""")
|
||||||
|
has_f_devise = cursor.fetchone()[0] > 0
|
||||||
|
|
||||||
|
if has_f_devise:
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
D_Code,
|
||||||
|
D_Intitule,
|
||||||
|
D_Sigle,
|
||||||
|
D_CoursActuel
|
||||||
|
FROM F_DEVISE
|
||||||
|
ORDER BY D_Code
|
||||||
|
""")
|
||||||
|
devises = []
|
||||||
|
for row in cursor.fetchall():
|
||||||
|
devises.append(
|
||||||
|
{
|
||||||
|
"code": row[0],
|
||||||
|
"intitule": (row[1] or "").strip(),
|
||||||
|
"sigle": (row[2] or "").strip(),
|
||||||
|
"cours_actuel": float(row[3] or 1.0),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
if devises:
|
||||||
|
return devises
|
||||||
|
|
||||||
|
# Fallback: Lire depuis P_DOSSIER
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT N_DeviseCompte, N_DeviseEquival
|
||||||
|
FROM P_DOSSIER
|
||||||
|
""")
|
||||||
|
row = cursor.fetchone()
|
||||||
|
|
||||||
|
# Devise par défaut basée sur la config dossier
|
||||||
|
devise_principale = row[0] if row else 0
|
||||||
|
|
||||||
|
# Retourner les devises standards
|
||||||
|
devises_standards = [
|
||||||
|
{
|
||||||
|
"code": 0,
|
||||||
|
"intitule": "Euro",
|
||||||
|
"sigle": "EUR",
|
||||||
|
"cours_actuel": 1.0,
|
||||||
|
"est_principale": devise_principale == 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 1,
|
||||||
|
"intitule": "Dollar US",
|
||||||
|
"sigle": "USD",
|
||||||
|
"cours_actuel": 1.0,
|
||||||
|
"est_principale": devise_principale == 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 2,
|
||||||
|
"intitule": "Livre Sterling",
|
||||||
|
"sigle": "GBP",
|
||||||
|
"cours_actuel": 1.0,
|
||||||
|
"est_principale": devise_principale == 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": 3,
|
||||||
|
"intitule": "Franc Suisse",
|
||||||
|
"sigle": "CHF",
|
||||||
|
"cours_actuel": 1.0,
|
||||||
|
"est_principale": devise_principale == 3,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return devises_standards
|
||||||
|
|
||||||
|
|
||||||
|
def lire_journaux_tresorerie(self) -> List[Dict]:
|
||||||
|
if not self.cial:
|
||||||
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
JO_Num,
|
||||||
|
JO_Intitule,
|
||||||
|
CG_Num,
|
||||||
|
JO_Type,
|
||||||
|
JO_Reglement,
|
||||||
|
JO_Sommeil
|
||||||
|
FROM F_JOURNAUX
|
||||||
|
WHERE JO_Type = 2
|
||||||
|
AND JO_Reglement = 1
|
||||||
|
AND (JO_Sommeil = 0 OR JO_Sommeil IS NULL)
|
||||||
|
ORDER BY JO_Num
|
||||||
|
""")
|
||||||
|
|
||||||
|
journaux = []
|
||||||
|
for row in cursor.fetchall():
|
||||||
|
compte_general = (row[2] or "").strip()
|
||||||
|
# Déterminer le type basé sur le compte général
|
||||||
|
if compte_general.startswith("53"):
|
||||||
|
type_journal = "caisse"
|
||||||
|
elif compte_general.startswith("51"):
|
||||||
|
type_journal = "banque"
|
||||||
|
else:
|
||||||
|
type_journal = "tresorerie"
|
||||||
|
|
||||||
|
journaux.append(
|
||||||
|
{
|
||||||
|
"code": row[0].strip(),
|
||||||
|
"intitule": (row[1] or "").strip(),
|
||||||
|
"compte_general": compte_general,
|
||||||
|
"type": type_journal,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return journaux
|
||||||
|
|
||||||
|
|
||||||
|
def lire_comptes_generaux(
|
||||||
|
self, prefixe: str = None, type_compte: str = None
|
||||||
|
) -> List[Dict]:
|
||||||
|
if not self.cial:
|
||||||
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
# Mapping type -> préfixes de comptes
|
||||||
|
prefixes_map = {
|
||||||
|
"client": ["411"],
|
||||||
|
"fournisseur": ["401"],
|
||||||
|
"banque": ["51"],
|
||||||
|
"caisse": ["53"],
|
||||||
|
"tva_collectee": ["4457"],
|
||||||
|
"tva_deductible": ["4456"],
|
||||||
|
"tva": ["445"],
|
||||||
|
"produit": ["7"],
|
||||||
|
"charge": ["6"],
|
||||||
|
}
|
||||||
|
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
|
||||||
|
query = """
|
||||||
|
SELECT
|
||||||
|
CG_Num,
|
||||||
|
CG_Intitule,
|
||||||
|
CG_Type,
|
||||||
|
CG_Raccourci,
|
||||||
|
CG_Sommeil
|
||||||
|
FROM F_COMPTEG
|
||||||
|
WHERE (CG_Sommeil = 0 OR CG_Sommeil IS NULL)
|
||||||
|
"""
|
||||||
|
params = []
|
||||||
|
|
||||||
|
# Appliquer les filtres
|
||||||
|
if type_compte and type_compte in prefixes_map:
|
||||||
|
prefixes = prefixes_map[type_compte]
|
||||||
|
conditions = " OR ".join(["CG_Num LIKE ?" for _ in prefixes])
|
||||||
|
query += f" AND ({conditions})"
|
||||||
|
params.extend([f"{p}%" for p in prefixes])
|
||||||
|
elif prefixe:
|
||||||
|
query += " AND CG_Num LIKE ?"
|
||||||
|
params.append(f"{prefixe}%")
|
||||||
|
|
||||||
|
query += " ORDER BY CG_Num"
|
||||||
|
|
||||||
|
cursor.execute(query, params)
|
||||||
|
|
||||||
|
comptes = []
|
||||||
|
for row in cursor.fetchall():
|
||||||
|
comptes.append(
|
||||||
|
{
|
||||||
|
"numero": row[0].strip(),
|
||||||
|
"intitule": (row[1] or "").strip(),
|
||||||
|
"type": row[2] or 0,
|
||||||
|
"raccourci": (row[3] or "").strip(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return comptes
|
||||||
|
|
||||||
|
|
||||||
|
def lire_tva_taux(self) -> List[Dict]:
|
||||||
|
if not self.cial:
|
||||||
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
TA_No,
|
||||||
|
TA_Code,
|
||||||
|
TA_Intitule,
|
||||||
|
TA_Taux,
|
||||||
|
TA_TTaux,
|
||||||
|
TA_Type,
|
||||||
|
TA_Sens,
|
||||||
|
CG_Num,
|
||||||
|
TA_Assujet
|
||||||
|
FROM F_TAXE
|
||||||
|
ORDER BY TA_No
|
||||||
|
""")
|
||||||
|
|
||||||
|
taux = []
|
||||||
|
for row in cursor.fetchall():
|
||||||
|
taux.append(
|
||||||
|
{
|
||||||
|
"numero": row[0],
|
||||||
|
"code": (row[1] or "").strip(),
|
||||||
|
"intitule": (row[2] or "").strip(),
|
||||||
|
"taux": float(row[3] or 0),
|
||||||
|
"type_taux": row[4] or 0, # 0=Pourcentage, 1=Montant
|
||||||
|
"type": row[5] or 0, # 0=Collectée, 1=Déductible, etc.
|
||||||
|
"sens": row[6] or 0, # 0=Vente, 1=Achat
|
||||||
|
"compte_general": (row[7] or "").strip(),
|
||||||
|
"assujetti": row[8] or 0,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return taux
|
||||||
|
|
||||||
|
|
||||||
|
def lire_parametres_encaissement(self) -> Dict:
|
||||||
|
if not self.cial:
|
||||||
|
raise RuntimeError("Connexion Sage non établie")
|
||||||
|
|
||||||
|
with self._get_sql_connection() as conn:
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("""
|
||||||
|
SELECT
|
||||||
|
D_TVAEncReg,
|
||||||
|
D_TVAEncAffect,
|
||||||
|
N_DeviseCompte
|
||||||
|
FROM P_DOSSIER
|
||||||
|
""")
|
||||||
|
|
||||||
|
row = cursor.fetchone()
|
||||||
|
if row:
|
||||||
|
return {
|
||||||
|
"tva_encaissement_regime": row[0] or 0,
|
||||||
|
"tva_encaissement_affectation": row[1] or 0,
|
||||||
|
"tva_encaissement_actif": (row[0] or 0) > 0,
|
||||||
|
"devise_compte": row[2] or 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"tva_encaissement_regime": 0,
|
||||||
|
"tva_encaissement_affectation": 0,
|
||||||
|
"tva_encaissement_actif": False,
|
||||||
|
"devise_compte": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"ModeReglement",
|
"ModeReglement",
|
||||||
"lire_journaux_banque",
|
"lire_journaux_banque",
|
||||||
|
|
@ -779,4 +1265,11 @@ __all__ = [
|
||||||
"regler_factures_client",
|
"regler_factures_client",
|
||||||
"lire_reglements_facture",
|
"lire_reglements_facture",
|
||||||
"lire_reglements_client",
|
"lire_reglements_client",
|
||||||
|
"lire_modes_reglement",
|
||||||
|
"lire_devises",
|
||||||
|
"lire_journaux_tresorerie",
|
||||||
|
"lire_comptes_generaux",
|
||||||
|
"lire_tva_taux",
|
||||||
|
"lire_parametres_encaissement",
|
||||||
|
"_get_modes_reglement_standards",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue