diff --git a/.claude/scheduled_tasks.lock b/.claude/scheduled_tasks.lock new file mode 100644 index 00000000..69489df0 --- /dev/null +++ b/.claude/scheduled_tasks.lock @@ -0,0 +1 @@ +{"sessionId":"995b3836-6e56-40fa-aec9-e8cfae013a0b","pid":70631,"acquiredAt":1776733239341} \ No newline at end of file diff --git a/fusion_reports_templates/__init__.py b/fusion_reports_templates/__init__.py new file mode 100644 index 00000000..0650744f --- /dev/null +++ b/fusion_reports_templates/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/fusion_reports_templates/__manifest__.py b/fusion_reports_templates/__manifest__.py new file mode 100644 index 00000000..7207558d --- /dev/null +++ b/fusion_reports_templates/__manifest__.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 (Odoo Proprietary License v1.0) +{ + 'name': 'Fusion Reports — Templates', + 'version': '19.0.1.0.0', + 'category': 'Tools/Reports', + 'summary': 'Branded PDF templates for Quotation, Sales Order, Invoice, Delivery, Purchase Order, and Payment Receipt.', + 'description': """ +Fusion Reports Templates +======================== +Replaces Odoo's default PDF layouts for the customer-facing quote-to-cash +documents with a consistent NEXA Systems branded design. The customer-facing +mail templates are redirected to the new reports so emails always send the +branded PDF, not the stock Odoo one. + +Reports included (each in portrait + landscape): + * Quotation / Sales Order + * Customer Invoice / Credit Note + * Delivery / Packing Slip + * Purchase Order / RFQ + * Payment Receipt +""", + 'author': 'Nexa Systems Inc.', + 'website': 'https://nexasystems.ca', + 'depends': [ + 'sale', + 'account', + 'stock', + 'purchase', + ], + 'data': [ + 'security/ir.model.access.csv', + 'report/report_base_styles.xml', + 'report/report_actions.xml', + 'report/report_sale.xml', + 'report/report_invoice.xml', + 'report/report_delivery.xml', + 'report/report_purchase.xml', + 'report/report_receipt.xml', + 'data/mail_template_override.xml', + 'data/hide_default_reports.xml', + ], + 'installable': True, + 'application': False, + 'auto_install': False, + 'license': 'OPL-1', +} diff --git a/fusion_reports_templates/data/hide_default_reports.xml b/fusion_reports_templates/data/hide_default_reports.xml new file mode 100644 index 00000000..c75cd7a2 --- /dev/null +++ b/fusion_reports_templates/data/hide_default_reports.xml @@ -0,0 +1,96 @@ + + + + + + + + action + + + + + + action + + + + action + + + + + + action + + + + + + action + + + + action + + + + + + action + + + + + + action + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fusion_reports_templates/data/mail_template_override.xml b/fusion_reports_templates/data/mail_template_override.xml new file mode 100644 index 00000000..f925ed2c --- /dev/null +++ b/fusion_reports_templates/data/mail_template_override.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/fusion_reports_templates/models/__init__.py b/fusion_reports_templates/models/__init__.py new file mode 100644 index 00000000..a248cf21 --- /dev/null +++ b/fusion_reports_templates/models/__init__.py @@ -0,0 +1 @@ +from . import ir_actions_report diff --git a/fusion_reports_templates/models/ir_actions_report.py b/fusion_reports_templates/models/ir_actions_report.py new file mode 100644 index 00000000..16be4d7b --- /dev/null +++ b/fusion_reports_templates/models/ir_actions_report.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 (Odoo Proprietary License v1.0) +"""Sort the Print-menu report bindings by `sequence`. + +Odoo 19 returns `ir.actions.report` bindings in raw insertion order, which +pushes third-party reports to the bottom even when they are the primary +customer-facing document. Adding a sequence field and sorting inside +`ir.actions.actions._get_bindings` restores the expected ordering. +""" +from odoo import api, fields, models +from odoo.tools import frozendict + + +class IrActionsReport(models.Model): + _inherit = 'ir.actions.report' + + sequence = fields.Integer( + default=100, + help='Order in which this report appears in the Print menu ' + '(lower = higher in the list).', + ) + + +class IrActionsActions(models.Model): + _inherit = 'ir.actions.actions' + + @api.model + def _get_bindings(self, model_name): + result = super()._get_bindings(model_name) + if not result.get('report'): + return result + sorted_reports = tuple(sorted( + result['report'], + key=lambda vals: ( + vals.get('sequence', 100), + (vals.get('name') or '').lower(), + ), + )) + new_result = dict(result) + new_result['report'] = sorted_reports + return frozendict(new_result) diff --git a/fusion_reports_templates/report/report_actions.xml b/fusion_reports_templates/report/report_actions.xml new file mode 100644 index 00000000..36af3940 --- /dev/null +++ b/fusion_reports_templates/report/report_actions.xml @@ -0,0 +1,139 @@ + + + + + + + + + Quotation / Order (Portrait) + sale.order + qweb-pdf + fusion_reports_templates.report_fr_sale_portrait + fusion_reports_templates.report_fr_sale_portrait + (object.state in ('draft', 'sent') and 'Quotation - %s' % object.name) or 'Order - %s' % object.name + + report + + + + Quotation / Order (Landscape) + sale.order + qweb-pdf + fusion_reports_templates.report_fr_sale_landscape + fusion_reports_templates.report_fr_sale_landscape + (object.state in ('draft', 'sent') and 'Quotation - %s' % object.name) or 'Order - %s' % object.name + + report + + + + + + + + Invoice (Portrait) + account.move + qweb-pdf + fusion_reports_templates.report_fr_invoice_portrait + fusion_reports_templates.report_fr_invoice_portrait + 'Invoice - %s' % (object.name or '') + + report + + + + Invoice (Landscape) + account.move + qweb-pdf + fusion_reports_templates.report_fr_invoice_landscape + fusion_reports_templates.report_fr_invoice_landscape + 'Invoice - %s' % (object.name or '') + + report + + + + + + + + Delivery Slip (Portrait) + stock.picking + qweb-pdf + fusion_reports_templates.report_fr_delivery_portrait + fusion_reports_templates.report_fr_delivery_portrait + 'Delivery - %s' % object.name + + report + + + + Delivery Slip (Landscape) + stock.picking + qweb-pdf + fusion_reports_templates.report_fr_delivery_landscape + fusion_reports_templates.report_fr_delivery_landscape + 'Delivery - %s' % object.name + + report + + + + + + + + Purchase Order (Portrait) + purchase.order + qweb-pdf + fusion_reports_templates.report_fr_purchase_portrait + fusion_reports_templates.report_fr_purchase_portrait + (object.state in ('draft', 'sent', 'to approve') and 'RFQ - %s' % object.name) or 'PO - %s' % object.name + + report + + + + Purchase Order (Landscape) + purchase.order + qweb-pdf + fusion_reports_templates.report_fr_purchase_landscape + fusion_reports_templates.report_fr_purchase_landscape + (object.state in ('draft', 'sent', 'to approve') and 'RFQ - %s' % object.name) or 'PO - %s' % object.name + + report + + + + + + + + Payment Receipt (Portrait) + account.payment + qweb-pdf + fusion_reports_templates.report_fr_receipt_portrait + fusion_reports_templates.report_fr_receipt_portrait + 'Receipt - %s' % (object.name or '') + + report + + + + Payment Receipt (Landscape) + account.payment + qweb-pdf + fusion_reports_templates.report_fr_receipt_landscape + fusion_reports_templates.report_fr_receipt_landscape + 'Receipt - %s' % (object.name or '') + + report + + + + diff --git a/fusion_reports_templates/report/report_base_styles.xml b/fusion_reports_templates/report/report_base_styles.xml new file mode 100644 index 00000000..28ee19c6 --- /dev/null +++ b/fusion_reports_templates/report/report_base_styles.xml @@ -0,0 +1,105 @@ + + + + + + + + + A4 Landscape (Fusion Reports) + + A4 + Landscape + 20 + 20 + 7 + 7 + + 20 + 90 + + + + + + + + + + + + + diff --git a/fusion_reports_templates/report/report_delivery.xml b/fusion_reports_templates/report/report_delivery.xml new file mode 100644 index 00000000..c074389a --- /dev/null +++ b/fusion_reports_templates/report/report_delivery.xml @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + diff --git a/fusion_reports_templates/report/report_invoice.xml b/fusion_reports_templates/report/report_invoice.xml new file mode 100644 index 00000000..244747fd --- /dev/null +++ b/fusion_reports_templates/report/report_invoice.xml @@ -0,0 +1,359 @@ + + + + + + + + + + + + + + + diff --git a/fusion_reports_templates/report/report_purchase.xml b/fusion_reports_templates/report/report_purchase.xml new file mode 100644 index 00000000..14148a24 --- /dev/null +++ b/fusion_reports_templates/report/report_purchase.xml @@ -0,0 +1,317 @@ + + + + + + + + + + + + + + + diff --git a/fusion_reports_templates/report/report_receipt.xml b/fusion_reports_templates/report/report_receipt.xml new file mode 100644 index 00000000..b429204a --- /dev/null +++ b/fusion_reports_templates/report/report_receipt.xml @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + diff --git a/fusion_reports_templates/report/report_sale.xml b/fusion_reports_templates/report/report_sale.xml new file mode 100644 index 00000000..8f008d8e --- /dev/null +++ b/fusion_reports_templates/report/report_sale.xml @@ -0,0 +1,355 @@ + + + + + + + + + + + + + + + diff --git a/fusion_reports_templates/security/ir.model.access.csv b/fusion_reports_templates/security/ir.model.access.csv new file mode 100644 index 00000000..97dd8b91 --- /dev/null +++ b/fusion_reports_templates/security/ir.model.access.csv @@ -0,0 +1 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink