diff --git a/fusion_plating/fusion_plating_jobs/__init__.py b/fusion_plating/fusion_plating_jobs/__init__.py index a0fdc10f..7db66946 100644 --- a/fusion_plating/fusion_plating_jobs/__init__.py +++ b/fusion_plating/fusion_plating_jobs/__init__.py @@ -1,2 +1,3 @@ # -*- coding: utf-8 -*- from . import models +from . import report diff --git a/fusion_plating/fusion_plating_jobs/__manifest__.py b/fusion_plating/fusion_plating_jobs/__manifest__.py index db9075d7..cc439664 100644 --- a/fusion_plating/fusion_plating_jobs/__manifest__.py +++ b/fusion_plating/fusion_plating_jobs/__manifest__.py @@ -3,7 +3,7 @@ # License OPL-1 (Odoo Proprietary License v1.0) { 'name': 'Fusion Plating — Native Jobs', - 'version': '19.0.1.7.0', + 'version': '19.0.1.8.0', 'category': 'Manufacturing/Plating', 'summary': 'Native plating job model — replaces mrp.production / mrp.workorder bridge.', 'description': """ @@ -33,10 +33,13 @@ full design rationale and §6.2 of the implementation plan for task list. 'fusion_plating_portal', # fusion.plating.portal.job 'fusion_plating_quality', # fusion.plating.customer.spec, fusion.plating.quality.hold 'fusion_plating_receiving', # fp.racking.inspection (Phase 3) + 'fusion_plating_reports', # paperformat helpers, customer_line_header (Phase 5) ], 'data': [ 'security/ir.model.access.csv', 'views/res_config_settings_views.xml', + 'report/report_fp_job_sticker.xml', + 'report/report_fp_job_traveller.xml', ], 'installable': True, 'application': False, diff --git a/fusion_plating/fusion_plating_jobs/report/__init__.py b/fusion_plating/fusion_plating_jobs/report/__init__.py new file mode 100644 index 00000000..24f7bb39 --- /dev/null +++ b/fusion_plating/fusion_plating_jobs/report/__init__.py @@ -0,0 +1,3 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Nexa Systems Inc. +# License OPL-1 (Odoo Proprietary License v1.0) diff --git a/fusion_plating/fusion_plating_jobs/report/report_fp_job_sticker.xml b/fusion_plating/fusion_plating_jobs/report/report_fp_job_sticker.xml new file mode 100644 index 00000000..8e4906b4 --- /dev/null +++ b/fusion_plating/fusion_plating_jobs/report/report_fp_job_sticker.xml @@ -0,0 +1,117 @@ + + + + + + FP Job Sticker (6x4") + custom + 152 + 102 + Portrait + 0 + 0 + 0 + 0 + + 0 + + 300 + + + + Job Sticker + fp.job + qweb-pdf + fusion_plating_jobs.report_fp_job_sticker_template + fusion_plating_jobs.report_fp_job_sticker_template + 'Job Sticker - %s' % (object.name or '').replace('/', '-') + + report + + + + + + diff --git a/fusion_plating/fusion_plating_jobs/report/report_fp_job_traveller.xml b/fusion_plating/fusion_plating_jobs/report/report_fp_job_traveller.xml new file mode 100644 index 00000000..d83afb28 --- /dev/null +++ b/fusion_plating/fusion_plating_jobs/report/report_fp_job_traveller.xml @@ -0,0 +1,71 @@ + + + + + + Job Traveller + fp.job + qweb-pdf + fusion_plating_jobs.report_fp_job_traveller_template + fusion_plating_jobs.report_fp_job_traveller_template + 'Traveller - %s' % (object.name or '').replace('/', '-') + + report + + + + + diff --git a/fusion_plating/fusion_plating_jobs/tests/test_fp_job_extensions.py b/fusion_plating/fusion_plating_jobs/tests/test_fp_job_extensions.py index 1324a3c9..12ac2131 100644 --- a/fusion_plating/fusion_plating_jobs/tests/test_fp_job_extensions.py +++ b/fusion_plating/fusion_plating_jobs/tests/test_fp_job_extensions.py @@ -503,3 +503,32 @@ class TestPhase4Refactors(TransactionCase): }) job.action_confirm() # Should not raise even with no templates self.assertEqual(job.state, 'confirmed') + + +class TestReports(TransactionCase): + def setUp(self): + super().setUp() + self.partner = self.env['res.partner'].create({'name': 'C'}) + self.product = self.env['product.product'].create({'name': 'P'}) + + def test_sticker_report_action_exists(self): + action = self.env.ref('fusion_plating_jobs.action_report_fp_job_sticker', raise_if_not_found=False) + self.assertTrue(action) + self.assertEqual(action.model, 'fp.job') + + def test_traveller_report_action_exists(self): + action = self.env.ref('fusion_plating_jobs.action_report_fp_job_traveller', raise_if_not_found=False) + self.assertTrue(action) + self.assertEqual(action.model, 'fp.job') + + def test_sticker_renders_for_a_job(self): + # Smoke test: the QWeb template should render without error. + job = self.env['fp.job'].create({ + 'partner_id': self.partner.id, + 'product_id': self.product.id, + 'qty': 1.0, + }) + report = self.env.ref('fusion_plating_jobs.action_report_fp_job_sticker') + # Render HTML (faster than PDF; doesn't need wkhtmltopdf) + html, _ = report._render_qweb_html(report.report_name, job.ids) + self.assertIn(job.name, html.decode() if isinstance(html, bytes) else html)