feat(payments): enhance payment processing with new endpoints and schema
This commit is contained in:
parent
457c746706
commit
beabefa3f9
3 changed files with 192 additions and 36 deletions
104
api.py
104
api.py
|
|
@ -3037,19 +3037,25 @@ async def regler_facture(
|
|||
try:
|
||||
resultat = sage_client.regler_facture(
|
||||
numero_facture=numero_facture,
|
||||
montant=reglement.montant,
|
||||
montant=float(reglement.montant),
|
||||
mode_reglement=reglement.mode_reglement,
|
||||
code_journal=reglement.code_journal,
|
||||
date_reglement=reglement.date_reglement.isoformat()
|
||||
if reglement.date_reglement
|
||||
else None,
|
||||
reference=reglement.reference or "",
|
||||
libelle=reglement.libelle or "",
|
||||
code_journal=reglement.code_journal,
|
||||
devise_code=reglement.devise_code,
|
||||
cours_devise=float(reglement.cours_devise)
|
||||
if reglement.cours_devise
|
||||
else 1.0,
|
||||
tva_encaissement=reglement.tva_encaissement,
|
||||
compte_general=reglement.compte_general,
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Règlement facture {numero_facture}: {reglement.montant}€ - "
|
||||
f"Solde: {resultat.get('solde_restant', 0)}€"
|
||||
f"Journal: {reglement.code_journal} - Mode: {reglement.mode_reglement}"
|
||||
)
|
||||
|
||||
return {
|
||||
|
|
@ -3150,24 +3156,6 @@ async def get_reglements_client(
|
|||
raise HTTPException(500, str(e))
|
||||
|
||||
|
||||
@app.get("/reglements/modes", tags=["Règlements"])
|
||||
async def get_modes_reglement():
|
||||
return {
|
||||
"success": True,
|
||||
"data": {
|
||||
"modes": [
|
||||
{"code": 1, "libelle": "Virement"},
|
||||
{"code": 2, "libelle": "Chèque"},
|
||||
{"code": 3, "libelle": "Traite"},
|
||||
{"code": 4, "libelle": "Carte bancaire"},
|
||||
{"code": 5, "libelle": "LCR"},
|
||||
{"code": 6, "libelle": "Prélèvement"},
|
||||
{"code": 7, "libelle": "Espèces"},
|
||||
]
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@app.get("/journaux/banque", tags=["Règlements"])
|
||||
async def get_journaux_banque():
|
||||
try:
|
||||
|
|
@ -3178,6 +3166,80 @@ async def get_journaux_banque():
|
|||
raise HTTPException(500, str(e))
|
||||
|
||||
|
||||
@app.get("/reglements/modes", tags=["Référentiels"])
|
||||
async def get_modes_reglement():
|
||||
"""Liste des modes de règlement disponibles dans Sage"""
|
||||
try:
|
||||
modes = sage_client.get_modes_reglement()
|
||||
return {"success": True, "data": {"modes": modes}}
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lecture modes règlement: {e}")
|
||||
raise HTTPException(500, str(e))
|
||||
|
||||
|
||||
@app.get("/devises", tags=["Référentiels"])
|
||||
async def get_devises():
|
||||
"""Liste des devises disponibles dans Sage"""
|
||||
try:
|
||||
devises = sage_client.get_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("/journaux/tresorerie", tags=["Référentiels"])
|
||||
async def get_journaux_tresorerie():
|
||||
"""Liste des journaux de trésorerie (banque + caisse)"""
|
||||
try:
|
||||
journaux = sage_client.get_journaux_tresorerie()
|
||||
return {"success": True, "data": {"journaux": journaux}}
|
||||
except Exception as e:
|
||||
logger.error(f"Erreur lecture journaux: {e}")
|
||||
raise HTTPException(500, str(e))
|
||||
|
||||
|
||||
@app.get("/comptes-generaux", tags=["Référentiels"])
|
||||
async def get_comptes_generaux(
|
||||
prefixe: Optional[str] = Query(None, description="Filtre par préfixe"),
|
||||
type_compte: Optional[str] = Query(
|
||||
None,
|
||||
description="client | fournisseur | banque | caisse | tva | produit | charge",
|
||||
),
|
||||
):
|
||||
"""Liste des comptes généraux"""
|
||||
try:
|
||||
comptes = sage_client.get_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("/tva/taux", tags=["Référentiels"])
|
||||
async def get_tva_taux():
|
||||
"""Liste des taux de TVA"""
|
||||
try:
|
||||
taux = sage_client.get_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("/parametres/encaissement", tags=["Référentiels"])
|
||||
async def get_parametres_encaissement():
|
||||
"""Paramètres TVA sur encaissement"""
|
||||
try:
|
||||
params = sage_client.get_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("/health", tags=["System"])
|
||||
async def health_check(
|
||||
sage: SageGatewayClient = Depends(get_sage_client_for_user),
|
||||
|
|
|
|||
|
|
@ -520,6 +520,50 @@ class SageGatewayClient:
|
|||
def get_journaux_banque(self) -> dict:
|
||||
return self._get("/sage/journaux/banque").get("data", {})
|
||||
|
||||
def get_modes_reglement(self) -> List[dict]:
|
||||
"""Récupère les modes de règlement depuis Sage"""
|
||||
return self._get("/sage/reglements/modes").get("data", {}).get("modes", [])
|
||||
|
||||
def get_devises(self) -> List[dict]:
|
||||
"""Récupère les devises disponibles"""
|
||||
return self._get("/sage/devises").get("data", {}).get("devises", [])
|
||||
|
||||
def get_journaux_tresorerie(self) -> List[dict]:
|
||||
"""Récupère les journaux de trésorerie (banque + caisse)"""
|
||||
return (
|
||||
self._get("/sage/journaux/tresorerie").get("data", {}).get("journaux", [])
|
||||
)
|
||||
|
||||
def get_comptes_generaux(
|
||||
self, prefixe: str = None, type_compte: str = None
|
||||
) -> List[dict]:
|
||||
"""
|
||||
Récupère les comptes généraux
|
||||
|
||||
Args:
|
||||
prefixe: Filtre par préfixe (ex: "41", "51")
|
||||
type_compte: "client", "fournisseur", "banque", "caisse", "tva"
|
||||
"""
|
||||
params = {}
|
||||
if prefixe:
|
||||
params["prefixe"] = prefixe
|
||||
if type_compte:
|
||||
params["type_compte"] = type_compte
|
||||
|
||||
return (
|
||||
self._get("/sage/comptes-generaux", params=params)
|
||||
.get("data", {})
|
||||
.get("comptes", [])
|
||||
)
|
||||
|
||||
def get_tva_taux(self) -> List[dict]:
|
||||
"""Récupère les taux de TVA"""
|
||||
return self._get("/sage/tva/taux").get("data", {}).get("taux", [])
|
||||
|
||||
def get_parametres_encaissement(self) -> dict:
|
||||
"""Récupère les paramètres TVA sur encaissement"""
|
||||
return self._get("/sage/parametres/encaissement").get("data", {})
|
||||
|
||||
def refresh_cache(self) -> Dict:
|
||||
return self._post("/sage/cache/refresh")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,19 +1,46 @@
|
|||
from pydantic import BaseModel, Field, field_validator
|
||||
from typing import List, Optional
|
||||
from datetime import datetime
|
||||
import logging
|
||||
from decimal import Decimal
|
||||
from datetime import date
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ReglementFactureCreate(BaseModel):
|
||||
"""Requête de règlement d'une facture côté VPS"""
|
||||
|
||||
montant: float = Field(..., gt=0)
|
||||
mode_reglement: int = Field(default=2, ge=1, le=7)
|
||||
date_reglement: Optional[datetime] = None
|
||||
reference: Optional[str] = Field(default="", max_length=35)
|
||||
libelle: Optional[str] = Field(default="", max_length=69)
|
||||
code_journal: str = Field(default="BEU", max_length=6)
|
||||
# Montant et devise
|
||||
montant: Decimal = Field(..., gt=0, description="Montant à régler")
|
||||
devise_code: Optional[int] = Field(0, description="Code devise (0=EUR par défaut)")
|
||||
cours_devise: Optional[Decimal] = Field(1.0, description="Cours de la devise")
|
||||
|
||||
# Mode et journal
|
||||
mode_reglement: int = Field(
|
||||
..., ge=0, description="Code mode règlement depuis /reglements/modes"
|
||||
)
|
||||
code_journal: str = Field(
|
||||
..., min_length=1, description="Code journal depuis /journaux/tresorerie"
|
||||
)
|
||||
|
||||
# Dates
|
||||
date_reglement: Optional[date] = Field(
|
||||
None, description="Date du règlement (défaut: aujourd'hui)"
|
||||
)
|
||||
date_echeance: Optional[date] = Field(None, description="Date d'échéance")
|
||||
|
||||
# Références
|
||||
reference: Optional[str] = Field(
|
||||
"", max_length=17, description="Référence pièce règlement"
|
||||
)
|
||||
libelle: Optional[str] = Field(
|
||||
"", max_length=35, description="Libellé du règlement"
|
||||
)
|
||||
|
||||
# TVA sur encaissement
|
||||
tva_encaissement: Optional[bool] = Field(
|
||||
False, description="Appliquer TVA sur encaissement"
|
||||
)
|
||||
|
||||
@field_validator("montant")
|
||||
def validate_montant(cls, v):
|
||||
|
|
@ -28,6 +55,12 @@ class ReglementFactureCreate(BaseModel):
|
|||
"mode_reglement": 2,
|
||||
"reference": "CHQ-001",
|
||||
"code_journal": "BEU",
|
||||
"date_reglement": "2024-01-01",
|
||||
"libelle": "Règlement multiple",
|
||||
"tva_encaissement": False,
|
||||
"devise_code": 0,
|
||||
"cours_devise": 1.0,
|
||||
"date_echeance": "2024-01-31",
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -35,14 +68,23 @@ class ReglementFactureCreate(BaseModel):
|
|||
class ReglementMultipleCreate(BaseModel):
|
||||
"""Requête de règlement multiple côté VPS"""
|
||||
|
||||
client_id: str
|
||||
montant_total: float = Field(..., gt=0)
|
||||
mode_reglement: int = Field(default=2, ge=1, le=7)
|
||||
date_reglement: Optional[datetime] = None
|
||||
reference: Optional[str] = Field(default="", max_length=35)
|
||||
libelle: Optional[str] = Field(default="", max_length=69)
|
||||
code_journal: str = Field(default="BEU", max_length=6)
|
||||
numeros_factures: Optional[List[str]] = None
|
||||
client_id: str = Field(..., description="Code client")
|
||||
montant_total: Decimal = Field(..., gt=0)
|
||||
|
||||
# Même structure que ReglementFactureCreate
|
||||
devise_code: Optional[int] = Field(0)
|
||||
cours_devise: Optional[Decimal] = Field(1.0)
|
||||
mode_reglement: int = Field(...)
|
||||
code_journal: str = Field(...)
|
||||
date_reglement: Optional[date] = None
|
||||
reference: Optional[str] = Field("")
|
||||
libelle: Optional[str] = Field("")
|
||||
tva_encaissement: Optional[bool] = Field(False)
|
||||
|
||||
# Factures spécifiques (optionnel)
|
||||
numeros_factures: Optional[List[str]] = Field(
|
||||
None, description="Si vide, règle les plus anciennes en premier"
|
||||
)
|
||||
|
||||
@field_validator("client_id", mode="before")
|
||||
def strip_client_id(cls, v):
|
||||
|
|
@ -61,5 +103,13 @@ class ReglementMultipleCreate(BaseModel):
|
|||
"montant_total": 1000.00,
|
||||
"mode_reglement": 2,
|
||||
"numeros_factures": ["FA00081", "FA00082"],
|
||||
"reference": "CHQ-001",
|
||||
"code_journal": "BEU",
|
||||
"date_reglement": "2024-01-01",
|
||||
"libelle": "Règlement multiple",
|
||||
"tva_encaissement": False,
|
||||
"devise_code": 0,
|
||||
"cours_devise": 1.0,
|
||||
"date_echeance": "2024-01-31",
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue