diff --git a/email_queue.py b/email_queue.py index 16b2fcc..1d59593 100644 --- a/email_queue.py +++ b/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,