diff --git a/product_label_image/README.rst b/product_label_image/README.rst new file mode 100644 index 00000000..e036a97f --- /dev/null +++ b/product_label_image/README.rst @@ -0,0 +1,5 @@ +=================== +Product Label Image +=================== + +Product barcode print with product image diff --git a/product_label_image/__init__.py b/product_label_image/__init__.py new file mode 100644 index 00000000..0c291b47 --- /dev/null +++ b/product_label_image/__init__.py @@ -0,0 +1 @@ +from . import reports, wizard diff --git a/product_label_image/__manifest__.py b/product_label_image/__manifest__.py new file mode 100644 index 00000000..37797b89 --- /dev/null +++ b/product_label_image/__manifest__.py @@ -0,0 +1,18 @@ +{ + "name": "Product Label Image", + "category": "other", + "version": "18.0.1.0.1", + "summary": """Prints product barcode along with product image""", + "author": "Nitrokey GmbH", + "website": "https://github.com/Nitrokey/odoo-modules", + "license": "AGPL-3", + "depends": ["product"], + "data": [ + "reports/product_template_report.xml", + ], + "assets": { + "web.report_assets_common": [ + "product_label_image/static/src/scss/product_label_image.scss" + ], + }, +} diff --git a/product_label_image/reports/__init__.py b/product_label_image/reports/__init__.py new file mode 100644 index 00000000..50fc64e0 --- /dev/null +++ b/product_label_image/reports/__init__.py @@ -0,0 +1 @@ +from . import product_label_report diff --git a/product_label_image/reports/product_label_report.py b/product_label_image/reports/product_label_report.py new file mode 100644 index 00000000..109df49d --- /dev/null +++ b/product_label_image/reports/product_label_report.py @@ -0,0 +1,50 @@ +from collections import defaultdict + +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": + Product = env["product.template"].with_context(display_default_code=False) + elif data.get("active_model") == "product.product": + Product = env["product.product"].with_context(display_default_code=False) + else: + raise UserError( + _("Product model not defined, Please contact your administrator.") + ) + + total, quantity_by_product = 0, defaultdict(list) + for p, q in data.get("quantity_by_product", {}).items(): + product = Product.browse(int(p)) + quantity_by_product[product].append((product.barcode, q)) + total += q + if data.get("custom_barcodes"): + # we expect custom barcodes format as: {product: [(barcode, qty_of_barcode)]} + for product, barcodes_qtys in data.get("custom_barcodes").items(): + quantity_by_product[Product.browse(int(product))] += barcodes_qtys + total += sum(qty for _, qty in barcodes_qtys) + + 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": (total - 1) // (layout_wizard.rows * layout_wizard.columns) + 1, + "price_included": data.get("price_included"), + "extra_html": layout_wizard.extra_html, + } + + +class ReportProductTemplateLabelImage4x6(models.AbstractModel): + _name = "report.product_label_image.producttemplatelabel_image_4x6" + _description = "Product Label Report" + + def _get_report_values(self, docids, data): + return _prepare_data(self.env, data) diff --git a/product_label_image/reports/product_template_report.xml b/product_label_image/reports/product_template_report.xml new file mode 100644 index 00000000..24c36f3c --- /dev/null +++ b/product_label_image/reports/product_template_report.xml @@ -0,0 +1,76 @@ + + + + + + + + + + Product Label (PDF) + product.template + qweb-pdf + product_label_image.producttemplatelabel_image_4x6 + product_label_image.producttemplatelabel_image_4x6 + + 'Products Labels - %s' % (object.name) + report + + diff --git a/product_label_image/static/src/scss/product_label_image.scss b/product_label_image/static/src/scss/product_label_image.scss new file mode 100644 index 00000000..fba86bd5 --- /dev/null +++ b/product_label_image/static/src/scss/product_label_image.scss @@ -0,0 +1,37 @@ +div { + &.o_firstdiv { + width: 100%; + margin-bottom: 200px; + } + &.o_seconddiv { + width: 310px; + height: 210px; + border: 2px solid #555555 !important; + padding: 2px 4px; + } + &.o_thirddiv { + height: 86px; + margin-bottom: 18px; + overflow: hidden; + & > strong { + font-size: 16px; + } + } + &.o_barcode { + padding: 5px; + } + &.o_product_img_div1 { + width: 310px; + height: 210px; + border: 2px solid #555555; + border-left: 1px; + } + &.img_div2 { + height: 10rem; + } + & > img.o_product_picture { + height: 190px; + width: auto; + margin-top: 8%; + } +} diff --git a/product_label_image/wizard/__init__.py b/product_label_image/wizard/__init__.py new file mode 100644 index 00000000..6818894b --- /dev/null +++ b/product_label_image/wizard/__init__.py @@ -0,0 +1 @@ +from . import product_label_layout diff --git a/product_label_image/wizard/product_label_layout.py b/product_label_image/wizard/product_label_layout.py new file mode 100644 index 00000000..7758dd6d --- /dev/null +++ b/product_label_image/wizard/product_label_layout.py @@ -0,0 +1,39 @@ +from odoo import _, fields, models +from odoo.exceptions import UserError + + +class ProductLabelLayout(models.TransientModel): + _inherit = "product.label.layout" + + print_format = fields.Selection( + selection_add=[("4x6", "4x6")], + default="4x6", + ondelete={"4x6": "set default"}, + ) + + def _prepare_report_data(self): + if self.custom_quantity <= 0: + raise UserError(_("You need to set a positive quantity.")) + + # Get layout grid + if self.print_format != "4x6": + return super()._prepare_report_data() + + xml_id = "product_label_image.report_product_label_image_4x6" + + active_model = "" + if self.product_tmpl_ids: + products = self.product_tmpl_ids.ids + active_model = "product.template" + elif self.product_ids: + products = self.product_ids.ids + active_model = "product.product" + + # Build data to pass to the report + data = { + "active_model": active_model, + "quantity_by_product": {p: self.custom_quantity for p in products}, + "layout_wizard": self.id, + "price_included": "xprice" in self.print_format, + } + return xml_id, data