From d9f45ba6941939b3d4b40beb5abbc330be84d695 Mon Sep 17 00:00:00 2001 From: William Henrotin Date: Wed, 21 Apr 2021 10:01:33 +0000 Subject: [PATCH] [IMP] product,stock{_picking_batch}: product labels revamp This commit removes the pdf and zpl reports for product templates and variants. Instead, labels are printed via a new wizard allowing to specify the label quantity, format and optional text. There are a bunch of usual retail label sizes in pdf or zpl code Task : 2501730 closes odoo/odoo#69690 Related: odoo/enterprise#20246 Related: odoo/upgrade#2542 Signed-off-by: William Henrotin --- addons/product/__init__.py | 1 + addons/product/__manifest__.py | 6 +- addons/product/models/product.py | 5 + addons/product/models/product_template.py | 5 + addons/product/report/__init__.py | 1 + addons/product/report/product_label_report.py | 41 ++++ .../report/product_product_templates.xml | 209 +++++++++++++----- addons/product/report/product_reports.xml | 59 +++-- .../report/product_template_templates.xml | 20 +- addons/product/security/ir.model.access.csv | 1 + .../static/src/scss/report_label_sheet.scss | 69 ++++++ .../product/views/product_template_views.xml | 3 + addons/product/views/product_views.xml | 15 ++ addons/product/wizard/__init__.py | 3 + addons/product/wizard/product_label_layout.py | 71 ++++++ .../wizard/product_label_layout_views.xml | 27 +++ addons/stock/__manifest__.py | 1 + addons/stock/models/stock_picking.py | 14 ++ addons/stock/report/__init__.py | 1 + addons/stock/report/product_label_report.py | 20 ++ addons/stock/report/product_templates.xml | 86 ++----- addons/stock/report/stock_report_views.xml | 47 +--- addons/stock/views/product_views.xml | 24 +- addons/stock/views/stock_picking_views.xml | 1 + addons/stock/wizard/__init__.py | 1 + addons/stock/wizard/product_label_layout.py | 34 +++ .../wizard/product_label_layout_views.xml | 20 ++ .../models/stock_picking_batch.py | 16 ++ .../views/stock_picking_batch_views.xml | 1 + odoo/addons/base/models/ir_qweb_fields.py | 6 + 30 files changed, 579 insertions(+), 229 deletions(-) create mode 100644 addons/product/report/product_label_report.py create mode 100644 addons/product/static/src/scss/report_label_sheet.scss create mode 100644 addons/product/wizard/__init__.py create mode 100644 addons/product/wizard/product_label_layout.py create mode 100644 addons/product/wizard/product_label_layout_views.xml create mode 100644 addons/stock/report/product_label_report.py create mode 100644 addons/stock/wizard/product_label_layout.py create mode 100644 addons/stock/wizard/product_label_layout_views.xml diff --git a/addons/product/__init__.py b/addons/product/__init__.py index c072b1a6890..2a8e352ba2e 100644 --- a/addons/product/__init__.py +++ b/addons/product/__init__.py @@ -4,3 +4,4 @@ from . import models from . import report from . import populate +from . import wizard diff --git a/addons/product/__manifest__.py b/addons/product/__manifest__.py index 09790ddbffa..9e2e25721ca 100644 --- a/addons/product/__manifest__.py +++ b/addons/product/__manifest__.py @@ -30,6 +30,7 @@ Print product labels with barcode. 'data/product_data.xml', 'security/product_security.xml', 'security/ir.model.access.csv', + 'wizard/product_label_layout_views.xml', 'views/res_config_settings_views.xml', 'views/product_attribute_views.xml', 'views/product_views.xml', @@ -40,7 +41,7 @@ Print product labels with barcode. 'report/product_product_templates.xml', 'report/product_template_templates.xml', 'report/product_packaging.xml', - 'report/product_pricelist_report_templates.xml' + 'report/product_pricelist_report_templates.xml', ], 'demo': [ 'data/product_demo.xml', @@ -51,6 +52,9 @@ Print product labels with barcode. 'web.assets_backend': [ 'product/static/src/js/**/*', ], + 'web.report_assets_common': [ + 'product/static/src/scss/report_label_sheet.scss', + ], 'web.qunit_suite_tests': [ 'product/static/tests/**/*', ], diff --git a/addons/product/models/product.py b/addons/product/models/product.py index d21afe1d566..f937ea3f849 100644 --- a/addons/product/models/product.py +++ b/addons/product/models/product.py @@ -596,6 +596,11 @@ class ProductProduct(models.Model): ) return super().view_header_get(view_id, view_type) + def action_open_label_layout(self): + action = self.env['ir.actions.act_window']._for_xml_id('product.action_open_label_layout') + action['context'] = {'default_product_ids': self.ids} + return action + def open_pricelist_rules(self): self.ensure_one() domain = ['|', diff --git a/addons/product/models/product_template.py b/addons/product/models/product_template.py index 785657b11ae..c5c1e11184f 100644 --- a/addons/product/models/product_template.py +++ b/addons/product/models/product_template.py @@ -528,6 +528,11 @@ class ProductTemplate(models.Model): '', args=[('id', 'in', list(searched_ids))], operator='ilike', limit=limit, name_get_uid=name_get_uid) + def action_open_label_layout(self): + action = self.env['ir.actions.act_window']._for_xml_id('product.action_open_label_layout') + action['context'] = {'default_product_tmpl_ids': self.ids} + return action + def open_pricelist_rules(self): self.ensure_one() domain = ['|', diff --git a/addons/product/report/__init__.py b/addons/product/report/__init__.py index 537678882bf..107ceeafd85 100644 --- a/addons/product/report/__init__.py +++ b/addons/product/report/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- # Part of Odoo. See LICENSE file for full copyright and licensing details. +from . import product_label_report from . import product_pricelist_report diff --git a/addons/product/report/product_label_report.py b/addons/product/report/product_label_report.py new file mode 100644 index 00000000000..7ee922fa1e9 --- /dev/null +++ b/addons/product/report/product_label_report.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import _, models +from odoo.exceptions import UserError + +def _prepare_data(env, data): + # change product ids by actual product object to get access to fields in xml template + # we needed to pass ids because reports only accepts native python types (int, float, strings, ...) + if data.get('active_model') == 'product.template': + quantity_by_product = {env['product.template'].with_context(display_default_code=False).browse(int(p)): q for p, q in data.get('quantity_by_product').items()} + elif data.get('active_model') == 'product.product': + quantity_by_product = {env['product.product'].with_context(display_default_code=False).browse(int(p)): q for p, q in data.get('quantity_by_product').items()} + else: + raise UserError(_('Product model not defined, Please contact your administrator.')) + layout_wizard = env['product.label.layout'].browse(data.get('layout_wizard')) + if not layout_wizard: + return {} + + return { + 'quantity': quantity_by_product, + 'rows': layout_wizard.rows, + 'columns': layout_wizard.columns, + 'page_numbers': (sum(quantity_by_product.values()) - 1) // (layout_wizard.rows * layout_wizard.columns) + 1, + 'price_included': data.get('price_included'), + 'extra_html': layout_wizard.extra_html, + } + +class ReportProductTemplateLabel(models.AbstractModel): + _name = 'report.product.report_producttemplatelabel' + _description = 'Product Label Report' + + def _get_report_values(self, docids, data): + return _prepare_data(self.env, data) + +class ReportProductTemplateLabelDymo(models.AbstractModel): + _name = 'report.product.report_producttemplatelabel_dymo' + _description = 'Product Label Report' + + def _get_report_values(self, docids, data): + return _prepare_data(self.env, data) diff --git a/addons/product/report/product_product_templates.xml b/addons/product/report/product_product_templates.xml index 822f3b415d6..4635790d275 100644 --- a/addons/product/report/product_product_templates.xml +++ b/addons/product/report/product_product_templates.xml @@ -1,75 +1,168 @@ -