feat(pdf): add dynamic company info to PDF generator
This commit is contained in:
parent
08665f15dd
commit
3f1dce918d
1 changed files with 159 additions and 22 deletions
181
email_queue.py
181
email_queue.py
|
|
@ -20,7 +20,6 @@ from io import BytesIO
|
|||
from reportlab.lib.units import mm
|
||||
from reportlab.lib.colors import HexColor, Color
|
||||
from PIL import Image
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -82,6 +81,8 @@ async def execute_with_retry(
|
|||
base_delay: float = 0.1,
|
||||
max_delay: float = 2.0,
|
||||
):
|
||||
from sqlalchemy.exc import OperationalError
|
||||
|
||||
last_exception = None
|
||||
|
||||
for attempt in range(max_retries):
|
||||
|
|
@ -106,7 +107,7 @@ async def execute_with_retry(
|
|||
else:
|
||||
# Autre erreur OperationalError, ne pas retry
|
||||
raise
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
# Autres exceptions, ne pas retry
|
||||
raise
|
||||
|
||||
|
|
@ -372,8 +373,18 @@ class EmailQueue:
|
|||
if not doc:
|
||||
raise Exception(f"Document {doc_id} introuvable")
|
||||
|
||||
# Récupérer les informations de la société émettrice
|
||||
societe_info = None
|
||||
try:
|
||||
societe_info = self.sage_client.lire_informations_societe()
|
||||
logger.debug(
|
||||
f"Infos société récupérées: {societe_info.raison_sociale if societe_info else 'N/A'}"
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(f"Impossible de récupérer les infos société: {e}")
|
||||
|
||||
# Générer le PDF avec le nouveau générateur
|
||||
generator = SagePDFGenerator(doc, type_doc)
|
||||
generator = SagePDFGenerator(doc, type_doc, societe_info=societe_info)
|
||||
return generator.generate()
|
||||
|
||||
|
||||
|
|
@ -392,10 +403,11 @@ class SagePDFGenerator:
|
|||
GRAY_800 = HexColor("#1F2937")
|
||||
GRAY_900 = HexColor("#111827")
|
||||
|
||||
COMPANY_NAME = "Bijou S.A.S"
|
||||
COMPANY_ADDRESS_1 = "123 Avenue de la République"
|
||||
COMPANY_ADDRESS_2 = "75011 Paris, France"
|
||||
COMPANY_EMAIL = "contact@bijou.com"
|
||||
# Valeurs par défaut (fallback si société non disponible)
|
||||
DEFAULT_COMPANY_NAME = "Entreprise"
|
||||
DEFAULT_COMPANY_ADDRESS = ""
|
||||
DEFAULT_COMPANY_CITY = ""
|
||||
DEFAULT_COMPANY_EMAIL = ""
|
||||
|
||||
# Labels des types de documents
|
||||
TYPE_LABELS = {
|
||||
|
|
@ -406,10 +418,11 @@ class SagePDFGenerator:
|
|||
60: "Facture",
|
||||
}
|
||||
|
||||
def __init__(self, doc_data: dict, type_doc: int):
|
||||
def __init__(self, doc_data: dict, type_doc: int, societe_info=None):
|
||||
self.doc = doc_data
|
||||
self.type_doc = type_doc
|
||||
self.type_label = self.TYPE_LABELS.get(type_doc, "Document")
|
||||
self.societe_info = societe_info
|
||||
|
||||
# Configuration de la page
|
||||
self.page_width, self.page_height = A4
|
||||
|
|
@ -427,6 +440,64 @@ class SagePDFGenerator:
|
|||
_register_sage_font()
|
||||
self.use_sage_font = _sage_font_registered
|
||||
|
||||
def _get_societe_field(self, field: str, default: str = "") -> str:
|
||||
"""Récupère un champ de la société avec fallback."""
|
||||
if self.societe_info is None:
|
||||
return default
|
||||
return getattr(self.societe_info, field, default) or default
|
||||
|
||||
def _get_societe_name(self) -> str:
|
||||
"""Retourne la raison sociale de la société."""
|
||||
return self._get_societe_field("raison_sociale", self.DEFAULT_COMPANY_NAME)
|
||||
|
||||
def _get_societe_address_line1(self) -> str:
|
||||
"""Retourne la première ligne d'adresse."""
|
||||
adresse = self._get_societe_field("adresse", "")
|
||||
complement = self._get_societe_field("complement_adresse", "")
|
||||
|
||||
if adresse and complement:
|
||||
return f"{adresse}, {complement}"
|
||||
return adresse or complement or self.DEFAULT_COMPANY_ADDRESS
|
||||
|
||||
def _get_societe_address_line2(self) -> str:
|
||||
"""Retourne la deuxième ligne d'adresse (CP + Ville + Pays)."""
|
||||
cp = self._get_societe_field("code_postal", "")
|
||||
ville = self._get_societe_field("ville", "")
|
||||
pays = self._get_societe_field("pays", "")
|
||||
|
||||
parts = []
|
||||
if cp:
|
||||
parts.append(cp)
|
||||
if ville:
|
||||
parts.append(ville)
|
||||
|
||||
city_line = " ".join(parts)
|
||||
|
||||
if pays and pays.lower() not in ["france", "fr"]:
|
||||
city_line = f"{city_line}, {pays}" if city_line else pays
|
||||
|
||||
return city_line or self.DEFAULT_COMPANY_CITY
|
||||
|
||||
def _get_societe_email(self) -> str:
|
||||
"""Retourne l'email de la société."""
|
||||
# Priorité à email_societe, puis email
|
||||
email = self._get_societe_field("email_societe", "")
|
||||
if not email:
|
||||
email = self._get_societe_field("email", "")
|
||||
return email or self.DEFAULT_COMPANY_EMAIL
|
||||
|
||||
def _get_societe_phone(self) -> str:
|
||||
"""Retourne le téléphone de la société."""
|
||||
return self._get_societe_field("telephone", "")
|
||||
|
||||
def _get_societe_siret(self) -> str:
|
||||
"""Retourne le SIRET de la société."""
|
||||
return self._get_societe_field("siret", "")
|
||||
|
||||
def _get_societe_tva(self) -> str:
|
||||
"""Retourne le numéro de TVA de la société."""
|
||||
return self._get_societe_field("numero_tva", "")
|
||||
|
||||
def _get_font(self, bold: bool = False) -> str:
|
||||
"""Retourne le nom de la police à utiliser."""
|
||||
if self.use_sage_font:
|
||||
|
|
@ -563,31 +634,57 @@ class SagePDFGenerator:
|
|||
col1_x, y, "ÉMETTEUR", font_size=8, bold=True, color=self.GRAY_400
|
||||
)
|
||||
|
||||
# === INFORMATIONS SOCIÉTÉ (dynamiques) ===
|
||||
y_emetteur = y - 6 * mm
|
||||
self._draw_text(
|
||||
col1_x,
|
||||
y_emetteur,
|
||||
self.COMPANY_NAME,
|
||||
self._get_societe_name(),
|
||||
font_size=10,
|
||||
bold=True,
|
||||
color=self.GRAY_800,
|
||||
)
|
||||
|
||||
y_emetteur -= 5 * mm
|
||||
self._draw_text(
|
||||
col1_x, y_emetteur, self.COMPANY_ADDRESS_1, font_size=9, color=self.GRAY_600
|
||||
)
|
||||
# Adresse ligne 1
|
||||
address_line1 = self._get_societe_address_line1()
|
||||
if address_line1:
|
||||
y_emetteur -= 5 * mm
|
||||
# Tronquer si trop long
|
||||
if len(address_line1) > 45:
|
||||
address_line1 = address_line1[:42] + "..."
|
||||
self._draw_text(
|
||||
col1_x, y_emetteur, address_line1, font_size=9, color=self.GRAY_600
|
||||
)
|
||||
|
||||
y_emetteur -= 4 * mm
|
||||
self._draw_text(
|
||||
col1_x, y_emetteur, self.COMPANY_ADDRESS_2, font_size=9, color=self.GRAY_600
|
||||
)
|
||||
# Adresse ligne 2 (CP + Ville)
|
||||
address_line2 = self._get_societe_address_line2()
|
||||
if address_line2:
|
||||
y_emetteur -= 4 * mm
|
||||
self._draw_text(
|
||||
col1_x, y_emetteur, address_line2, font_size=9, color=self.GRAY_600
|
||||
)
|
||||
|
||||
y_emetteur -= 5 * mm
|
||||
self._draw_text(
|
||||
col1_x, y_emetteur, self.COMPANY_EMAIL, font_size=9, color=self.GRAY_600
|
||||
)
|
||||
# Email
|
||||
societe_email = self._get_societe_email()
|
||||
if societe_email:
|
||||
y_emetteur -= 5 * mm
|
||||
self._draw_text(
|
||||
col1_x, y_emetteur, societe_email, font_size=9, color=self.GRAY_600
|
||||
)
|
||||
|
||||
# Téléphone (optionnel)
|
||||
societe_phone = self._get_societe_phone()
|
||||
if societe_phone:
|
||||
y_emetteur -= 4 * mm
|
||||
self._draw_text(
|
||||
col1_x,
|
||||
y_emetteur,
|
||||
f"Tél: {societe_phone}",
|
||||
font_size=8,
|
||||
color=self.GRAY_500,
|
||||
)
|
||||
|
||||
# === DESTINATAIRE ===
|
||||
box_padding = 4 * mm
|
||||
box_height = 26 * mm
|
||||
box_y = y - 3 * mm
|
||||
|
|
@ -912,8 +1009,48 @@ class SagePDFGenerator:
|
|||
return y
|
||||
|
||||
def _draw_footer(self):
|
||||
footer_y = 12 * mm
|
||||
footer_y = 15 * mm
|
||||
|
||||
# Informations légales de la société
|
||||
legal_parts = []
|
||||
|
||||
societe_name = self._get_societe_name()
|
||||
if societe_name and societe_name != self.DEFAULT_COMPANY_NAME:
|
||||
legal_parts.append(societe_name)
|
||||
|
||||
siret = self._get_societe_siret()
|
||||
if siret:
|
||||
legal_parts.append(f"SIRET: {siret}")
|
||||
|
||||
tva = self._get_societe_tva()
|
||||
if tva:
|
||||
legal_parts.append(f"TVA: {tva}")
|
||||
|
||||
# Forme juridique et capital si disponibles
|
||||
if self.societe_info:
|
||||
forme = self._get_societe_field("forme_juridique", "")
|
||||
capital = getattr(self.societe_info, "capital", 0)
|
||||
if forme and capital > 0:
|
||||
legal_parts.append(
|
||||
f"{forme} au capital de {capital:,.0f} €".replace(",", " ")
|
||||
)
|
||||
|
||||
# Dessiner les informations légales
|
||||
if legal_parts:
|
||||
legal_text = " • ".join(legal_parts)
|
||||
# Tronquer si trop long
|
||||
if len(legal_text) > 100:
|
||||
legal_text = legal_text[:97] + "..."
|
||||
self._draw_text(
|
||||
self.page_width / 2,
|
||||
footer_y + 4 * mm,
|
||||
legal_text,
|
||||
font_size=7,
|
||||
color=self.GRAY_400,
|
||||
align="center",
|
||||
)
|
||||
|
||||
# Pagination
|
||||
page_text = f"Page {self.page_number} / {self.total_pages}"
|
||||
self._draw_text(
|
||||
self.page_width / 2,
|
||||
|
|
|
|||
Loading…
Reference in a new issue