diff --git a/product_label_template/README.rst b/product_label_template/README.rst new file mode 100644 index 0000000..8c78169 --- /dev/null +++ b/product_label_template/README.rst @@ -0,0 +1,107 @@ +====================== +Product Label Template +====================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:3cd9f427940b108db44583c0d5202f01bb9a9c87512c153281f205ea751bd94f + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-blue.png + :target: http://www.gnu.org/licenses/lgpl-3.0-standalone.html + :alt: License: LGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-Quartile%2Frbkk--custom-lightgray.png?logo=github + :target: https://github.com/Quartile/rbkk-custom/tree/18.0/product_label_template + :alt: Quartile/rbkk-custom + +|badge1| |badge2| |badge3| + +This module lets you define, per product, a label template that +positions the lot/serial number, a QR code and a barcode at exact +coordinates over a label background image. + +The barcode encodes the lot/serial number (Code128, the same barcode as +the one printed by the standard *Lot/Serial Numbers* label), and its +size and position on the label are fully configurable. + +It adds a **Product Label** print action to lots/serial numbers, so the +label can be printed from the standard *Lot/Serial Numbers > Print* +menu, using the paper format configured on the product's label template. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +Go to *Inventory > Configuration > Products > Product Label Templates* +and create/maintain a template per product. The template can also be +maintained from the *Label Templates* tab of the product variant form. + +Product Label Template settings: + +- **Paper Format**: paper format used to print the PDF with. +- **Conversion Coefficient**: environment-dependent parameter to + convert the input values (cm) to the actual printed length, taking + the dpi setting into account. +- **Product Label**: label background image. +- **Label Width / Label Height**: size of the printed label image (in + cm). +- **Label Width/Height Margin**: margins on the right/bottom of the + label (in cm). +- **Font Size**: size of the printed text (in cm). +- **Width/Height Padding (Lot)**: position of the lot/serial number + from the left/top of the label (in cm). +- **With QR Code**: whether a QR code (of the lot/serial number) is + printed, with its own size and left/top position. +- **With Barcode**: whether a barcode (Code128 of the lot/serial + number) is printed, with its own width, height and left/top position. + +Usage +===== + +Go to *Inventory > Products > Lots/Serial Numbers*, select one or more +lots/serial numbers, then use *Print > Product Label*. The label is +rendered from the label template configured on each lot's product. + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +------- + +* Quartile + +Contributors +------------ + +- `Quartile `__: + + - Tim + - Yoshi Tashiro + - Tack Yabe + +Maintainers +----------- + +This module is part of the `Quartile/rbkk-custom `_ project on GitHub. + +You are welcome to contribute. diff --git a/product_label_template/__init__.py b/product_label_template/__init__.py new file mode 100644 index 0000000..0650744 --- /dev/null +++ b/product_label_template/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/product_label_template/__manifest__.py b/product_label_template/__manifest__.py new file mode 100644 index 0000000..c88c88d --- /dev/null +++ b/product_label_template/__manifest__.py @@ -0,0 +1,19 @@ +# Copyright 2021 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). +{ + "name": "Product Label Template", + "version": "18.0.1.0.0", + "author": "Quartile", + "website": "https://www.quartile.co", + "category": "Inventory", + "license": "LGPL-3", + "depends": ["stock"], + "data": [ + "security/ir.model.access.csv", + "views/ir_actions_report_views.xml", + "views/product_label_template_views.xml", + "views/product_product_views.xml", + "reports/product_label_report.xml", + ], + "installable": True, +} diff --git a/product_label_template/i18n/ja.po b/product_label_template/i18n/ja.po new file mode 100644 index 0000000..39bd0e7 --- /dev/null +++ b/product_label_template/i18n/ja.po @@ -0,0 +1,342 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * product_label_template +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 18.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2026-07-15 06:20+0000\n" +"PO-Revision-Date: 2026-07-15 06:20+0000\n" +"Last-Translator: \n" +"Language-Team: \n" +"Language: ja\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: nplurals=1; plural=0;\n" + +#. module: product_label_template +#: model:ir.actions.report,print_report_name:product_label_template.action_report_product_label +msgid "'Product Label - %s' % object.name" +msgstr "" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__product_template_attribute_value_ids +msgid "Attribute Values" +msgstr "属性値" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_form +msgid "Barcode" +msgstr "バーコード" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__barcode_height +msgid "Barcode Height" +msgstr "バーコード高さ" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__barcode_width +msgid "Barcode Width" +msgstr "バーコード幅" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__coefficient +msgid "Conversion Coefficient" +msgstr "換算係数" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__create_uid +msgid "Created by" +msgstr "作成者" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__create_date +msgid "Created on" +msgstr "作成日" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__display_name +msgid "Display Name" +msgstr "表示名" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__font_size +msgid "Font Size" +msgstr "フォントサイズ" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_search +msgid "Group By" +msgstr "グループ化" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__barcode_height_padding +msgid "Height Padding (Barcode)" +msgstr "バーコード位置(縦)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__height_padding_lot +msgid "Height Padding (Lot)" +msgstr "ロット位置(縦)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__qr_code_height_padding +msgid "Height Padding (QR)" +msgstr "QR位置(縦)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__barcode_height +msgid "Height of the printed barcode (in cm)" +msgstr "印刷されるバーコードの高さ(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__label_height +msgid "Height of the printed label image (in cm)" +msgstr "印刷されるラベル画像の高さ(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__qr_code_width_padding +msgid "Horizontal position of the QR code from the left of the label (in cm)" +msgstr "ラベル左端からのQRコードの水平位置(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__barcode_width_padding +msgid "Horizontal position of the barcode from the left of the label (in cm)" +msgstr "ラベル左端からのバーコードの水平位置(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__width_padding_lot +msgid "Horizontal position of the lot from the left of the label (in cm)" +msgstr "ラベル左端からのロットの水平位置(cm)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__id +msgid "ID" +msgstr "ID" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__label_height +msgid "Label Height" +msgstr "ラベル高さ" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__label_height_margin +msgid "Label Height Margin" +msgstr "ラベル同士の間隔(縦)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__label_image +msgid "Label Image" +msgstr "ラベル画像" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__label_ratio +msgid "Label Ratio" +msgstr "ラベル縦横比" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_list +#: model_terms:ir.ui.view,arch_db:product_label_template.product_normal_view_form +msgid "Label Templates" +msgstr "ラベルテンプレート" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__label_width +msgid "Label Width" +msgstr "ラベル幅" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__label_width_margin +msgid "Label Width Margin" +msgstr "ラベル同士の間隔(横)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__write_uid +msgid "Last Updated by" +msgstr "最終更新者" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__write_date +msgid "Last Updated on" +msgstr "最終更新日" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_form +msgid "Lot Information" +msgstr "ロット情報" + +#. module: product_label_template +#: model:ir.model.fields.selection,name:product_label_template.selection__ir_actions_report__plt_paperformat_type__main +msgid "Main" +msgstr "メイン" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_form +msgid "Main Attributes" +msgstr "主要属性" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__label_height_margin +msgid "Margin at the bottom of the label (in cm)" +msgstr "ラベル下部の余白(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__label_width_margin +msgid "Margin on the right side of the label (in cm)" +msgstr "ラベル右側の余白(cm)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__paperformat_id +msgid "Paper Format" +msgstr "用紙フォーマット" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__paperformat_id +msgid "Paper format used to print the PDF with" +msgstr "PDF印刷に使用する用紙フォーマット" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__product_id +msgid "Product" +msgstr "プロダクト" + +#. module: product_label_template +#: model:ir.actions.report,name:product_label_template.action_report_product_label +msgid "Product Label" +msgstr "プロダクトラベル" + +#. module: product_label_template +#: model:ir.model,name:product_label_template.model_product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_product__product_label_template_ids +msgid "Product Label Template" +msgstr "プロダクトラベルテンプレート" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_ir_actions_report__plt_paperformat_type +msgid "Product Label Template Paperformat Type" +msgstr "プロダクトラベルテンプレート用紙フォーマット種別" + +#. module: product_label_template +#: model:ir.actions.act_window,name:product_label_template.product_label_template_action +#: model:ir.ui.menu,name:product_label_template.menu_product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_form +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_search +msgid "Product Label Templates" +msgstr "プロダクトラベルテンプレート" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_normal_view_form +msgid "Product Labels" +msgstr "プロダクトラベル" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__product_tmpl_id +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_search +msgid "Product Template" +msgstr "プロダクトテンプレート" + +#. module: product_label_template +#: model:ir.model,name:product_label_template.model_product_product +msgid "Product Variant" +msgstr "プロダクトバリアント" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_search +msgid "Product variant attribute" +msgstr "プロダクトバリアント属性" + +#. module: product_label_template +#: model_terms:ir.ui.view,arch_db:product_label_template.product_label_template_view_form +msgid "QR Code" +msgstr "QRコード" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__qr_code_size +msgid "QR Code Size" +msgstr "QRコードサイズ" + +#. module: product_label_template +#: model:ir.model,name:product_label_template.model_ir_actions_report +msgid "Report Action" +msgstr "レポートアクション" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__qr_code_size +msgid "Size of the QR code (in cm)" +msgstr "QRコードのサイズ(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__font_size +msgid "Size of the font (in cm)" +msgstr "フォントのサイズ(cm)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_ir_actions_report__smart_search +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__smart_search +#: model:ir.model.fields,field_description:product_label_template.field_product_product__smart_search +msgid "Smart Search" +msgstr "スマート検索" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__coefficient +msgid "" +"The coefficient to convert the parameter values from 'cm' to 'mm' taking the" +" dpi setting into account." +msgstr "" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_ir_actions_report__use_plt_paperformat +msgid "Use Product Label Template Paperformat" +msgstr "プロダクトラベルテンプレートの用紙フォーマットを使用" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__qr_code_height_padding +msgid "Vertical position of the QR code from the top of the label (in cm)" +msgstr "ラベル上端からのQRコードの垂直位置(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__barcode_height_padding +msgid "Vertical position of the barcode from the top of the label (in cm)" +msgstr "ラベル上端からのバーコードの垂直位置(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__height_padding_lot +msgid "Vertical position of the lot from the top of the label (in cm)" +msgstr "ラベル上端からのロットの垂直位置(cm)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__barcode_width_padding +msgid "Width Padding (Barcode)" +msgstr "バーコード位置(横)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__width_padding_lot +msgid "Width Padding (Lot)" +msgstr "ロット位置(横)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__qr_code_width_padding +msgid "Width Padding (QR)" +msgstr "QR位置(横)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__barcode_width +msgid "Width of the printed barcode (in cm)" +msgstr "印刷されるバーコードの幅(cm)" + +#. module: product_label_template +#: model:ir.model.fields,help:product_label_template.field_product_label_template__label_width +msgid "Width of the printed label image (in cm)" +msgstr "印刷されるラベル画像の幅(cm)" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__with_barcode +msgid "With Barcode" +msgstr "バーコードを印刷" + +#. module: product_label_template +#: model:ir.model.fields,field_description:product_label_template.field_product_label_template__with_qr_code +msgid "With QR Code" +msgstr "QRコードを印刷" diff --git a/product_label_template/models/__init__.py b/product_label_template/models/__init__.py new file mode 100644 index 0000000..e670ad7 --- /dev/null +++ b/product_label_template/models/__init__.py @@ -0,0 +1,3 @@ +from . import product_label_template +from . import product_product +from . import ir_actions_report diff --git a/product_label_template/models/ir_actions_report.py b/product_label_template/models/ir_actions_report.py new file mode 100644 index 0000000..d5ad243 --- /dev/null +++ b/product_label_template/models/ir_actions_report.py @@ -0,0 +1,55 @@ +# Copyright 2021 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo import api, fields, models + + +class IrActionsReport(models.Model): + _inherit = "ir.actions.report" + + use_plt_paperformat = fields.Boolean("Use Product Label Template Paperformat") + plt_paperformat_type = fields.Selection( + selection=[("main", "Main")], + string="Product Label Template Paperformat Type", + ) + + def get_paperformat(self): + if self.use_plt_paperformat and self.env.context.get("plt_paperformat"): + return self.env.context.get("plt_paperformat") + return super().get_paperformat() + + @api.model + def _get_product_for_active_rec(self, active_rec): + """Return the product used to look up the product label template. + + Extend this method to support models other than ``stock.lot``. + """ + if active_rec._name == "stock.lot": + return active_rec.product_id + return False + + def _get_plt_paperformat(self, res_ids, plt_paperformat_type): + """Return the paperformat from the relevant product label template.""" + active_rec = self.env[self.model].browse(res_ids)[:1] + if not active_rec: + return False + product = self._get_product_for_active_rec(active_rec) + if not product: + return False + plt_rec = self.env["product.label.template"].search( + [("product_id", "=", product.id)], limit=1 + ) + if not plt_rec: + return False + if plt_paperformat_type == "main": + return plt_rec.paperformat_id + + def _render_qweb_pdf(self, report_ref, res_ids=None, data=None): + report = self._get_report(report_ref) + if report.use_plt_paperformat and report.plt_paperformat_type: + plt_paperformat = report._get_plt_paperformat( + res_ids, report.plt_paperformat_type + ) + if plt_paperformat: + self = self.with_context(plt_paperformat=plt_paperformat) + return super()._render_qweb_pdf(report_ref, res_ids=res_ids, data=data) diff --git a/product_label_template/models/product_label_template.py b/product_label_template/models/product_label_template.py new file mode 100644 index 0000000..04625e1 --- /dev/null +++ b/product_label_template/models/product_label_template.py @@ -0,0 +1,151 @@ +# Copyright 2021 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +import base64 +import io + +from PIL import Image + +from odoo import api, fields, models +from odoo.tools.image import image_data_uri + + +class ProductLabelTemplate(models.Model): + _name = "product.label.template" + _rec_name = "product_id" + _description = "Product Label Template" + + product_id = fields.Many2one("product.product", required=True) + product_template_attribute_value_ids = fields.Many2many( + related="product_id.product_template_attribute_value_ids" + ) + product_tmpl_id = fields.Many2one(related="product_id.product_tmpl_id", store=True) + paperformat_id = fields.Many2one( + "report.paperformat", + "Paper Format", + required=True, + help="Paper format used to print the PDF with", + ) + label_image = fields.Binary(attachment=True) + label_width = fields.Float(help="Width of the printed label image (in cm)") + label_height = fields.Float(help="Height of the printed label image (in cm)") + label_ratio = fields.Float() + label_width_margin = fields.Float( + help="Margin on the right side of the label (in cm)" + ) + label_height_margin = fields.Float(help="Margin at the bottom of the label (in cm)") + font_size = fields.Float(help="Size of the font (in cm)") + width_padding_lot = fields.Float( + "Width Padding (Lot)", + help="Horizontal position of the lot from the left of the label (in cm)", + ) + height_padding_lot = fields.Float( + "Height Padding (Lot)", + help="Vertical position of the lot from the top of the label (in cm)", + ) + with_qr_code = fields.Boolean("With QR Code") + qr_code_size = fields.Float("QR Code Size", help="Size of the QR code (in cm)") + qr_code_width_padding = fields.Float( + "Width Padding (QR)", + help="Horizontal position of the QR code from the left of the label (in cm)", + ) + qr_code_height_padding = fields.Float( + "Height Padding (QR)", + help="Vertical position of the QR code from the top of the label (in cm)", + ) + with_barcode = fields.Boolean() + barcode_width = fields.Float(help="Width of the printed barcode (in cm)") + barcode_height = fields.Float(help="Height of the printed barcode (in cm)") + barcode_width_padding = fields.Float( + "Width Padding (Barcode)", + help="Horizontal position of the barcode from the left of the label (in cm)", + ) + barcode_height_padding = fields.Float( + "Height Padding (Barcode)", + help="Vertical position of the barcode from the top of the label (in cm)", + ) + coefficient = fields.Float( + "Conversion Coefficient", + default=38.55, + help="The coefficient to convert the parameter values from 'cm' to 'mm' " + "taking the dpi setting into account.", + ) + + def get_label_layout_css(self, field_name): + self.ensure_one() + width_margin_field = getattr(self, f"{field_name}_width_margin") + height_margin_field = getattr(self, f"{field_name}_height_margin") + # margin-top and margin-left will be given by report.paperformat + css_list = [ + "display: inline-table", + f"margin-bottom: {height_margin_field * self.coefficient}mm", + f"margin-right: {width_margin_field * self.coefficient}mm", + ] + return ";".join(css_list) + + def get_label_css(self): + self.ensure_one() + css_list = [ + "position: relative", + f"background-image: url('{image_data_uri(self.label_image or b'')}')", + f"height: {self.label_height * self.coefficient}mm", + f"width: {self.label_width * self.coefficient}mm", + "background-size: cover", + ] + return ";".join(css_list) + + def get_label_text_css(self, field_name): + self.ensure_one() + width_padding_field = getattr(self, f"width_padding_{field_name}") + height_padding_field = getattr(self, f"height_padding_{field_name}") + css_list = [ + "position: absolute", + "font-family: Arial", + f"font-size: {self.font_size * self.coefficient}mm", + f"left: {width_padding_field * self.coefficient}mm", + f"top: {height_padding_field * self.coefficient}mm", + ] + return ";".join(css_list) + + def get_qr_code_css(self): + self.ensure_one() + css_list = [ + "position: absolute", + f"left: {self.qr_code_width_padding * self.coefficient}mm", + f"top: {self.qr_code_height_padding * self.coefficient}mm", + f"width: {self.qr_code_size * self.coefficient}mm", + f"height: {self.qr_code_size * self.coefficient}mm", + ] + return ";".join(css_list) + + def get_barcode_css(self): + self.ensure_one() + css_list = [ + "position: absolute", + f"left: {self.barcode_width_padding * self.coefficient}mm", + f"top: {self.barcode_height_padding * self.coefficient}mm", + f"width: {self.barcode_width * self.coefficient}mm", + f"height: {self.barcode_height * self.coefficient}mm", + ] + return ";".join(css_list) + + @api.onchange("label_image") + def _onchange_label_image(self): + if self.label_image: + # Borrowing logic from odoo image tool + # https://github.com/odoo/odoo/blob/4e2d0b97f3ec0491294301a5a6b05086e158dea8/odoo/tools/image.py#L68-L69 # noqa + image_stream = io.BytesIO(base64.b64decode(self.label_image)) + image = Image.open(image_stream) + self.label_width = image.size[0] + self.label_height = image.size[1] + self.label_ratio = image.size[0] / image.size[1] + + @api.onchange("label_width") + def _onchange_label_width(self): + if self.label_width and self.label_ratio: + self.label_height = self.label_width / self.label_ratio + + @api.onchange("label_height") + def _onchange_label_height(self): + if self.label_height and self.label_ratio: + self.label_width = self.label_height * self.label_ratio diff --git a/product_label_template/models/product_product.py b/product_label_template/models/product_product.py new file mode 100644 index 0000000..cf475c9 --- /dev/null +++ b/product_label_template/models/product_product.py @@ -0,0 +1,12 @@ +# Copyright 2021 Quartile (https://www.quartile.co) +# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl). + +from odoo import fields, models + + +class ProductProduct(models.Model): + _inherit = "product.product" + + product_label_template_ids = fields.One2many( + "product.label.template", "product_id", "Product Label Template" + ) diff --git a/product_label_template/pyproject.toml b/product_label_template/pyproject.toml new file mode 100644 index 0000000..4231d0c --- /dev/null +++ b/product_label_template/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["whool"] +build-backend = "whool.buildapi" diff --git a/product_label_template/readme/CONFIGURE.md b/product_label_template/readme/CONFIGURE.md new file mode 100644 index 0000000..414bbf8 --- /dev/null +++ b/product_label_template/readme/CONFIGURE.md @@ -0,0 +1,20 @@ +Go to *Inventory > Configuration > Products > Product Label Templates* and +create/maintain a template per product. The template can also be maintained from +the *Label Templates* tab of the product variant form. + +Product Label Template settings: + +- **Paper Format**: paper format used to print the PDF with. +- **Conversion Coefficient**: environment-dependent parameter to convert the + input values (cm) to the actual printed length, taking the dpi setting into + account. +- **Product Label**: label background image. +- **Label Width / Label Height**: size of the printed label image (in cm). +- **Label Width/Height Margin**: margins on the right/bottom of the label (in cm). +- **Font Size**: size of the printed text (in cm). +- **Width/Height Padding (Lot)**: position of the lot/serial number from the + left/top of the label (in cm). +- **With QR Code**: whether a QR code (of the lot/serial number) is printed, with + its own size and left/top position. +- **With Barcode**: whether a barcode (Code128 of the lot/serial number) is + printed, with its own width, height and left/top position. diff --git a/product_label_template/readme/CONTRIBUTORS.md b/product_label_template/readme/CONTRIBUTORS.md new file mode 100644 index 0000000..5105ad1 --- /dev/null +++ b/product_label_template/readme/CONTRIBUTORS.md @@ -0,0 +1,4 @@ +- [Quartile](https://www.quartile.co): + - Tim + - Yoshi Tashiro + - Tack Yabe diff --git a/product_label_template/readme/DESCRIPTION.md b/product_label_template/readme/DESCRIPTION.md new file mode 100644 index 0000000..e02f00a --- /dev/null +++ b/product_label_template/readme/DESCRIPTION.md @@ -0,0 +1,11 @@ +This module lets you define, per product, a label template that positions the +lot/serial number, a QR code and a barcode at exact coordinates over a label +background image. + +The barcode encodes the lot/serial number (Code128, the same barcode as the one +printed by the standard *Lot/Serial Numbers* label), and its size and position on +the label are fully configurable. + +It adds a **Product Label** print action to lots/serial numbers, so the label can +be printed from the standard *Lot/Serial Numbers > Print* menu, using the paper +format configured on the product's label template. diff --git a/product_label_template/readme/USAGE.md b/product_label_template/readme/USAGE.md new file mode 100644 index 0000000..ddca5b2 --- /dev/null +++ b/product_label_template/readme/USAGE.md @@ -0,0 +1,3 @@ +Go to *Inventory > Products > Lots/Serial Numbers*, select one or more +lots/serial numbers, then use *Print > Product Label*. The label is rendered from +the label template configured on each lot's product. diff --git a/product_label_template/reports/product_label_report.xml b/product_label_template/reports/product_label_report.xml new file mode 100644 index 0000000..d5484dd --- /dev/null +++ b/product_label_template/reports/product_label_report.xml @@ -0,0 +1,55 @@ + + + + + + + + Product Label + stock.lot + qweb-pdf + product_label_template.report_product_label + product_label_template.report_product_label + True + main + 'Product Label - %s' % object.name + + report + + diff --git a/product_label_template/security/ir.model.access.csv b/product_label_template/security/ir.model.access.csv new file mode 100644 index 0000000..a015d9a --- /dev/null +++ b/product_label_template/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_product_label_template_user,access.product.label.template.user,model_product_label_template,base.group_user,1,0,0,0 +access_product_label_template_stock_manager,access.product.label.template.stock.manager,model_product_label_template,stock.group_stock_manager,1,1,1,1 diff --git a/product_label_template/static/description/index.html b/product_label_template/static/description/index.html new file mode 100644 index 0000000..5c19f58 --- /dev/null +++ b/product_label_template/static/description/index.html @@ -0,0 +1,462 @@ + + + + + + +Product Label Template + + + +
+

Product Label Template

+ + +

Beta License: LGPL-3 Quartile/rbkk-custom

+

This module lets you define, per product, a label template that +positions the lot/serial number, a QR code and a barcode at exact +coordinates over a label background image.

+

The barcode encodes the lot/serial number (Code128, the same barcode as +the one printed by the standard Lot/Serial Numbers label), and its +size and position on the label are fully configurable.

+

It adds a Product Label print action to lots/serial numbers, so the +label can be printed from the standard Lot/Serial Numbers > Print +menu, using the paper format configured on the product’s label template.

+

Table of contents

+ +
+

Configuration

+

Go to Inventory > Configuration > Products > Product Label Templates +and create/maintain a template per product. The template can also be +maintained from the Label Templates tab of the product variant form.

+

Product Label Template settings:

+
    +
  • Paper Format: paper format used to print the PDF with.
  • +
  • Conversion Coefficient: environment-dependent parameter to +convert the input values (cm) to the actual printed length, taking +the dpi setting into account.
  • +
  • Product Label: label background image.
  • +
  • Label Width / Label Height: size of the printed label image (in +cm).
  • +
  • Label Width/Height Margin: margins on the right/bottom of the +label (in cm).
  • +
  • Font Size: size of the printed text (in cm).
  • +
  • Width/Height Padding (Lot): position of the lot/serial number +from the left/top of the label (in cm).
  • +
  • With QR Code: whether a QR code (of the lot/serial number) is +printed, with its own size and left/top position.
  • +
  • With Barcode: whether a barcode (Code128 of the lot/serial +number) is printed, with its own width, height and left/top position.
  • +
+
+
+

Usage

+

Go to Inventory > Products > Lots/Serial Numbers, select one or more +lots/serial numbers, then use Print > Product Label. The label is +rendered from the label template configured on each lot’s product.

+
+
+

Bug Tracker

+

Bugs are tracked on GitHub Issues. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +feedback.

+

Do not contact contributors directly about support or help with technical issues.

+
+
+

Credits

+
+

Authors

+
    +
  • Quartile
  • +
+
+
+

Contributors

+
    +
  • Quartile:
      +
    • Tim
    • +
    • Yoshi Tashiro
    • +
    • Tack Yabe
    • +
    +
  • +
+
+
+

Maintainers

+

This module is part of the Quartile/rbkk-custom project on GitHub.

+

You are welcome to contribute.

+
+
+
+ + diff --git a/product_label_template/views/ir_actions_report_views.xml b/product_label_template/views/ir_actions_report_views.xml new file mode 100644 index 0000000..fdae41d --- /dev/null +++ b/product_label_template/views/ir_actions_report_views.xml @@ -0,0 +1,17 @@ + + + + ir.actions.report.form.plt + ir.actions.report + + + + + + + + + diff --git a/product_label_template/views/product_label_template_views.xml b/product_label_template/views/product_label_template_views.xml new file mode 100644 index 0000000..82d07f5 --- /dev/null +++ b/product_label_template/views/product_label_template_views.xml @@ -0,0 +1,118 @@ + + + + product.label.template.form + product.label.template + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + product.label.template.list + product.label.template + + + + + + + + + + + + + + + + + + + + + + product.label.template.search + product.label.template + + + + + + + + + + + + + Product Label Templates + product.label.template + list,form + {'search_default_by_product_template': 1} + + +
diff --git a/product_label_template/views/product_product_views.xml b/product_label_template/views/product_product_views.xml new file mode 100644 index 0000000..dec52c3 --- /dev/null +++ b/product_label_template/views/product_product_views.xml @@ -0,0 +1,34 @@ + + + + product.product.form.label.template + product.product + + + + + + + + + + + + + + + + + + + + + +