""" Create / update the custom Print Format "Facture TARGO" on ERPNext. Design ------ - Letter-size, #10 envelope-window compatible - 2-column layout: left = client + per-location charges, right = summary + QR - Items grouped by Sales Invoice Item.service_location (Link → Service Location). Identical (name, rate) rows within a location are consolidated with a "(xN)" suffix, matching the reference preview. - QR code is embedded as base64 data URI via the whitelisted method `gigafibre_utils.api.invoice_qr_base64`. Depends on the custom app `gigafibre_utils` being installed on the bench (see /opt/erpnext/custom/ on the ERPNext host). wkhtmltopdf does NOT fetch the QR over HTTP. - SVG logo paths use inline `fill="#019547"` (wkhtmltopdf / QtWebKit does not honour `
{% if prev_invoice_date and prev_invoice_date != '—' %}
{% if _is_en %}ACCOUNT SUMMARY{% else %}SOMMAIRE DU COMPTE{% endif %}
{% for payment in recent_payments %} {% endfor %}
{% if _is_en %}Previous balance{% else %}Solde précédent{% endif %} ({{ prev_invoice_date }}) $ {{ prev_invoice_total }}
{% if _is_en %}Payment received — thank you{% else %}Paiement reçu — merci{% endif %}− $ {{ payment.amount }}
{% if _is_en %}Carried forward{% else %}Solde reporté{% endif %}$ {{ remaining_balance }}
{% endif %}
{% if _is_en %}Bill to{% else %}Facturer à{% endif %}
{{ client_name }}
{{ client_address_line1 }}
{{ client_address_line2 }}
{% if _is_en %}CURRENT CHARGES{% else %}FRAIS COURANTS{% endif %}
{% for location in current_charges_locations %} {#- Collect distinct non-empty periods from this location's items. If they're all the same, show once in the address header. If they differ (rare), append to each item's description as before. -#} {%- set _periods = [] -%} {%- for _it in location['items'] -%} {%- if _it.period_str and _it.period_str not in _periods -%} {%- set _ = _periods.append(_it.period_str) -%} {%- endif -%} {%- endfor -%}
◎ {{ location.name }}{% if _periods|length == 1 %} · {{ _periods[0] }}{% endif %}
{% for item in location['items'] %} {% endfor %}
{{ item.description }}{% if _periods|length > 1 and item.period_str %} ({{ item.period_str }}){% endif %}{% if item.qty and item.qty|string not in ('1', '1.0') %} (×{{ item.qty }}){% endif %} {{ item.amount }}
{% endfor %}
{% if _is_en %}Subtotal before tax{% else %}Sous-total avant taxes{% endif %}$ {{ subtotal_before_taxes }}
{% if _is_en %}Tax: GST ${{ tps_amount }} · QST ${{ tvq_amount }}{% else %}Taxes : TPS ${{ tps_amount }} · TVQ ${{ tvq_amount }}{% endif %}$ {{ total_taxes }}
TOTAL$ {{ current_charges_total }}
TPS: 834975559RT0001  |  TVQ: 1213765929TQ0001
{{ doc_title }}
{% if _is_en %}Invoice #{% else %}Nº facture{% endif %}{{ invoice_number }}
Date{{ invoice_date }}
{% if _is_en %}Account #{% else %}Nº compte{% endif %}{{ account_number }}
{% if _is_en %}Amount due{% else %}Montant dû{% endif %}
{% if _is_en %}before{% else %}avant le{% endif %} {{ due_date }}
$ {{ total_amount_due }}
{% if qr_code_base64 %} {% else %}
QR
{% endif %}
{% if _is_en %}Pay online{% else %}Payez en ligne{% endif %}
{% if _is_en %}Scan the QR code or visit{% else %}Scannez le code QR ou visitez{% endif %}
client.gigafibre.ca
{% if _is_en %} Refer a friend and each receive $50 credit on your monthly bill · targo.ca/parrainage {% else %} Référez un ami et recevez chacun 50 $ de crédit sur votre facture mensuelle · targo.ca/parrainage {% endif %}
{% if _is_en %}Your code{% else %}Votre code{% endif %} {{ referral_code }}
{% if _is_en %} By paying this invoice, you accept our terms and conditions.

Please note that any invoice not paid by the due date will be subject to a late payment fee. {% else %} En payant cette facture, vous acceptez nos termes et conditions.

Prendre note que toute facture non acquittée à la date d'échéance sera assujettie à des frais de retard. {% endif %}
{% if _is_en %}Contact us{% else %}Contactez-nous{% endif %}
TARGO Communications Inc.
1867 chemin de la Rivière
Sainte-Clotilde, QC J0L 1W0
855 888-2746 · {% if _is_en %}Mon-Fri 8am-5pm{% else %}Lun-Ven 8h-17h{% endif %}
info@targo.ca • www.targo.ca
{% if _is_en %} Complaint about your telecom or TV service? The CCTS can help you for free: www.ccts-cprst.ca. {% else %} Plainte relative à votre service de télécommunication ou de télévision? La CPRST peut vous aider sans frais : www.ccts-cprst.ca. {% endif %}
""" # Print Format options shared between create/update paths. pdf_generator="chrome" # uses Chromium headless for pixel-accurate modern-CSS rendering (matches the # Antigravity / browser preview). Chromium must be installed in the container; # see /opt/erpnext/custom/Dockerfile (apt-get install chromium) and # common_site_config.json → "chromium_path": "/usr/bin/chromium". # # Margins are explicit — Chrome PDF generator IGNORES `@page { margin: … }` # in the CSS (preferCSSPageSize=False). We keep 5mm top/bottom so the client # address stays aligned with the #10 envelope window (~2" from top edge). _PF_OPTIONS = { "print_format_type": "Jinja", "standard": "No", "custom_format": 1, "pdf_generator": "chrome", "margin_top": 5, "margin_bottom": 5, "margin_left": 15, "margin_right": 15, "disabled": 0, } # ── Create or update the Print Format ── if frappe.db.exists("Print Format", PRINT_FORMAT_NAME): pf = frappe.get_doc("Print Format", PRINT_FORMAT_NAME) pf.html = html_template for k, v in _PF_OPTIONS.items(): setattr(pf, k, v) pf.save(ignore_permissions=True) print(f" Updated Print Format: {PRINT_FORMAT_NAME} ({len(html_template)} bytes)") else: pf = frappe.get_doc({ "doctype": "Print Format", "name": PRINT_FORMAT_NAME, "__newname": PRINT_FORMAT_NAME, "doc_type": "Sales Invoice", "module": "Accounts", **_PF_OPTIONS, "html": html_template, "default_print_language": "fr", }) pf.insert(ignore_permissions=True) print(f" Created Print Format: {PRINT_FORMAT_NAME} ({len(html_template)} bytes)") # ── Set as default print format for Sales Invoice ── try: frappe.db.set_value( "Property Setter", None, "value", PRINT_FORMAT_NAME, { "doctype_or_field": "DocType", "doc_type": "Sales Invoice", "property": "default_print_format", }, ) except Exception as e: print(f" (info) could not set default print format: {e}") # ── Disable the legacy Server Script "invoice_qr_code" if still around ── # QR generation now lives in the custom app `gigafibre_utils` (whitelisted # method `gigafibre_utils.api.invoice_qr_base64`). The old Server Script # crashed under safe_exec because it tried `import qrcode`. if frappe.db.exists("Server Script", "invoice_qr_code"): ss = frappe.get_doc("Server Script", "invoice_qr_code") if not ss.disabled: ss.disabled = 1 ss.save(ignore_permissions=True) print(" Disabled legacy Server Script: invoice_qr_code " "(superseded by gigafibre_utils.api.invoice_qr_base64)") frappe.db.commit() print(f"\n Done. Print Format '{PRINT_FORMAT_NAME}' ready.") print(" Dependency: custom app `gigafibre_utils` must be installed " "(bench --site erp.gigafibre.ca install-app gigafibre_utils).") print(" Preview: ERPNext → Sales Invoice → Print → Select 'Facture TARGO'")