# /home/Autopartes/pos/services/pdf_generator.py """Generate printable HTML for quotations (browser print-to-PDF). Returns self-contained HTML with @media print CSS for clean PDF output. No external dependencies required — uses the browser's built-in print. """ from datetime import datetime def generate_quote_html(quotation, items, business_info=None, customer_info=None): """Generate printable HTML for a quotation. Args: quotation: dict with keys: id, subtotal, tax_total, total, valid_until, created_at, notes, employee_name items: list of dicts: part_number, name, quantity, unit_price, discount_pct, tax_rate, subtotal business_info: dict with keys: name, rfc, address, phone, email (optional) customer_info: dict with keys: name, rfc, phone, email (optional) Returns: str: Complete HTML document ready for printing """ biz = business_info or {} biz_name = biz.get('name', 'Autopartes Nexus') biz_rfc = biz.get('rfc', '') biz_address = biz.get('address', '') biz_phone = biz.get('phone', '') biz_email = biz.get('email', '') cust = customer_info or {} cust_name = cust.get('name', 'Publico en General') cust_rfc = cust.get('rfc', 'XAXX010101000') cust_phone = cust.get('phone', '') cust_email = cust.get('email', '') quot_id = quotation.get('id', 0) created = quotation.get('created_at', '') valid_until = quotation.get('valid_until', '') notes = quotation.get('notes', '') employee_name = quotation.get('employee_name', '') subtotal = float(quotation.get('subtotal', 0)) tax_total = float(quotation.get('tax_total', 0)) total = float(quotation.get('total', 0)) # Build items rows items_html = '' for i, item in enumerate(items, 1): qty = item.get('quantity', 1) price = float(item.get('unit_price', 0)) disc = float(item.get('discount_pct', 0)) line_sub = float(item.get('subtotal', qty * price)) pn = item.get('part_number', '') name = item.get('name', '') disc_str = f'{disc:.0f}%' if disc > 0 else '-' items_html += f""" {i} {qty} {pn} {name} ${price:,.2f} {disc_str} ${line_sub:,.2f} """ try: created_fmt = datetime.fromisoformat(str(created).replace('Z', '+00:00')).strftime('%d/%m/%Y %H:%M') except Exception: created_fmt = str(created)[:16] if created else '' try: valid_fmt = datetime.fromisoformat(str(valid_until)).strftime('%d/%m/%Y') except Exception: valid_fmt = str(valid_until)[:10] if valid_until else '' return f""" Cotizacion #{quot_id}

{biz_name}

{f'RFC: {biz_rfc}
' if biz_rfc else ''} {f'{biz_address}
' if biz_address else ''} {f'Tel: {biz_phone}
' if biz_phone else ''} {f'{biz_email}' if biz_email else ''}
COTIZACION #{quot_id}
Fecha: {created_fmt}
{f'Vendedor: {employee_name}' if employee_name else ''}

Cliente

{cust_name}

{f'

RFC: {cust_rfc}

' if cust_rfc else ''} {f'

Tel: {cust_phone}

' if cust_phone else ''} {f'

{cust_email}

' if cust_email else ''}
{items_html}
# Cant No. Parte Descripcion P. Unit. Desc. Subtotal
Subtotal:${subtotal:,.2f}
IVA (16%):${tax_total:,.2f}
TOTAL:${total:,.2f} MXN
"""