Penambahan QC dan OEE, serta instalasi Product Label

This commit is contained in:
2026-02-14 10:47:08 +07:00
parent d183336a9e
commit d5a05971ae
71 changed files with 6506 additions and 1 deletions
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+55
View File
@@ -0,0 +1,55 @@
=====================
Custom Product Labels
=====================
.. |badge1| image:: https://img.shields.io/badge/maturity-Production-green.png
:alt: Production
.. |badge2| image:: https://img.shields.io/badge/licence-LGPL--3-purple.png
:target: https://www.gnu.org/licenses/lgpl-3.0.html
:alt: License: LGPL-3
.. |badge3| image:: https://img.shields.io/badge/demo-Try%20me-FEA621.png
:target: https://garazd.biz/r/r2G
:alt: Try me on a Demo Instance
.. |badge4| image:: https://img.shields.io/badge/link-Garazd%20Apps-154577.png
:target: https://garazd.biz/shop/custom-product-labels-2
:alt: Get the app on Garazd Apps store
|badge1| |badge2| |badge3| |badge4|
Print custom product labels with barcode | Barcode Product Label
**Table of contents**
.. contents::
:local:
Credits
=======
Authors
~~~~~~~
* Garazd Creation
Maintainers
~~~~~~~~~~~
This module is maintained by the Garazd Creation.
.. image:: https://garazd.biz/logo.png
:alt: Garazd Creation
:target: https://garazd.biz
Our mission is to create convenient and effective business solutions
based on the Odoo ERP system in the areas in which we have the maximum
expertise, such as: eCommerce, marketing, SEO, integration with
marketplaces and analytic systems, product label printing and designing.
To solve these tasks, we create modules that complement each other,
extend the functionality of Odoo and improve the usability of the system.
Our solutions come with detailed documentation and additional materials
for easy use.
+1
View File
@@ -0,0 +1 @@
from . import wizard
+32
View File
@@ -0,0 +1,32 @@
# Copyright © 2018 Garazd Creation (https://garazd.biz)
# @author: Yurii Razumovskyi (support@garazd.biz)
# @author: Iryna Razumovska (support@garazd.biz)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html).
{
'name': 'Custom Product Labels',
'version': '14.0.2.3.2',
'category': 'Extra Tools',
'author': 'Garazd Creation',
'website': 'https://garazd.biz/en/shop/category/odoo-product-labels-15',
'license': 'LGPL-3',
'summary': 'Print custom product labels with barcode | Barcode Product Label',
'images': ['static/description/banner.png', 'static/description/icon.png'],
'depends': [
'product',
],
'data': [
'security/ir.model.access.csv',
'report/product_label_reports.xml',
'report/product_label_templates.xml',
'wizard/print_product_label_views.xml',
'views/res_config_settings_views.xml',
],
'demo': [
'demo/product_demo.xml',
],
'support': 'support@garazd.biz',
'application': True,
'installable': True,
'auto_install': False,
}
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo noupdate="1">
<record id="product.product_product_12" model="product.product">
<field name="barcode">0500010543219</field>
</record>
<record id="product.product_product_27" model="product.product">
<field name="name">Drawer with three panels and one lockable, on wheels, mobile and respectable</field>
<field name="barcode">1234567890128</field>
</record>
<!-- Product variant with EAN-8-->
<record id="product.product_product_10" model="product.product">
<field name="name">Cabinet with Doors: minimalistic wooden with brown top, divided by two sides, with drawer</field>
<field name="barcode">12345670</field>
</record>
<!-- Product variant with EAN-13-->
<record id="product.product_product_13" model="product.product">
<field name="name">Corner Desk Black with metal base and wooden table-top, ergonomic and comfortable</field>
<field name="barcode">4444000022222</field>
</record>
<!-- Product variant with Code 128: Customizable Desk (Legs: Aluminium, Color: White) -->
<record id="product.product_product_4c" model="product.product">
<field name="name">Customizable Desk: adjustment by height, maximum free space</field>
<field name="barcode">10203040506070809</field>
</record>
</odoo>
+85
View File
@@ -0,0 +1,85 @@
.. _changelog:
Changelog
=========
`14.0.2.3.2`
------------
- Add method to get PDF.
`14.0.2.3.1`
------------
- Add UA translations.
`14.0.2.3.0`
------------
- Improve getting of labels to print, add excluding of lines with qty=0.
- Add the "mode" option for technical purposes.
`14.0.2.2.0`
------------
- Implement sorting of label lines by a product.
- Add the sequence for the label lines.
`14.0.2.1.0`
------------
- Add the settings section "Product Labels".
`14.0.2.0.0`
------------
- Add a product label template 50x38 mm.
- Improve product demo data.
- Implement a new logic for print wizard.
- Add a company selection to the wizard.
`14.0.1.2.0`
------------
- Add the option "Language" to translate product names.
`14.0.1.1.1`
------------
- Add method "_get_label_to_print" to define actual product lines.
`14.0.1.1.0`
------------
- Add the option "Border" to define a border width on multi labels on A4, US letter paper formats.
`14.0.1.0.3`
------------
- Add barcode types in the 57x35 label template
- Add currency symbol position before/after in the 57x35 label template
- Add option Humanreadable barcode to the wizard
`14.0.1.0.2`
------------
- Fix save_eval error: NameError: name Product_labels_57x35mm is not defined
`14.0.1.0.1`
------------
- change print_report_name (spaces removed)
`14.0.1.0.0`
------------
- Migrate to 14.0
+343
View File
@@ -0,0 +1,343 @@
# Translation of Odoo Server.
# This file contains the translation of the following modules:
# * garazd_product_label
#
msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 14.0+e\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2024-08-15 17:27+0000\n"
"PO-Revision-Date: 2024-08-15 17:27+0000\n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
#. module: garazd_product_label
#: model:ir.actions.report,print_report_name:garazd_product_label.action_report_product_label_50x38
msgid "'Product Labels 50x38mm'"
msgstr "'Етикетки 50х38 мм'"
#. module: garazd_product_label
#: model:ir.actions.report,print_report_name:garazd_product_label.action_report_product_label_A4_57x35
msgid "'Product Labels 57x35mm'"
msgstr "'Етикетки 57х35 мм'"
#. module: garazd_product_label
#: model:ir.actions.report,print_report_name:garazd_product_label.action_report_product_label_from_template
msgid "'Product Labels Custom Design'"
msgstr "'Етикетки товарів з власний дизайном'"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "<span>Get the Label Builder to create your own labels</span>"
msgstr ""
"<span>Дізнайтеся, як створювати етикетки з власним дизайном за допомогою "
"Label Builder</span>"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__barcode
#: model_terms:ir.ui.view,arch_db:garazd_product_label.label_57x35
#: model_terms:ir.ui.view,arch_db:garazd_product_label.report_product_label_50x38_template
msgid "Barcode"
msgstr "Штрих-код"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__border_width
msgid "Border"
msgstr "Обрамлення"
#. module: garazd_product_label
#: model:ir.model.fields,help:garazd_product_label.field_print_product_label__border_width
msgid "Border width for labels (in pixels). Set \"0\" for no border."
msgstr ""
"Ширина рамки для етикеток (у пікселях). Встановіть \"0\", якщо рамка не "
"потрібна."
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__company_id
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__company_id
msgid "Company"
msgstr "Компанія"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__create_uid
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__create_uid
msgid "Created by"
msgstr ""
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__create_date
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__create_date
msgid "Created on"
msgstr ""
#. module: garazd_product_label
#: model:ir.actions.act_window,name:garazd_product_label.action_print_label_from_product
#: model:ir.actions.act_window,name:garazd_product_label.action_print_label_from_template
msgid "Custom Product Labels"
msgstr "Етикетки товарів"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Decrease Qty"
msgstr "Зменшити кількість"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__display_name
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__display_name
msgid "Display Name"
msgstr ""
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "How to get Product Label Builder"
msgstr "Як отримати конструктор етикеток \"Product Label Builder\""
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__humanreadable
msgid "Human readable barcode"
msgstr "Читабельний штрих-код"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__id
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__id
msgid "ID"
msgstr ""
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Increase Qty"
msgstr "Збільшити кількість"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__qty_initial
msgid "Initial Qty"
msgstr "Первісна кількість"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__is_template_report
msgid "Is Template Report"
msgstr "Шаблон звіту"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__report_id
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Label"
msgstr "Етикетка"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__qty
msgid "Label Qty"
msgstr "Кількість етикеток"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__qty_per_product
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Label quantity per product"
msgstr "Кількість етикеток для кожного товару"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Labels"
msgstr "Етикетки"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__label_ids
msgid "Labels for Products"
msgstr "Етикетки для товарів"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__lang
msgid "Language"
msgstr "Мова"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label____last_update
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line____last_update
msgid "Last Modified on"
msgstr ""
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__write_uid
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__write_uid
msgid "Last Updated by"
msgstr ""
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__write_date
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__write_date
msgid "Last Updated on"
msgstr ""
#. module: garazd_product_label
#: model:ir.model,name:garazd_product_label.model_print_product_label_line
msgid "Line with a Product Label Data"
msgstr ""
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__message
msgid "Message"
msgstr "Повідомлення"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__mode
msgid "Mode"
msgstr "Режим"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__name
msgid "Name"
msgstr "Назва"
#. module: garazd_product_label
#: code:addons/garazd_product_label/wizard/print_product_label.py:0
#, python-format
msgid "Nothing to print, set the quantity of labels in the table."
msgstr "Друкувати нічого, встановіть кількість етикеток у таблиці."
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Options"
msgstr "Налаштування"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Output"
msgstr "Формат"
#. module: garazd_product_label
#: model:ir.model.fields.selection,name:garazd_product_label.selection__print_product_label__output__pdf
msgid "PDF"
msgstr ""
#. module: garazd_product_label
#: code:addons/garazd_product_label/wizard/print_product_label.py:0
#, python-format
msgid "Please select a label type."
msgstr "Будь ласка, оберіть тип етикетки."
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Preview"
msgstr "Попередній перегляд"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Preview product labels"
msgstr "Попередній перегляд товарних етикеток"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__selected
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Print"
msgstr "Друк"
#. module: garazd_product_label
#: code:addons/garazd_product_label/wizard/print_product_label.py:0
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
#, python-format
msgid "Print Product Labels"
msgstr "Друк етикеток"
#. module: garazd_product_label
#: model:ir.model.fields,help:garazd_product_label.field_print_product_label__humanreadable
msgid "Print digital code of barcode."
msgstr "Роздрукувати цифровий код штрих-коду."
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Print product labels"
msgstr "Друк товарних етикеток"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label__output
msgid "Print to"
msgstr "Друкувати в"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__product_id
msgid "Product"
msgstr "Товар"
#. module: garazd_product_label
#: model:ir.actions.report,name:garazd_product_label.action_report_product_label_from_template
msgid "Product Label from your own template"
msgstr "Етикетки з вашим власним дизайном"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.res_config_settings_view_form
msgid "Product Labels"
msgstr "Друк етикеток"
#. module: garazd_product_label
#: model:ir.actions.report,name:garazd_product_label.action_report_product_label_50x38
msgid "Product Labels 50x38mm"
msgstr "Етикетки 50х38 мм"
#. module: garazd_product_label
#: model:ir.actions.report,name:garazd_product_label.action_report_product_label_A4_57x35
msgid "Product Labels 57x35mm (A4, 21 pcs)"
msgstr "Етикетки 57x35 мм (A4, 21 шт)"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Restore initial quantity"
msgstr "Відновити первісну кількість етикеток"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__sequence
msgid "Sequence"
msgstr "Послідовність"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Set a certain quantity for each line."
msgstr "Встановіть певну кількість для кожного рядка."
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Set quantity"
msgstr "Встановити кількість"
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Sort labels by a product"
msgstr "Сортування етикеток за товаром"
#. module: garazd_product_label
#: model:ir.model.fields,help:garazd_product_label.field_print_product_label__company_id
msgid "Specify a company for product labels."
msgstr "Вкажіть компанію для товарних етикеток."
#. module: garazd_product_label
#: model:ir.model.fields,help:garazd_product_label.field_print_product_label__mode
msgid "Technical field"
msgstr ""
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Template"
msgstr "Шаблон"
#. module: garazd_product_label
#: model:ir.model.fields,help:garazd_product_label.field_print_product_label__lang
msgid "The language that will be used to translate label names."
msgstr "Мова, яка використовуватиметься для перекладу полів етикетки."
#. module: garazd_product_label
#: model_terms:ir.ui.view,arch_db:garazd_product_label.print_product_label_view_form
msgid "Total"
msgstr "Всього"
#. module: garazd_product_label
#: model:ir.model.fields,field_description:garazd_product_label.field_print_product_label_line__wizard_id
msgid "Wizard"
msgstr "Майстер"
#. module: garazd_product_label
#: model:ir.model,name:garazd_product_label.model_print_product_label
msgid "Wizard to print Product Labels"
msgstr "Майстер для друку етикеток товарів"
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="paperformat_label_a4_blank" model="report.paperformat">
<field name="name">Label A4</field>
<field name="format">A4</field>
<field name="page_height">0</field>
<field name="page_width">0</field>
<field name="orientation">Portrait</field>
<field name="margin_top">10</field>
<field name="margin_bottom">10</field>
<field name="margin_left">5</field>
<field name="margin_right">5</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">0</field>
<field name="dpi">77</field>
<field name="default" eval="False"/>
</record>
<record id="paperformat_label_50x38" model="report.paperformat">
<field name="name">Label 50x38 mm</field>
<field name="format">custom</field>
<field name="page_height">38</field>
<field name="page_width">50</field>
<field name="orientation">Portrait</field>
<field name="margin_top">1</field>
<field name="margin_bottom">0</field>
<field name="margin_left">0</field>
<field name="margin_right">0</field>
<field name="header_line" eval="False"/>
<field name="header_spacing">0</field>
<field name="dpi">77</field>
<field name="default" eval="False"/>
</record>
<record id="action_report_product_label_A4_57x35" model="ir.actions.report">
<field name="name">Product Labels 57x35mm (A4, 21 pcs)</field>
<field name="model">print.product.label.line</field>
<field name="report_type">qweb-pdf</field>
<field name="paperformat_id" ref="paperformat_label_a4_blank"/>
<field name="report_name">garazd_product_label.report_product_label_57x35_template</field>
<field name="report_file">garazd_product_label.report_product_label_57x35_template</field>
<field name="print_report_name">'Product Labels 57x35mm'</field>
</record>
<record id="action_report_product_label_50x38" model="ir.actions.report">
<field name="name">Product Labels 50x38mm</field>
<field name="model">print.product.label.line</field>
<field name="report_type">qweb-pdf</field>
<field name="paperformat_id" ref="paperformat_label_50x38"/>
<field name="report_name">garazd_product_label.report_product_label_50x38_template</field>
<field name="report_file">garazd_product_label.report_product_label_50x38_template</field>
<field name="print_report_name">'Product Labels 50x38mm'</field>
</record>
<record id="action_report_product_label_from_template" model="ir.actions.report">
<field name="name">Product Label from your own template</field>
<field name="model">print.product.label.line</field>
<field name="report_type">qweb-pdf</field>
<field name="paperformat_id" ref="garazd_product_label.paperformat_label_a4_blank"/>
<field name="report_name">garazd_product_label.report_product_label_from_template</field>
<field name="report_file">garazd_product_label.report_product_label_from_template</field>
<field name="print_report_name">'Product Labels Custom Design'</field>
</record>
</odoo>
@@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<template id="label_57x35">
<table class="table" style="margin: 0; padding: 0;">
<tr height="144px" style="border:0;margin:0;padding:0;">
<td class="col-xs-4 text-center" style="border:0;margin:0;padding:0;">
<div style="overflow:hidden; height:65px !important; width: 215px !important; padding: 5px 5px 0; line-height: 1.3;">
<span t-field="label.product_id.name"/>
<span t-if="label.product_id.product_template_attribute_value_ids"
t-esc="u', '.join(map(lambda x: x.attribute_line_id.attribute_id.name + u': ' + x.name, label.product_id.product_template_attribute_value_ids))"
class="badge"
/>
</div>
<div style="width: 100%; padding: 0; margin: 0; font-size: 21px; font-weight: bold;">
<span t-if="label.product_id.currency_id.position == 'before'" t-field="label.product_id.currency_id.symbol"/>
<span t-field="label.product_id.lst_price"/>
<span t-if="label.product_id.currency_id.position == 'after'" t-field="label.product_id.currency_id.symbol"/>
</div>
<div t-if="label.product_id.default_code" style="width: 100%; padding: 0; margin: 0; font-size: 12px;">
<span t-field="label.product_id.default_code"/>
</div>
<div t-if="label.product_id.barcode" class="text-center align-middle" style="width: 100%; height: 13px; padding: 0 8px;">
<t t-if="label.wizard_id.humanreadable" t-set="show_code" t-value="1"/>
<t t-else="" t-set="show_code" t-value="0" />
<img alt="Barcode" t-if="len(label.product_id.barcode) == 13"
t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s&amp;humanreadable=%s' % ('EAN13', label.product_id.barcode, 600, 100, show_code)"
style="overflow: hidden; width: 100%; height: 1.4rem;"
/>
<img alt="Barcode" t-elif="len(label.product_id.barcode) == 8"
t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s&amp;humanreadable=%s' % ('EAN8', label.product_id.barcode, 600, 100, show_code)"
style="overflow: hidden; width: 100%; height: 1.4rem;"/>
<img alt="Barcode" t-else=""
t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s&amp;humanreadable=%s' % ('Code128', label.product_id.barcode, 600, 100, show_code)"
style="overflow: hidden; width: 100%; height: 1.4rem;"
/>
</div>
</td>
</tr>
</table>
</template>
<template id="report_product_label_57x35_template">
<t t-call="web.html_container">
<t t-call="web.basic_layout">
<t t-set="count" t-value="0" />
<div class="page">
<div class="oe_structure"/>
<t t-foreach="docs" t-as="label">
<t t-set="qty" t-value="1" />
<t t-if="label.qty">
<t t-set="qty" t-value="label.qty" />
</t>
<t t-foreach="list(range(qty))" t-as="index_qty">
<div t-if="count % 21 == 0" style="page-break-after:always;"/>
<div t-if="count % 3 == 0" style="clear:both;"/>
<div t-att-style="'width: 233px; float: left; height: 145px; margin: 0 4px 4px; border: {};'.format('%dpx solid #777;' % label.wizard_id.border_width if label.wizard_id.border_width else '0')">
<t t-call="garazd_product_label.label_57x35"/>
</div>
<t t-set="count" t-value="count+1" />
</t>
</t>
</div>
</t>
</t>
</template>
<template id="report_product_label_50x38_template">
<t t-call="web.html_container">
<t t-call="web.basic_layout">
<t t-foreach="docs" t-as="label">
<t t-set="qty" t-value="1"/>
<t t-if="label.qty" t-set="qty" t-value="label.qty" />
<t t-foreach="list(range(qty))" t-as="index_qty">
<div class="page" style="page-break-after: always;">
<div style="height: 136px !important; width: 165px !important;">
<table class="table" t-att-style="'height: 100%; border: {};'.format('%dpx solid #777;' % label.wizard_id.border_width if label.wizard_id.border_width else '0')">
<tr style="border: 0;">
<td class="text-center" style="padding: 0; margin: 0; border: 0;">
<div style="overflow: hidden; height: 64px !important; font-size: 13px; line-height: 1.2; margin-bottom: 2px;">
<span t-field="label.product_id.name" />
<span t-if="label.product_id.product_template_attribute_value_ids"
t-esc="u', '.join(map(lambda x: x.attribute_line_id.attribute_id.name + u': ' + x.name, label.product_id.product_template_attribute_value_ids))"
class="badge"/>
</div>
<div style="width: 100%; overflow: hidden; height: 26px !important;">
<div style="float: right; width: 60%; font-size: 20px; font-weight: bold; line-height: 1.0; text-align: right; margin-bottom: 0px;">
<span t-if="label.product_id.currency_id.position == 'before'" t-field="label.product_id.currency_id.symbol"/>
<span t-field="label.product_id.lst_price"/>
<span t-if="label.product_id.currency_id.position == 'after'" t-field="label.product_id.currency_id.symbol"/>
</div>
<div style="float: left; width: 40%; font-size: 10px; font-weight: 900; line-height: 1.0; text-align: left; margin-bottom: 0px; padding-top: 6px;">
<span t-if="label.product_id.default_code"><span t-field="label.product_id.default_code"/> </span>
</div>
</div>
<div t-if="label.product_id.barcode" class="text-center align-middle" style="margin: 2px; height: 32px; clear: both;">
<t t-if="label.wizard_id.humanreadable" t-set="show_code" t-value="1"/>
<t t-else="" t-set="show_code" t-value="0" />
<img alt="Barcode" t-if="len(label.product_id.barcode) == 13"
t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s&amp;humanreadable=%s' % ('EAN13', label.product_id.barcode, 600, 100, show_code)"
style="overflow: hidden; width: 100%; height: 2rem;"/>
<img alt="Barcode" t-elif="len(label.product_id.barcode) == 8"
t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s&amp;humanreadable=%s' % ('EAN8', label.product_id.barcode, 600, 100, show_code)"
style="overflow: hidden; width: 100%; height: 2rem;"/>
<img alt="Barcode" t-else=""
t-att-src="'/report/barcode/?type=%s&amp;value=%s&amp;width=%s&amp;height=%s&amp;humanreadable=%s' % ('Code128', label.product_id.barcode, 600, 100, show_code)"
style="overflow: hidden; width: 100%; height: 2rem;"/>
</div>
</td>
</tr>
</table>
</div>
</div>
</t>
</t>
</t>
</t>
</template>
<template id="report_product_label_from_template">
<t t-call="web.basic_layout"/>
</template>
</odoo>
@@ -0,0 +1,3 @@
id,name,model_id/id,group_id/id,perm_read,perm_write,perm_create,perm_unlink
access_print_product_label_line_user,access_print_product_label_line_user,model_print_product_label_line,base.group_user,1,1,1,1
access_print_product_label_user,access_print_product_label_user,model_print_product_label,base.group_user,1,1,1,0
1 id name model_id/id group_id/id perm_read perm_write perm_create perm_unlink
2 access_print_product_label_line_user access_print_product_label_line_user model_print_product_label_line base.group_user 1 1 1 1
3 access_print_product_label_user access_print_product_label_user model_print_product_label base.group_user 1 1 1 0
Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

@@ -0,0 +1,594 @@
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row mt-3">
<ul class="offset-3 col-6 text-left d-md-none list-unstyled pt-5">
<li class="border-top border-bottom"><div class="my-2 mx-sm-2" style="color: #6F649A;"><i class="fa fa-check-circle"></i> Community</div></li>
<li class="border-bottom"><div class="my-2 mx-sm-2" style="color: #694D65;"><i class="fa fa-check-circle"></i> Enterprise</div></li>
</ul>
<div class="col-12 text-right d-none d-md-block">
<span class="m-2" style="float: right; background-color: #694D65; border-color: #694D65; color: #FFFFFF; padding: 5px 18px; border-radius: 15px 0 15px 0; opacity: 1;"><i class="fa fa-check"></i> Enterprise</span>
<span class="m-2" style="float: right; background-color: #6F649A; border-color: #6F649A; color: #FFFFFF; padding: 5px 18px; border-radius: 15px 0 15px 0; opacity: 1;"><i class="fa fa-check"></i> Community</span>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row oe_spaced">
<div class="offset-2 col-8 offset-md-3 col-md-6 offset-lg-0 col-lg-2">
<div class="text-center shadow ml8">
<div class="s_panel_video" data-video-id="0Sem8pMbUyU?rel=0&start=0" style="cursor: pointer; width: 100%;" data-container="body" data-toggle="popover" data-placement="top" data-content="Click on the image to play the video.">
<img class="s_tooltip_tabs_tooltip_image s_figure_link img-fluid rounded-top pb-0" src="banner_youtube.png" alt="Custom Product Labels youtube video tutorial">
</div>
<a href="https://youtu.be/0Sem8pMbUyU" target="_blank" class="btn btn-danger rounded-bottom p-1" role="button" style="width: 100%; font-size: 0.7rem;">Watch on Youtube <i class="fa fa-external-link"></i></a>
</div>
</div>
<div class="offset-xl-1 col-lg-9 d-flex d-column mt-5 mt-lg-0">
<h2 class="h1 align-self-center text-center" style="color: #154577; font-weight: 900; font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">Product label printing easily in Odoo</h2>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row oe_spaced">
<div class="col-12">
<div class="h2 text-left ml8" style="color: #FEA621;"><i class="fa fa-newspaper-o mr8"></i>Description</div>
<div class="media p-2 pt-4 overflow-hidden" style="border-color: #FEA621 !important; border-radius: 0 15px 0 0; border-top-style: solid; border-right-style: solid;">
<div class="py-2 px-md-5 lead w-100" style="line-height: 2.5rem;"><p>There are a lot of cases when company business processes require having the ability to print product barcode labels. However, different printers and label makers use varied paper formats and label designs can be individual for each company.</p>
<p>The <a href="https://apps.odoo.com/apps/modules/browse?search=product+label&amp;repo_maintainer_id=119796">Odoo Product Labels</a> app family by <b>Garazd Creation</b> solves this business need and gives a usable tool to generate and print product labels with required sizes.</p>
<p class="pt-3">This module allows printing custom product labels with barcode on various paper formats. It includes two label templates:</p>
<ul>
<li><b>57x35mm</b> (21 pcs on the A4 paper format, 3 pcs x 7 rows)</li>
<li><b>50x38mm</b> (the Dymo label, 2" x 1.5")</li>
</ul>
</div>
</div>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row oe_spaced">
<div class="col-12">
<div class="h2 text-left ml8" style="color: #FEA621;"><i class="fa fa-check-square-o mr8"></i>Benefits</div>
<div class="s_features_grid p-2 pt-4 o_colored_level" data-snippet="s_features_grid" data-name="Features Grid" style="border-color: #FEA621 !important; border-radius: 0 15px 0 0; border-top-style: solid; border-right-style: solid; background-color: #ffa81f14;">
<div class="container p-0">
<div class="row px-md-5">
<div class="col-lg-6 s_col_no_bgcolor pb24">
<div class="row">
<div class="col-lg-12 o_colored_level" data-name="Box">
<i class="s_features_grid_icon fa fa-2x float-left mr32 mr-3 bg-warning fa-youtube-play rounded-circle" style="line-height:5rem; height:5rem; width:5rem; text-align:center; float:left;"></i>
<div class="s_features_grid_content">
<div class="h4 pt-2">Watch Demo</div>
<p>Watch the video tutorial</p>
</div>
</div>
</div>
</div>
<div class="col-lg-6 s_col_no_bgcolor pb24">
<div class="row">
<div class="col-lg-12 o_colored_level" data-name="Box">
<i class="s_features_grid_icon fa fa-2x float-left mr32 mr-3 bg-warning fa-check-square-o rounded-circle" style="line-height:5rem; height:5rem; width:5rem; text-align:center; float:left;"></i>
<div class="s_features_grid_content">
<div class="h4 pt-2">Tested</div>
<p>Include unit tests</p>
</div>
</div>
</div>
</div>
<div class="col-lg-6 s_col_no_bgcolor pb24">
<div class="row">
<div class="col-lg-12 o_colored_level" data-name="Box">
<i class="s_features_grid_icon fa fa-2x float-left mr32 mr-3 bg-warning fa-edit rounded-circle" style="line-height:5rem; height:5rem; width:5rem; text-align:center; float:left;"></i>
<div class="s_features_grid_content">
<div class="h4 pt-2">Customize</div>
<p>Contact us for improvements and changes</p>
</div>
</div>
</div>
</div>
<div class="col-lg-6 s_col_no_bgcolor pb24">
<div class="row">
<div class="col-lg-12 o_colored_level" data-name="Box">
<i class="s_features_grid_icon fa fa-2x float-left mr32 mr-3 bg-dark fa-search rounded-circle" style="line-height:5rem; height:5rem; width:5rem; text-align:center; float:left;"></i>
<div class="s_features_grid_content">
<div class="h4 pt-2">Try me</div>
<p>Demo &amp; Test. Click on the "Live Preview" button</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row oe_spaced">
<div class="col-12">
<section class="oe_container" style="font-family: 'Montserrat','Odoo Unicode Support Noto',sans-serif; line-height: 2rem;">
<div class="h2 text-left ml8" style="color: #FEA621;"><i class="fa fa-mouse-pointer mr8"></i>Product Selection</div>
<div class="media p-2 pt-4 border-top border-right" style="border-color: #FEA621 !important; border-radius: 0 15px 0 0;">
<div class="media-body">
<div class="py-2 px-md-5" style="line-height: 2rem;">
To print labels by the wizard, go to the "<b>Products</b>" or "<b>Product Variants</b>" menu and select one or several products.
Then click on the "<b>Custom Product Labels</b>" in the "<b>Print</b>" menu.
</div>
<div class="text-center my-5 mx-md-5">
<img src="print_product_label_select_products.png" class="w-100 img-fluid rounded shadow-lg border" alt="Odoo 14.0 select products to print">
</div>
<blockquote class="py-2 my-3 ml-md-5">By using our additional modules, you will also be able to select products from:
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_picking/">Stock Pickings</a>,
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_packaging/">Product Packaging</a>,
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_purchase/">Purchase Orders</a>,
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_mrp/">Manufacturing Orders</a>.
</blockquote>
</div>
</div>
</section>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row oe_spaced">
<div class="col-12">
<section class="oe_container" style="font-family: 'Montserrat','Odoo Unicode Support Noto',sans-serif; line-height: 2rem;">
<div class="h2 text-left ml8" style="color: #FEA621;"><i class="fa fa-gears mr8"></i>Label Settings</div>
<div class="media p-2 pt-4 border-top border-right bg-light" style="border-color: #FEA621 !important; border-radius: 0 15px 0 0;">
<div class="media-body">
<div class="h3 mt-4 p-2 pl-md-5">Label Settings</div>
<div class="py-2 px-md-5" style="line-height: 2rem;">
In the print wizard form:
</div>
<ol class="py-2 mx-md-3">
<li>Select a <b>Label Template</b>.</li>
<blockquote>
Templates can be in a variety of designs, sizes, and paper formats. Look at our <a href="https://apps.odoo.com/apps/modules/browse?search=garazd_product_label&amp;repo_maintainer_id=119796">other related modules</a>.
</blockquote>
<li>Specify the number of labels you want to print</li>
<blockquote> You can enter a quantity value or use <i class="fa fa-minus"></i> / <i class="fa fa-plus"></i> buttons.</blockquote>
<li>If you need to set a specific quantity for each label, enter the value and click on <b>Set quantity</b>.</li>
<li>After changing the label quantities, you can restore the initial values by clicking the button <i class="fa fa-undo"></i>.</li>
<li>To sort labels by product, click on this button.</li>
<li>You can reorder the labels manually or deactivate some labels to avoid printing them.</li>
</ol>
<div class="text-center my-5 mx-md-5">
<img src="print_product_label_settings.png" class="w-100 img-fluid rounded shadow-lg border" alt="Odoo 14.0 product label settings">
</div>
<div class="h3 mt-4 p-2 pl-md-5">Label Options</div>
<div class="py-2 px-md-5" style="line-height: 2rem;">
You can also set some label options on the tab <b>Options</b>:
</div>
<ul class="py-2 mx-md-5">
<li><b>Language</b> - to specify the language to translate label fields.</li>
<li><b>Human readable barcode</b> - to print a barcode digit code on the labels.</li>
<li><b>Border</b> - to set the label border width.</li>
<blockquote>Set to <b>0</b> to print labels without border.</blockquote>
<li><b>Company</b> - select a company if your label's data is related from the company.</li>
</ul>
<div class="text-center my-5 mx-md-5">
<img src="print_product_label_options.png" class="w-100 img-fluid rounded shadow-lg border" alt="Odoo 14.0 product label options">
</div>
<div class="h3 mt-4 p-2 pl-md-5">Label Printing</div>
<div class="py-2 px-md-5 mb-4" style="line-height: 2rem;">
Finally, you can preview the labels before printing, by clicking on the <span class="btn btn-sm btn-secondary"><i class="fa fa-search"/> PREVIEW</span> button, or print them with the <span class="btn btn-sm btn-primary"><i class="fa fa-print"/> PRINT</span>
</div>
</div>
</div>
</section>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row oe_spaced">
<div class="col-12">
<section class="oe_container" style="font-family: 'Montserrat','Odoo Unicode Support Noto',sans-serif; line-height: 2rem;">
<div class="h2 text-left pl-2" style="color: #FEA621;"><i class="fa fa-paint-brush mr8"></i>Design your own label</div>
<div class="mb-3 border-top border-right" style="background-color: #FEA621; border-color: #FEA621 !important; border-radius: 0 15px 0 0;">
<div class="container p-0">
<div class="py-2 px-md-5 text-white d-flex justify-content-center" style="line-height: 2rem; font-size: 1.2rem;">
<span class="my-auto">Create a variety of labels with awesome designs using the </span>
<i class="fa fa-angle-double-right fa-2x px-3 my-auto"></i>
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_pro/" class="btn btn-light text-primary my-auto">Product Label Builder</a>
</div>
</div>
</div>
</section>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row oe_spaced">
<div class="col-12">
<section class="oe_container" style="font-family: 'Montserrat','Odoo Unicode Support Noto',sans-serif; line-height: 2rem;">
<div class="h2 text-left ml8" style="color: #FEA621;"><i class="fa fa-barcode mr8"></i>Label Samples</div>
<div class="media p-2 pt-4 border-top border-right" style="border-color: #FEA621 !important; border-radius: 0 15px 0 0;">
<div class="media-body">
<div class="py-2 px-md-5" style="line-height: 2rem;">
Labels will be generated in the PDF format:
</div>
<div class="text-center my-5 mx-md-5">
<img src="product_barcode_label_50x38mm.png" class="w-100 w-lg-25 img-fluid rounded shadow-lg border" alt="Odoo 14.0 Custom Product Labels">
</div>
<div class="text-center my-5 mx-md-5">
<img src="product_barcode_label_A4_57x35mm.png" class="w-100 w-lg-50 img-fluid rounded shadow-lg border" alt="Odoo 14.0 Custom Product Labels">
</div>
</div>
</div>
</section>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat','Odoo Unicode Support Noto',sans-serif;">
<div class="row oe_spaced">
<div class="col-12">
<div class="h2 text-left pl-2 pt-3" style="color: #FEA621; font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">Related Modules</div>
<div class="mb-3 bg-light" style="border-color:#FEA621 !important; border-radius: 0 15px 0 0; border-top-style: solid; border-right-style: solid;">
<div id="related_modules" class="carousel slide mt-2 mx-3" data-ride="carousel" data-interval="15000" data-pause="hover">
<div class="carousel-inner">
<div class="carousel-item row active" style="min-height: 0px;">
<div class="col-xs-12 col-sm-4 col-md-4 my-4 px-3" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_pro/" target="_blank">
<div class="card shadow-sm border rounded deep-1 deep_hover">
<img class="img img-responsive center-block border-bottom w-100" src="banner_garazd_product_label_pro.png" alt="Odoo App Product Label Builder" title="Product Label Builder | Product Barcode Label Building and Printing | Professional Tool to Print Labels | Barcode Product Label Builder | Product Label Designer | Sticker Label Maker | Dymo Label Maker | Barcode Label Generator | Direct Print">
<div class="card-body">
<div class="card-title h5 text-nowrap text-truncate" title="Product Label Builder">Product Label Builder</div>
<p class="card-text small text-nowrap text-truncate" title="Product Barcode Label Building and Printing | Professional Tool to Print Labels | Barcode Product Label Builder | Product Label Designer | Sticker Label Maker | Dymo Label Maker | Barcode Label Generator | Direct Print">Product Barcode Label Building and Printing | Professional Tool to Print Labels | Barcode Product Label Builder | Product Label Designer | Sticker Label Maker | Dymo Label Maker | Barcode Label Generator | Direct Print</p>
</div>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 my-4 px-3" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_picking/" target="_blank">
<div class="card shadow-sm border rounded deep-1 deep_hover">
<img class="img img-responsive center-block border-bottom w-100" src="banner_garazd_product_label_picking.png" alt="Odoo App Stock Product Labels" title="Stock Product Labels | Print custom product barcode labels for stock transfers | Product Barcode Labels Printing | Print Product Labels | Barcode Product Labels Printinf from Stock | Barcode labels for inventory | Label Inventory Tag">
<div class="card-body">
<div class="card-title h5 text-nowrap text-truncate" title="Stock Product Labels">Stock Product Labels</div>
<p class="card-text small text-nowrap text-truncate" title="Print custom product barcode labels for stock transfers | Product Barcode Labels Printing | Print Product Labels | Barcode Product Labels Printinf from Stock | Barcode labels for inventory | Label Inventory Tag">Print custom product barcode labels for stock transfers | Product Barcode Labels Printing | Print Product Labels | Barcode Product Labels Printinf from Stock | Barcode labels for inventory | Label Inventory Tag</p>
</div>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 my-4 px-3" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_purchase/" target="_blank">
<div class="card shadow-sm border rounded deep-1 deep_hover">
<img class="img img-responsive center-block border-bottom w-100" src="banner_garazd_product_label_purchase.png" alt="Odoo App Purchase Product Labels" title="Purchase Product Labels | Print custom product barcode labels for purchase orders | Barcode product label printing from purchase order">
<div class="card-body">
<div class="card-title h5 text-nowrap text-truncate" title="Purchase Product Labels">Purchase Product Labels</div>
<p class="card-text small text-nowrap text-truncate" title="Print custom product barcode labels for purchase orders | Barcode product label printing from purchase order">Print custom product barcode labels for purchase orders | Barcode product label printing from purchase order</p>
</div>
</div>
</a>
</div>
</div>
<div class="carousel-item row" style="min-height: 0px;">
<div class="col-xs-12 col-sm-4 col-md-4 my-4 px-3" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_packaging/" target="_blank">
<div class="card shadow-sm border rounded deep-1 deep_hover">
<img class="img img-responsive center-block border-bottom w-100" src="banner_garazd_product_label_packaging.png" alt="Odoo App Product Packaging Labels" title="Product Packaging Labels | Custom Product Packagings Labels | Product Barcode Labels Printing | Print Product Labels">
<div class="card-body">
<div class="card-title h5 text-nowrap text-truncate" title="Product Packaging Labels">Product Packaging Labels</div>
<p class="card-text small text-nowrap text-truncate" title="Custom Product Packagings Labels | Product Barcode Labels Printing | Print Product Labels">Custom Product Packagings Labels | Product Barcode Labels Printing | Print Product Labels</p>
</div>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 my-4 px-3" style="float:left">
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label_mrp/" target="_blank">
<div class="card shadow-sm border rounded deep-1 deep_hover">
<img class="img img-responsive center-block border-bottom w-100" src="banner_garazd_product_label_mrp.png" alt="Odoo App MRP Product Labels" title="MRP Product Labels | Custom Product Labels in Manufacturing | Barcode Product Labels Printinf from Manufacturing">
<div class="card-body">
<div class="card-title h5 text-nowrap text-truncate" title="MRP Product Labels">MRP Product Labels</div>
<p class="card-text small text-nowrap text-truncate" title="Custom Product Labels in Manufacturing | Barcode Product Labels Printinf from Manufacturing">Custom Product Labels in Manufacturing | Barcode Product Labels Printinf from Manufacturing</p>
</div>
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 my-4 px-3" style="float:left">
<a href="https://apps.odoo.com/apps/modules/17.0/garazd_product_label_account/" target="_blank">
<div class="card shadow-sm border rounded deep-1 deep_hover">
<img class="img img-responsive center-block border-bottom w-100" src="banner_garazd_product_label_account.png" alt="Odoo App Account Product Labels" title="Account Product Labels | Product Labels with Accounting Features | Barcode Labels with VAT | Product Labels with Tax-included prices">
<div class="card-body">
<div class="card-title h5 text-nowrap text-truncate" title="Account Product Labels">Account Product Labels</div>
<p class="card-text small text-nowrap text-truncate" title="Product Labels with Accounting Features | Barcode Labels with VAT | Product Labels with Tax-included prices">Product Labels with Accounting Features | Barcode Labels with VAT | Product Labels with Tax-included prices</p>
</div>
</div>
</a>
</div>
</div>
</div>
<!-- Control arrows -->
<a class="carousel-control-prev w-0" href="#related_modules" data-slide="prev" style="color: #FEA621;">
<span class="carousel-control-prev-icon"><i class="fa fa-chevron-left fa-2x"></i></span>
</a>
<a class="carousel-control-next w-0" href="#related_modules" data-slide="next" style="color: #FEA621;">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right fa-2x"></i></span>
</a>
</div>
</div>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif; background-color: #FEA621; border-color: #fea621; padding: 12px 28px; border-radius: 15px 0 15px 0;">
<div class="row my-2">
<div class="col-lg-4 text-center mb-5 mb-lg-0">
<div class="h3 p-2 mb-2 font-weight-bold">Contact Us</div>
<div class="lead text-white pb-2">Support, customizations, and development</div>
<div class="w-100 w-md-75 w-lg-100 my-1 pl-3 text-nowrap text-truncate btn btn-dark rounded">
<i class="fa fa-envelope fa-fw" style="font-size:1.2rem;"></i>
<a href="mailto:support@garazd.biz" target="_blank">support@garazd.biz</a>
</div>
<div class="w-100 w-md-75 w-lg-100 my-1 pl-3 text-nowrap text-truncate btn btn-dark rounded">
<i class="fa fa-skype fa-fw" style="font-size:1.2rem;"></i>
<span>Skype: </span>
<a href="skype:live:7f0648d653072c5f?chat" target="_blank">GarazdCreation</a>
</div>
<div class="w-100 w-md-75 w-lg-100 m-auto my-1 pl-3 text-nowrap text-truncate btn-light border border-dark rounded" style="line-height: 2.4rem;">
<a href="https://garazd.biz/contactus" target="_blank">https://garazd.biz/contactus</a>
</div>
</div>
<div class="col-12 col-lg-4 border-left border-right">
<div class="h3 p-2 mb-3 text-center font-weight-bold">Our expertise</div>
<div class="text-left">
<div class="my-3 pl-3 text-nowrap text-truncate lead text-white" data-container="body" data-toggle="popover" data-placement="top" data-content="Garazd Creation is official Odoo Partner with the status 'Learning Partner'.">
<i class="fa fa-handshake-o fa-fw"></i> Odoo Learning Partner
</div>
<div class="my-3 pl-3 text-nowrap text-truncate lead text-white" data-container="body" data-toggle="popover" data-placement="top" data-content="Odoo Community Association member.">
<i class="fa fa-group fa-fw"></i> OCA Member
</div>
<div class="my-3 pl-3 text-nowrap text-truncate lead text-white" data-container="body" data-toggle="popover" data-placement="top" data-content="Garazd Creation with Odoo since 2014.">
<i class="fa fa-calendar-check-o fa-fw"></i> With Odoo since 2014
</div>
<div class="my-3 pl-3 lead text-white" data-container="body" data-toggle="popover" data-placement="top" data-content="Over 20,000 app downloads and purchases in Odoo Apps Store.">
<i class="fa fa-download fa-fw"></i> Over 20,000 app downloads and purchases
</div>
<div class="my-3 pl-3 lead text-white" data-container="body" data-toggle="popover" data-placement="top" data-content="Our apps in the TOP 10 on Odoo Apps.">
<i class="fa fa-trophy fa-fw"></i> Our apps in the TOP 10 on Odoo Apps
</div>
</div>
</div>
<div class="col-12 col-lg-4 mt-5 mt-lg-0">
<div class="h3 p-2 text-center font-weight-bold">Explore our apps</div>
<div class="text-center mb-3">
<a href="https://apps.odoo.com/apps/browse?repo_maintainer_id=119796" target="_blank">
<div class="text-black bg-warning shadow-sm rounded">
<i class="fa fa-compass fa-4x py-0"></i>
</div>
</a>
</div>
<div class="h4 p-2 text-center font-weight-bold">Watch and subscribe</div>
<div class="text-center">
<a href="https://www.youtube.com/channel/UCjHB3t-qc6SQmbgnS8bSPOA?sub_confirmation=1" target="_blank">
<div class="text-black bg-warning shadow-sm rounded">
<i class="fa fa-youtube-play fa-4x py-0"></i>
</div>
</a>
</div>
</div>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat', 'Odoo Unicode Support Noto', sans-serif;">
<div class="row mt-5 mb-4 align-items-center">
<div class="col-6 text-left">Version: 14.0.2.3.2</div>
<div class="col-6 text-right" style="text-align: right;"><small>Module design is reserved</small> | Copyright &copy; <a href="https://garazd.biz/" target="_blank">Garazd Creation</a></div>
<section class="oe_container col-12 mt-5" style="font-family: 'Montserrat','Odoo Unicode Support Noto',sans-serif; line-height: 1.75rem;">
<div class="h2 text-left ml8 mr32" style="color: #FEA621;"><i class="fa fa-code-fork mr8"></i>Changelog</div>
<div class="media p-2 pt-4" style="border-color:#FEA621 !important; border-radius: 15px; border: solid;">
<small class="media-body">
<ul class="list-unstyled">
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.2.3.2</span>
<span class="text-muted ml16">2024-10-26</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add method to get PDF.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.2.3.1</span>
<span class="text-muted ml16">2024-08-17</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add UA translations.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.2.3.0</span>
<span class="text-muted ml16">2023-11-18</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Improve getting of labels to print, add excluding of lines with qty=0.</small></li>
<li class="mx-3"><small>Add the "mode" option for technical purposes.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.2.2.0</span>
<span class="text-muted ml16">2023-11-16</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Implement sorting of label lines by a product.</small></li>
<li class="mx-3"><small>Add the sequence for the label lines.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.2.1.0</span>
<span class="text-muted ml16">2023-09-19</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add the settings section "Product Labels".</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.2.0.0</span>
<span class="text-muted ml16">2023-04-06</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add a product label template 50x38 mm.</small></li>
<li class="mx-3"><small>Improve product demo data.</small></li>
<li class="mx-3"><small>Implement a new logic for print wizard.</small></li>
<li class="mx-3"><small>Add a company selection to the wizard.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.1.2.0</span>
<span class="text-muted ml16">2022-12-19</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add the option "Language" to translate product names.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.1.1.1</span>
<span class="text-muted ml16">2022-06-22</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add method "_get_label_to_print" to define actual product lines.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.1.1.0</span>
<span class="text-muted ml16">2022-06-20</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add the option "Border" to define a border width on multi labels on A4, US letter paper formats.</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.1.0.3</span>
<span class="text-muted ml16">2021-12-18</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Add barcode types in the 57x35 label template</small></li>
<li class="mx-3"><small>Add currency symbol position before/after in the 57x35 label template</small></li>
<li class="mx-3"><small>Add option Humanreadable barcode to the wizard</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.1.0.2</span>
<span class="text-muted ml16">2021-05-31</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Fix save_eval error: NameError: name Product_labels_57x35mm is not defined</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.1.0.1</span>
<span class="text-muted ml16">2021-03-28</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>change print_report_name (spaces removed)</small></li>
</ul>
</div>
</li>
<li class="media">
<div class="media-body mb-4">
<div class="h5 ml32 my-1" style="font-size: 1.0rem;">
<span class="font-weight-bold bg-dark text-white rounded py-1 px-3">14.0.1.0.0</span>
<span class="text-muted ml16">2021-02-18</span>
</div>
<ul class="mt-2">
<li class="mx-3"><small>Migrate to 14.0</small></li>
</ul>
</div>
</li>
</ul>
</div>
</small>
</div>
</section>
</div>
</section>
<section class="oe_container" style="font-family: 'Montserrat','Odoo Unicode Support Noto',sans-serif;">
<div class="container" id="odoo-app-rating">
<div class="row my-4 py-3 bg-light" style="padding: 12px 28px; border-radius: 0 0 15px 15px;">
<div class="col d-flex justify-content-center text-center" style="color: #FEA621;">
<i class="fa fa-fw fa-thumbs-o-up fa-4x"></i>
<span class="my-auto mx-5 display-4">
<a href="https://apps.odoo.com/apps/modules/14.0/garazd_product_label/#odoo-app-rating" class="btn btn-lg btn-warning text-white rounded">Rate the app</a>
- support us to do more!
</span>
<i class="fa fa-fw fa-angle-double-down fa-4x"></i>
</div>
<div>
</div>
</section>
Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

+1
View File
@@ -0,0 +1 @@
from . import test_print_product_label
@@ -0,0 +1,67 @@
from odoo.tests.common import TransactionCase
from odoo.tools import test_reports
class TestPrintProductLabel(TransactionCase):
def setUp(self):
super(TestPrintProductLabel, self).setUp()
self.product_chair = self.env.ref('product.product_product_12')
self.product_drawer = self.env.ref('product.product_product_27')
def test_print_wizard(self):
ctx = {
'active_model': 'product.product',
'default_product_ids': [
self.product_chair.id,
self.product_drawer.id,
],
}
wizard = self.env['print.product.label'].with_context(**ctx).create({})
self.assertEqual(len(wizard.label_ids), 2)
test_reports.try_report(
self.env.cr,
self.env.uid,
'garazd_product_label.report_product_label_57x35_template',
ids=wizard.label_ids.ids,
our_module='garazd_product_label'
)
def test_action_product_product_label_print(self):
ctx = {
'active_model': 'product.product',
'active_ids': [
self.product_chair.id,
self.product_drawer.id,
],
}
data_dict = {}
test_reports.try_report_action(
self.env.cr,
self.env.uid,
'action_print_label_from_product',
context=ctx,
wiz_data=data_dict,
wiz_buttons=['action_print'],
our_module='garazd_product_label'
)
def test_action_product_template_label_print(self):
ctx = {
'active_model': 'product.template',
'active_ids': [
self.product_chair.product_tmpl_id.id,
self.product_drawer.product_tmpl_id.id,
],
}
data_dict = {}
test_reports.try_report_action(
self.env.cr,
self.env.uid,
'action_print_label_from_template',
context=ctx,
wiz_data=data_dict,
wiz_buttons=['action_print'],
our_module='garazd_product_label'
)
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit.garazd_product_label</field>
<field name="model">res.config.settings</field>
<field name="inherit_id" ref="product.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='product_general_settings']" position="after">
<h2>Product Labels</h2>
<div class="row mt16 o_settings_container" id="garazd_product_label_setting"/>
</xpath>
</field>
</record>
</odoo>
+2
View File
@@ -0,0 +1,2 @@
from . import print_product_label_line
from . import print_product_label
@@ -0,0 +1,165 @@
# Copyright © 2018 Garazd Creation (<https://garazd.biz>)
# @author: Yurii Razumovskyi (<support@garazd.biz>)
# @author: Iryna Razumovska (<support@garazd.biz>)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html).
import base64
from typing import List
from odoo import api, fields, models, _
from odoo.exceptions import UserError
from odoo.addons.base.models.res_partner import _lang_get
class PrintProductLabel(models.TransientModel):
_name = "print.product.label"
_description = 'Wizard to print Product Labels'
@api.model
def _complete_label_fields(self, label_ids: List[int]) -> List[int]:
"""Set additional fields for product labels. Method to override."""
# Increase a label sequence
labels = self.env['print.product.label.line'].browse(label_ids)
for seq, label in enumerate(labels):
label.sequence = 1000 + seq
return label_ids
@api.model
def _get_product_label_ids(self):
res = []
# flake8: noqa: E501
if self._context.get('active_model') == 'product.template':
products = self.env[self._context.get('active_model')].browse(self._context.get('default_product_ids'))
for product in products:
label = self.env['print.product.label.line'].create({
'product_id': product.product_variant_id.id,
})
res.append(label.id)
elif self._context.get('active_model') == 'product.product':
products = self.env[self._context.get('active_model')].browse(self._context.get('default_product_ids'))
for product in products:
label = self.env['print.product.label.line'].create({
'product_id': product.id,
})
res.append(label.id)
res = self._complete_label_fields(res)
return res
name = fields.Char(default=_('Print Product Labels'))
message = fields.Char(readonly=True)
output = fields.Selection(
selection=[('pdf', 'PDF')],
string='Print to',
default='pdf',
)
mode = fields.Selection(selection=[], help='Technical field')
label_ids = fields.One2many(
comodel_name='print.product.label.line',
inverse_name='wizard_id',
string='Labels for Products',
default=_get_product_label_ids,
)
report_id = fields.Many2one(
comodel_name='ir.actions.report',
string='Label',
domain=[('model', '=', 'print.product.label.line')],
)
is_template_report = fields.Boolean(compute='_compute_is_template_report')
qty_per_product = fields.Integer(
string='Label quantity per product',
default=1,
)
# Options
humanreadable = fields.Boolean(
string='Human readable barcode',
help='Print digital code of barcode.',
default=False,
)
border_width = fields.Integer(
string='Border',
help='Border width for labels (in pixels). Set "0" for no border.'
)
lang = fields.Selection(
selection=_lang_get,
string='Language',
help="The language that will be used to translate label names.",
)
company_id = fields.Many2one(
comodel_name='res.company',
help='Specify a company for product labels.'
)
@api.depends('report_id')
def _compute_is_template_report(self):
for wizard in self:
# flake8: noqa: E501
wizard.is_template_report = self.report_id == self.env.ref('garazd_product_label.action_report_product_label_from_template')
def get_labels_to_print(self):
self.ensure_one()
labels = self.label_ids.filtered(lambda l: l.selected and l.qty)
if not labels:
raise UserError(
_('Nothing to print, set the quantity of labels in the table.'))
return labels
def _get_report_action_params(self):
"""Return two params for a report action: record "ids" and "data"."""
self.ensure_one()
return self.get_labels_to_print().ids, None
def _prepare_report(self):
self.ensure_one()
mode = self._context.get('print_mode', 'pdf')
if not self.report_id:
raise UserError(_('Please select a label type.'))
report = self.report_id.with_context(discard_logo_check=True, lang=self.lang)
report.sudo().write({'report_type': f'qweb-{mode}'})
return report
def action_print(self):
"""Print labels."""
self.ensure_one()
report = self._prepare_report()
return report.report_action(*self._get_report_action_params())
def action_set_qty(self):
"""Set a specific number of labels for all lines."""
self.ensure_one()
self.label_ids.write({'qty': self.qty_per_product})
def action_restore_initial_qty(self):
"""Restore the initial number of labels for all lines."""
self.ensure_one()
for label in self.label_ids:
if label.qty_initial:
label.update({'qty': label.qty_initial})
@api.model
def _set_sequence(self, lbl, seq, processed):
if lbl in processed:
return seq, processed
lbl.sequence = seq
seq += 1
processed += lbl
return seq, processed
def action_sort_by_product(self):
self.ensure_one()
sequence = 1000
processed_labels = self.env['print.product.label.line'].browse()
# flake8: noqa: E501
for label in self.label_ids:
sequence, processed_labels = self._set_sequence(label, sequence, processed_labels)
tmpl_labels = self.label_ids.filtered(lambda l: l.product_id.product_tmpl_id == label.product_id.product_tmpl_id).sorted(lambda l: l.product_id.id, reverse=True) - label
for tmpl_label in tmpl_labels:
sequence, processed_labels = self._set_sequence(tmpl_label, sequence, processed_labels)
product_labels = tmpl_labels.filtered(lambda l: l.product_id == label.product_id) - tmpl_label
for product_label in product_labels:
sequence, processed_labels = self._set_sequence(product_label, sequence, processed_labels)
def get_pdf(self):
self.ensure_one()
report = self.with_context(print_mode='pdf')._prepare_report()
pdf_data = report._render_qweb_pdf(*self._get_report_action_params())
return base64.b64encode(pdf_data[0])
@@ -0,0 +1,49 @@
# Copyright © 2018 Garazd Creation (<https://garazd.biz>)
# @author: Yurii Razumovskyi (<support@garazd.biz>)
# @author: Iryna Razumovska (<support@garazd.biz>)
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl-3.0.html).
from odoo import api, fields, models
class PrintProductLabelLine(models.TransientModel):
_name = "print.product.label.line"
_description = 'Line with a Product Label Data'
_order = 'sequence'
sequence = fields.Integer(default=900)
selected = fields.Boolean(string='Print', default=True)
wizard_id = fields.Many2one(comodel_name='print.product.label') # Not make required
product_id = fields.Many2one(comodel_name='product.product', required=True)
barcode = fields.Char(compute='_compute_barcode')
qty_initial = fields.Integer(string='Initial Qty', default=1)
qty = fields.Integer(string='Label Qty', default=1)
company_id = fields.Many2one(
comodel_name='res.company',
compute='_compute_company_id',
)
@api.depends('wizard_id.company_id')
def _compute_company_id(self):
for label in self:
label.company_id = \
label.wizard_id.company_id and label.wizard_id.company_id.id \
or self.env.user.company_id.id
@api.depends('product_id')
def _compute_barcode(self):
for label in self:
label.barcode = label.product_id.barcode
def action_plus_qty(self):
self.ensure_one()
if not self.qty:
self.update({'selected': True})
self.update({'qty': self.qty + 1})
def action_minus_qty(self):
self.ensure_one()
if self.qty > 0:
self.update({'qty': self.qty - 1})
if not self.qty:
self.update({'selected': False})
@@ -0,0 +1,104 @@
<?xml version="1.0" encoding="UTF-8"?>
<odoo>
<record id="print_product_label_view_form" model="ir.ui.view">
<field name="name">print.product.label.view.form</field>
<field name="model">print.product.label</field>
<field name="arch" type="xml">
<form create="false" string="Print Product Labels">
<header>
<button name="action_print"
string="Print"
help="Print product labels"
type="object"
icon="fa-print"
class="btn-primary mr8"/>
<button name="action_print"
string="Preview"
context="{'print_mode': 'html'}"
help="Preview product labels"
type="object"
icon="fa-search"
class="btn-secondary mr8"/>
</header>
<div class="oe_button_box mb-0" name="button_box"/>
<field name="mode" invisible="1"/>
<field name="is_template_report" invisible="1"/>
<div class="alert alert-info text-center mb-3"
attrs="{'invisible':[('message', '=', False)]}"
role="alert">
<field name="message"/>
</div>
<group col="6" colspan="2">
<group string="Output" name="output_format" col="1" colspan="1">
<field name="output" widget="badge"/>
</group>
<group string="Label" name="label_report" col="2" colspan="2">
<field name="report_id" string="Label" widget="radio" nolabel="1"/>
</group>
<group string="Template" name="label_template" col="2" colspan="3" attrs="{'invisible': [('is_template_report', '=', False)]}">
<a name="label_builder_link" attrs="{'invisible': [('is_template_report', '=', False)]}" href="https://garazd.biz/r/LfW" title="How to get Product Label Builder" target="_blank" rel="noopener noreferrer">
<span>Get the Label Builder to create your own labels</span>
</a>
</group>
</group>
<div name="extra_action" class="oe_row">
<button name="action_sort_by_product" title="Sort labels by a product" icon="fa-sort-amount-desc" type="object" class="btn-xs btn-light"/>
<span class="text-muted px-3">|</span>
<field name="qty_per_product" class="mr-2 mt-1 text-right" help="Label quantity per product" style="width: 40px !important;"/>
<button name="action_set_qty" string="Set quantity" help="Set a certain quantity for each line." type="object" class="btn-xs btn-light mr-2"/>
<button name="action_restore_initial_qty" title="Restore initial quantity" help="Restore initial quantity" icon="fa-undo" type="object" class="btn-xs btn-light"/>
</div>
<notebook>
<page string="Labels" name="labels">
<field name="label_ids" mode="tree">
<tree editable="top" decoration-muted="qty==0">
<field name="sequence" widget="handle" width="0.5"/>
<field name="selected" widget="boolean_toggle"/>
<field name="product_id"/>
<field name="barcode" optional="show"/>
<field name="company_id" groups="base.group_multi_company" optional="hide"/>
<button name="action_minus_qty" type="object" title="Decrease Qty" icon="fa-minus" class="btn-light"/>
<field name="qty" sum="Total" width="0.6" class="text-center font-weight-bold"/>
<button name="action_plus_qty" type="object" title="Increase Qty" icon="fa-plus" class="btn-light"/>
</tree>
</field>
</page>
<page string="Options" name="options">
<group name="general_options" class="o_label_nowrap">
<group>
<field name="lang" widget="radio" options="{'horizontal': true}"/>
<field name="humanreadable" widget="boolean_toggle" />
<field name="border_width" />
</group>
<group>
<field name="company_id" widget="radio" groups="base.group_multi_company"/>
</group>
</group>
</page>
</notebook>
</form>
</field>
</record>
<record id="action_print_label_from_template" model="ir.actions.act_window">
<field name="name">Custom Product Labels</field>
<field name="res_model">print.product.label</field>
<field name="view_mode">form</field>
<field name="target">current</field>
<field name="context">{'default_product_ids': active_ids}</field>
<field name="binding_model_id" ref="product.model_product_template"/>
<field name="binding_type">report</field>
</record>
<record id="action_print_label_from_product" model="ir.actions.act_window">
<field name="name">Custom Product Labels</field>
<field name="res_model">print.product.label</field>
<field name="view_mode">form</field>
<field name="target">current</field>
<field name="context">{'default_product_ids': active_ids}</field>
<field name="binding_model_id" ref="product.model_product_product"/>
<field name="binding_type">report</field>
</record>
</odoo>
+5 -1
View File
@@ -1,6 +1,6 @@
{
'name': 'SCADA for Odoo - Manufacturing Integration',
'version': '3.0.30',
'version': '4.0.31',
'category': 'manufacturing',
'license': 'LGPL-3',
'author': 'PT. Gagak Rimang Teknologi',
@@ -30,9 +30,13 @@
'views/scada_mrp_views.xml',
'views/scada_sensor_reading_view.xml',
'views/scada_api_log_view.xml',
'views/scada_quality_control_view.xml',
'views/scada_equipment_oee_view.xml',
'views/menu.xml',
'data/demo_data.xml',
'data/ir_cron.xml',
'reports/scada_quality_control_report.xml',
'reports/scada_equipment_oee_report.xml',
],
'demo': [
'data/demo_data.xml',
+2
View File
@@ -3,10 +3,12 @@ from . import scada_equipment
from . import scada_material_consumption
from . import scada_mo_weight
from . import scada_equipment_material
from . import scada_equipment_oee
from . import scada_sensor_reading
from . import scada_api_log
from . import scada_health
from . import scada_module
from . import scada_quality_control
from . import mrp_bom
from . import mrp_production
from . import mrp_bom_line
Binary file not shown.
+17
View File
@@ -31,3 +31,20 @@ class MrpProduction(models.Model):
if bom and bom.scada_equipment_id:
vals['scada_equipment_id'] = bom.scada_equipment_id.id
return super().create(vals_list)
def button_mark_done(self):
res = super().button_mark_done()
oee_model = self.env['scada.equipment.oee']
for mo in self:
if mo.state != 'done':
continue
equipment = mo.scada_equipment_id or (mo.bom_id.scada_equipment_id if mo.bom_id else False)
if not equipment:
continue
if oee_model.search([('manufacturing_order_id', '=', mo.id)], limit=1):
continue
vals = oee_model.prepare_from_mo(mo, equipment)
oee_model.create(vals)
return res
+130
View File
@@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class ScadaEquipmentOee(models.Model):
_name = 'scada.equipment.oee'
_description = 'SCADA Equipment OEE Summary'
_order = 'date_done desc, id desc'
_rec_name = 'mo_name'
manufacturing_order_id = fields.Many2one(
'mrp.production',
string='Manufacturing Order',
required=True,
ondelete='restrict'
)
mo_name = fields.Char(
string='MO Name',
related='manufacturing_order_id.name',
store=True,
readonly=True
)
equipment_id = fields.Many2one(
'scada.equipment',
string='Equipment',
required=True,
ondelete='restrict'
)
product_id = fields.Many2one(
'product.product',
string='Product',
related='manufacturing_order_id.product_id',
store=True,
readonly=True
)
date_done = fields.Datetime(
string='Done Date',
default=fields.Datetime.now,
required=True
)
qty_planned = fields.Float(
string='Planned Qty (BoM)',
digits=(12, 3)
)
qty_finished = fields.Float(
string='Actual Finished Qty',
digits=(12, 3)
)
qty_bom_consumption = fields.Float(
string='BoM Consumption (Total)',
digits=(12, 3)
)
qty_actual_consumption = fields.Float(
string='Actual Consumption (Total)',
digits=(12, 3)
)
variance_finished = fields.Float(
string='Finished Variance',
digits=(12, 3)
)
variance_consumption = fields.Float(
string='Consumption Variance',
digits=(12, 3)
)
yield_percent = fields.Float(
string='Yield %',
digits=(16, 3)
)
consumption_ratio = fields.Float(
string='Consumption Ratio %',
digits=(16, 3)
)
notes = fields.Text(string='Notes')
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company
)
_sql_constraints = [
('mo_unique', 'unique(manufacturing_order_id)',
'OEE summary already exists for this manufacturing order.')
]
@staticmethod
def _safe_ratio(numerator, denominator):
return (numerator / denominator * 100.0) if denominator else 0.0
@classmethod
def prepare_from_mo(cls, mo, equipment):
finished_qty = sum(
move.quantity_done for move in mo.move_finished_ids
if move.state != 'cancel'
)
actual_consumed = sum(
move.quantity_done for move in mo.move_raw_ids
if move.state != 'cancel'
)
bom_consumption = 0.0
if mo.bom_id and mo.bom_id.product_qty:
for line in mo.bom_id.bom_line_ids:
bom_consumption += (
(line.product_qty / mo.bom_id.product_qty) * mo.product_qty
)
planned_qty = mo.product_qty or 0.0
variance_finished = finished_qty - planned_qty
variance_consumption = actual_consumed - bom_consumption
return {
'manufacturing_order_id': mo.id,
'equipment_id': equipment.id,
'date_done': mo.date_finished or mo.date_planned_finished or fields.Datetime.now(),
'qty_planned': planned_qty,
'qty_finished': finished_qty,
'qty_bom_consumption': bom_consumption,
'qty_actual_consumption': actual_consumed,
'variance_finished': variance_finished,
'variance_consumption': variance_consumption,
'yield_percent': cls._safe_ratio(finished_qty, planned_qty),
'consumption_ratio': cls._safe_ratio(actual_consumed, bom_consumption),
'company_id': mo.company_id.id,
}
+83
View File
@@ -0,0 +1,83 @@
# -*- coding: utf-8 -*-
from odoo import models, fields
class ScadaQualityControl(models.Model):
_name = 'scada.quality.control'
_description = 'SCADA Quality Control'
_order = 'tanggal_uji desc, id desc'
_rec_name = 'kode'
product_id = fields.Many2one(
'product.product',
string='Product',
required=True,
ondelete='restrict'
)
product_name = fields.Char(
string='Product Name',
related='product_id.name',
store=True,
readonly=True
)
kode = fields.Char(string='Kode', required=True, index=True)
quantity = fields.Float(
string='Quantity',
digits='Product Unit of Measure',
required=True
)
uom_id = fields.Many2one(
'uom.uom',
string='Unit of Measure',
related='product_id.uom_id',
store=True,
readonly=True
)
qc_type = fields.Selection([
('raw', 'Raw Material'),
('finished', 'Finished Goods')
], string='QC Type', required=True, default='finished')
lot_id = fields.Many2one(
'stock.production.lot',
string='Lot/Serial Number'
)
warna = fields.Boolean(string='Warna', default=False)
aroma = fields.Boolean(string='Aroma', default=False)
tekstur = fields.Boolean(string='Tekstur', default=False)
pest = fields.Boolean(string='Pest', default=False)
kemasan = fields.Boolean(string='Kemasan', default=False)
jahitan = fields.Boolean(string='Jahitan', default=False)
label = fields.Boolean(string='Label', default=False)
density = fields.Float(string='Density', digits=(16, 3))
ka_output = fields.Float(string='KA Output', digits=(16, 3))
ka_output_max = fields.Float(string='KA Output Max', digits=(16, 3))
suhu_ruang = fields.Float(string='Suhu Ruang')
suhu_produk = fields.Float(string='Suhu Produk')
umur_barang = fields.Float(string='Umur Barang')
umur_simpan = fields.Float(string='Umur Simpan')
ka_supply = fields.Float(string='KA Supply', digits=(16, 3))
ka_supply_max = fields.Float(string='KA Supply Max', digits=(16, 3))
kadar_air = fields.Float(string='Kadar Air', digits=(16, 3))
ka_process_max = fields.Float(string='KA Process Max', digits=(16, 3))
tanggal_uji = fields.Date(
string='Tanggal Uji',
default=fields.Date.context_today,
required=True
)
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company
)
@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<report
id="report_scada_equipment_oee"
model="scada.equipment.oee"
string="OEE Summary"
report_type="qweb-pdf"
name="grt_scada.report_scada_equipment_oee"
file="grt_scada.report_scada_equipment_oee"
print_report_name="'OEE - %s' % (object.manufacturing_order_id.name or '')"
/>
<template id="report_scada_equipment_oee_document">
<t t-call="web.external_layout">
<t t-foreach="docs" t-as="o">
<div class="page">
<h2>Equipment OEE Summary</h2>
<table class="table table-sm">
<tbody>
<tr>
<th>Date Done</th>
<td><span t-esc="o.date_done"/></td>
<th>Equipment</th>
<td><span t-esc="o.equipment_id.name"/></td>
</tr>
<tr>
<th>MO</th>
<td><span t-esc="o.manufacturing_order_id.name"/></td>
<th>Product</th>
<td><span t-esc="o.product_id.display_name"/></td>
</tr>
</tbody>
</table>
<h3>Finished Quantity</h3>
<table class="table table-sm">
<tbody>
<tr>
<th>Planned</th><td><span t-esc="o.qty_planned"/></td>
<th>Actual</th><td><span t-esc="o.qty_finished"/></td>
<th>Variance</th><td><span t-esc="o.variance_finished"/></td>
</tr>
<tr>
<th>Yield %</th><td><span t-esc="o.yield_percent"/></td>
<th></th><td></td>
<th></th><td></td>
</tr>
</tbody>
</table>
<h3>Consumption</h3>
<table class="table table-sm">
<tbody>
<tr>
<th>BoM Total</th><td><span t-esc="o.qty_bom_consumption"/></td>
<th>Actual Total</th><td><span t-esc="o.qty_actual_consumption"/></td>
<th>Variance</th><td><span t-esc="o.variance_consumption"/></td>
</tr>
<tr>
<th>Ratio %</th><td><span t-esc="o.consumption_ratio"/></td>
<th></th><td></td>
<th></th><td></td>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</data>
</odoo>
@@ -0,0 +1,93 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<report
id="report_scada_quality_control"
model="scada.quality.control"
string="QC Report"
report_type="qweb-pdf"
name="grt_scada.report_scada_quality_control"
file="grt_scada.report_scada_quality_control"
print_report_name="'QC - %s' % (object.kode or '')"
/>
<template id="report_scada_quality_control_document">
<t t-call="web.external_layout">
<t t-foreach="docs" t-as="o">
<div class="page">
<h2>Quality Control Report</h2>
<table class="table table-sm">
<tbody>
<tr>
<th>Date</th>
<td><span t-esc="o.tanggal_uji"/></td>
<th>QC Type</th>
<td><span t-esc="o.qc_type"/></td>
</tr>
<tr>
<th>Product</th>
<td><span t-esc="o.product_id.display_name"/></td>
<th>Code</th>
<td><span t-esc="o.kode"/></td>
</tr>
<tr>
<th>Quantity</th>
<td><span t-esc="o.quantity"/> <span t-esc="o.uom_id.name"/></td>
<th>Lot/Serial</th>
<td><span t-esc="o.lot_id.name"/></td>
</tr>
</tbody>
</table>
<h3>Visual</h3>
<table class="table table-sm">
<tbody>
<tr>
<th>Warna</th><td><span t-esc="'OK' if o.warna else 'NG'"/></td>
<th>Aroma</th><td><span t-esc="'OK' if o.aroma else 'NG'"/></td>
<th>Tekstur</th><td><span t-esc="'OK' if o.tekstur else 'NG'"/></td>
</tr>
<tr>
<th>Pest</th><td><span t-esc="'OK' if o.pest else 'NG'"/></td>
<th>Kemasan</th><td><span t-esc="'OK' if o.kemasan else 'NG'"/></td>
<th>Jahitan</th><td><span t-esc="'OK' if o.jahitan else 'NG'"/></td>
</tr>
<tr>
<th>Label</th><td><span t-esc="'OK' if o.label else 'NG'"/></td>
<th></th><td></td>
<th></th><td></td>
</tr>
</tbody>
</table>
<h3>Kualitas</h3>
<table class="table table-sm">
<tbody>
<tr>
<th>Density</th><td><span t-esc="o.density"/></td>
<th>KA Output</th><td><span t-esc="o.ka_output"/></td>
<th>KA Output Max</th><td><span t-esc="o.ka_output_max"/></td>
</tr>
<tr>
<th>KA Supply</th><td><span t-esc="o.ka_supply"/></td>
<th>KA Supply Max</th><td><span t-esc="o.ka_supply_max"/></td>
<th>Kadar Air</th><td><span t-esc="o.kadar_air"/></td>
</tr>
<tr>
<th>KA Process Max</th><td><span t-esc="o.ka_process_max"/></td>
<th>Suhu Ruang</th><td><span t-esc="o.suhu_ruang"/></td>
<th>Suhu Produk</th><td><span t-esc="o.suhu_produk"/></td>
</tr>
<tr>
<th>Umur Barang</th><td><span t-esc="o.umur_barang"/></td>
<th>Umur Simpan</th><td><span t-esc="o.umur_simpan"/></td>
<th></th><td></td>
</tr>
</tbody>
</table>
</div>
</t>
</t>
</template>
</data>
</odoo>
+6
View File
@@ -13,3 +13,9 @@ access_scada_equipment_material_technician,scada.equipment.material Technician,m
access_scada_mo_weight_manager,scada.mo.weight Manager,model_scada_mo_weight,group_scada_manager,1,1,1,1
access_scada_mo_weight_operator,scada.mo.weight Operator,model_scada_mo_weight,group_scada_operator,1,0,0,0
access_scada_mo_weight_technician,scada.mo.weight Technician,model_scada_mo_weight,group_scada_technician,1,1,0,0
access_scada_quality_control_manager,scada.quality.control Manager,model_scada_quality_control,group_scada_manager,1,1,1,1
access_scada_quality_control_operator,scada.quality.control Operator,model_scada_quality_control,group_scada_operator,1,1,1,0
access_scada_quality_control_technician,scada.quality.control Technician,model_scada_quality_control,group_scada_technician,1,1,1,0
access_scada_equipment_oee_manager,scada.equipment.oee Manager,model_scada_equipment_oee,group_scada_manager,1,1,1,1
access_scada_equipment_oee_operator,scada.equipment.oee Operator,model_scada_equipment_oee,group_scada_operator,1,1,1,0
access_scada_equipment_oee_technician,scada.equipment.oee Technician,model_scada_equipment_oee,group_scada_technician,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
13 access_scada_mo_weight_manager scada.mo.weight Manager model_scada_mo_weight group_scada_manager 1 1 1 1
14 access_scada_mo_weight_operator scada.mo.weight Operator model_scada_mo_weight group_scada_operator 1 0 0 0
15 access_scada_mo_weight_technician scada.mo.weight Technician model_scada_mo_weight group_scada_technician 1 1 0 0
16 access_scada_quality_control_manager scada.quality.control Manager model_scada_quality_control group_scada_manager 1 1 1 1
17 access_scada_quality_control_operator scada.quality.control Operator model_scada_quality_control group_scada_operator 1 1 1 0
18 access_scada_quality_control_technician scada.quality.control Technician model_scada_quality_control group_scada_technician 1 1 1 0
19 access_scada_equipment_oee_manager scada.equipment.oee Manager model_scada_equipment_oee group_scada_manager 1 1 1 1
20 access_scada_equipment_oee_operator scada.equipment.oee Operator model_scada_equipment_oee group_scada_operator 1 1 1 0
21 access_scada_equipment_oee_technician scada.equipment.oee Technician model_scada_equipment_oee group_scada_technician 1 1 1 0
+28
View File
@@ -36,6 +36,34 @@
name="Sensor Readings"
sequence="1"/>
<!-- Quality Control Menu -->
<menuitem
id="menu_scada_quality_control"
parent="menu_scada_root"
name="Quality Control"
sequence="30"/>
<menuitem
id="menu_scada_quality_control_list"
parent="menu_scada_quality_control"
action="action_scada_quality_control"
name="QC Records"
sequence="1"/>
<!-- OEE Summary Menu -->
<menuitem
id="menu_scada_oee"
parent="menu_scada_root"
name="OEE Summary"
sequence="35"/>
<menuitem
id="menu_scada_oee_list"
parent="menu_scada_oee"
action="action_scada_equipment_oee"
name="OEE Results"
sequence="1"/>
<!-- API Logs Menu -->
<menuitem
id="menu_scada_logs"
@@ -0,0 +1,101 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- OEE Tree View -->
<record id="view_scada_equipment_oee_tree" model="ir.ui.view">
<field name="name">scada.equipment.oee.tree</field>
<field name="model">scada.equipment.oee</field>
<field name="arch" type="xml">
<tree string="Equipment OEE Summary" default_order="date_done desc">
<field name="date_done"/>
<field name="equipment_id"/>
<field name="manufacturing_order_id"/>
<field name="product_id"/>
<field name="qty_planned"/>
<field name="qty_finished"/>
<field name="variance_finished"/>
<field name="qty_bom_consumption"/>
<field name="qty_actual_consumption"/>
<field name="variance_consumption"/>
<field name="yield_percent"/>
<field name="consumption_ratio"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<!-- OEE Form View -->
<record id="view_scada_equipment_oee_form" model="ir.ui.view">
<field name="name">scada.equipment.oee.form</field>
<field name="model">scada.equipment.oee</field>
<field name="arch" type="xml">
<form string="Equipment OEE Summary">
<sheet>
<group>
<group>
<field name="date_done"/>
<field name="equipment_id"/>
<field name="manufacturing_order_id"/>
<field name="product_id"/>
</group>
<group>
<field name="qty_planned"/>
<field name="qty_finished"/>
<field name="variance_finished"/>
<field name="yield_percent"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
</group>
<notebook>
<page string="Consumption">
<group>
<group>
<field name="qty_bom_consumption"/>
<field name="qty_actual_consumption"/>
<field name="variance_consumption"/>
<field name="consumption_ratio"/>
</group>
</group>
</page>
<page string="Notes">
<field name="notes" placeholder="Notes..."/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- OEE Search View -->
<record id="view_scada_equipment_oee_search" model="ir.ui.view">
<field name="name">scada.equipment.oee.search</field>
<field name="model">scada.equipment.oee</field>
<field name="arch" type="xml">
<search string="Search OEE Summary">
<field name="equipment_id"/>
<field name="manufacturing_order_id"/>
<field name="product_id"/>
<field name="date_done"/>
<group expand="0" string="Group By">
<filter string="Equipment" name="group_equipment" context="{'group_by':'equipment_id'}"/>
<filter string="Product" name="group_product" context="{'group_by':'product_id'}"/>
<filter string="Date" name="group_date" context="{'group_by':'date_done'}"/>
</group>
</search>
</field>
</record>
<!-- OEE Action -->
<record id="action_scada_equipment_oee" model="ir.actions.act_window">
<field name="name">Equipment OEE Summary</field>
<field name="res_model">scada.equipment.oee</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_scada_equipment_oee_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
OEE summary will be generated when MO is marked done.
</p>
</field>
</record>
</data>
</odoo>
@@ -0,0 +1,118 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- QC Tree View -->
<record id="view_scada_quality_control_tree" model="ir.ui.view">
<field name="name">scada.quality.control.tree</field>
<field name="model">scada.quality.control</field>
<field name="arch" type="xml">
<tree string="Quality Control" default_order="tanggal_uji desc">
<field name="tanggal_uji"/>
<field name="qc_type"/>
<field name="product_id"/>
<field name="kode"/>
<field name="quantity"/>
<field name="uom_id"/>
<field name="lot_id"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<!-- QC Form View -->
<record id="view_scada_quality_control_form" model="ir.ui.view">
<field name="name">scada.quality.control.form</field>
<field name="model">scada.quality.control</field>
<field name="arch" type="xml">
<form string="Quality Control">
<sheet>
<group>
<group>
<field name="tanggal_uji"/>
<field name="qc_type"/>
<field name="product_id"/>
<field name="product_name" readonly="1"/>
<field name="kode"/>
</group>
<group>
<field name="quantity"/>
<field name="uom_id" readonly="1"/>
<field name="lot_id"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
</group>
<notebook>
<page string="Visual">
<group>
<field name="warna"/>
<field name="aroma"/>
<field name="tekstur"/>
<field name="pest"/>
<field name="kemasan"/>
<field name="jahitan"/>
<field name="label"/>
</group>
</page>
<page string="Kualitas">
<group>
<group>
<field name="density"/>
<field name="ka_output"/>
<field name="ka_output_max"/>
<field name="ka_supply"/>
<field name="ka_supply_max"/>
</group>
<group>
<field name="kadar_air"/>
<field name="ka_process_max"/>
<field name="suhu_ruang"/>
<field name="suhu_produk"/>
<field name="umur_barang"/>
<field name="umur_simpan"/>
</group>
</group>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- QC Search View -->
<record id="view_scada_quality_control_search" model="ir.ui.view">
<field name="name">scada.quality.control.search</field>
<field name="model">scada.quality.control</field>
<field name="arch" type="xml">
<search string="Search QC">
<field name="kode"/>
<field name="product_id"/>
<field name="qc_type"/>
<field name="tanggal_uji"/>
<filter string="Raw Material" name="qc_raw" domain="[('qc_type','=','raw')]"/>
<filter string="Finished Goods" name="qc_finished" domain="[('qc_type','=','finished')]"/>
<group expand="0" string="Group By">
<filter string="Product" name="group_product" context="{'group_by':'product_id'}"/>
<filter string="QC Type" name="group_type" context="{'group_by':'qc_type'}"/>
<filter string="Tanggal Uji" name="group_date" context="{'group_by':'tanggal_uji'}"/>
</group>
</search>
</field>
</record>
<!-- QC Action -->
<record id="action_scada_quality_control" model="ir.actions.act_window">
<field name="name">Quality Control</field>
<field name="res_model">scada.quality.control</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_scada_quality_control_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your first QC record
</p>
<p>
QC record tracks quality attributes for raw materials and finished goods.
</p>
</field>
</record>
</data>
</odoo>
+3294
View File
File diff suppressed because it is too large Load Diff
+118
View File
@@ -0,0 +1,118 @@
# Manufacturing Serial Number Module
## Deskripsi
Modul ini menyediakan sistem tracking serial number otomatis untuk produk hasil manufacturing di Odoo 14 Community Edition.
## Fitur Utama
### 1. **Auto Generate Serial Number**
- Serial number unik dibuat otomatis setiap kali Manufacturing Order selesai
- Format: `PREFIX-SEQUENCE-RANDOMCODE` (contoh: `MFG-S000001-A3X9`)
- Prefix bisa menggunakan kode produk (Product Reference)
### 2. **Integrasi dengan Manufacturing Order**
- Checkbox "Auto Generate Serial" di Manufacturing Order
- Smart button untuk melihat semua serial yang dihasilkan
- Tab "Serial Numbers" untuk melihat detail serial
- Button manual "Generate Serials Now" jika perlu
### 3. **Product Configuration**
- Field "Use Manufacturing Serial" di Product form
- Smart button untuk melihat history serial per produk
- Counter jumlah serial yang sudah dihasilkan
### 4. **Serial Number Management**
- State tracking: Draft → Produced → Delivered → Cancelled
- Link ke Manufacturing Order
- Search & filter berdasarkan product, state, date
- Group by product, MO, state, atau date
### 5. **Security & Access Rights**
- MRP User: Read, Write, Create
- MRP Manager: Full access termasuk Delete
- Stock User: Read only
## Instalasi
1. Copy folder `manufacturing_serial_number` ke direktori addons Odoo
2. Restart Odoo server
3. Aktifkan Developer Mode
4. Update Apps List
5. Cari "Manufacturing Serial Number" dan klik Install
## Cara Penggunaan
### Setup Produk
1. Buka **Inventory > Products**
2. Pilih produk yang ingin di-track
3. Di tab **Inventory**, aktifkan **"Use Manufacturing Serial"**
4. Save
### Menggunakan di Manufacturing
1. Buat Manufacturing Order baru
2. Pastikan checkbox **"Auto Generate Serial"** aktif
3. Process manufacturing order seperti biasa
4. Saat klik **"Mark as Done"**, serial numbers akan dibuat otomatis
5. Lihat serial numbers di Smart Button atau tab "Serial Numbers"
### Manual Generate (Opsional)
Jika serial belum ter-generate:
1. Buka Manufacturing Order yang sudah Done/In Progress
2. Klik tab **"Serial Numbers"**
3. Klik button **"Generate Serials Now"**
### Melihat History Serial
- **Per Product**: Buka Product → klik Smart Button "Mfg Serials"
- **Per MO**: Buka Manufacturing Order → klik Smart Button "Serials"
- **All Serials**: Menu Manufacturing > Manufacturing Serials > Serial Numbers
## Konfigurasi Lanjutan
### Format Serial Number
Edit di file `models/manufacturing_serial.py`, method `_generate_serial_number()`:
```python
def _generate_serial_number(self, product_id=None):
prefix = 'MFG' # Ubah prefix default di sini
# ... rest of code
```
### Batch Size Limit
Default maksimal 1000 serial per MO. Ubah di `models/mrp_production.py`:
```python
if qty_to_generate > 1000: # Ubah angka ini
raise UserError(...)
```
## Struktur Data
### Model: manufacturing.serial
- `serial_number`: Nomor serial unik
- `product_id`: Produk yang diproduksi
- `mrp_production_id`: Link ke Manufacturing Order
- `production_date`: Tanggal produksi
- `state`: Status (draft/produced/delivered/cancelled)
- `lot_id`: Link ke Stock Lot (opsional)
## Dependencies
- mrp (Manufacturing)
- stock (Inventory)
- product (Product Management)
## Kompatibilitas
- Odoo 14 Community Edition
- Odoo 14 Enterprise Edition
## Lisensi
LGPL-3
## Support
Untuk pertanyaan atau issue, hubungi tim development.
## Changelog
### Version 14.0.1.0.0 (2026-02-14)
- Initial release
- Auto generate serial numbers
- Manufacturing Order integration
- Product configuration
- Serial management views
+3
View File
@@ -0,0 +1,3 @@
# -*- coding: utf-8 -*-
from . import models
@@ -0,0 +1,33 @@
# -*- coding: utf-8 -*-
{
'name': 'Manufacturing Serial Number',
'version': '14.0.1.0.0',
'category': 'Manufacturing',
'summary': 'Automatic Serial Number Generation for Manufacturing Products',
'description': """
Manufacturing Serial Number
============================
Modul ini menyediakan fitur untuk:
* Generate otomatis serial number unik untuk setiap produk manufacturing
* Tracking serial number per Manufacturing Order
* Laporan dan history serial number
* Integrasi penuh dengan Manufacturing Order (MRP)
Cocok untuk community edition yang membutuhkan tracking serial number
tanpa harus menggunakan fitur berbayar.
""",
'author': 'Custom Development',
'website': '',
'depends': ['mrp', 'stock', 'product'],
'data': [
'security/ir.model.access.csv',
'views/manufacturing_serial_views.xml',
'views/mrp_production_views.xml',
'views/product_template_views.xml',
],
'installable': True,
'application': False,
'auto_install': False,
'license': 'LGPL-3',
}
@@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
from . import manufacturing_serial
from . import mrp_production
from . import product_template
@@ -0,0 +1,114 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import ValidationError
import random
import string
class ManufacturingSerial(models.Model):
_name = 'manufacturing.serial'
_description = 'Manufacturing Serial Number'
_order = 'serial_number desc'
_rec_name = 'serial_number'
serial_number = fields.Char(
string='Serial Number',
required=True,
copy=False,
readonly=True,
index=True,
default='New'
)
product_id = fields.Many2one(
'product.product',
string='Product',
required=True,
ondelete='restrict'
)
mrp_production_id = fields.Many2one(
'mrp.production',
string='Manufacturing Order',
ondelete='cascade'
)
production_date = fields.Datetime(
string='Production Date',
default=fields.Datetime.now,
required=True
)
state = fields.Selection([
('draft', 'Draft'),
('produced', 'Produced'),
('delivered', 'Delivered'),
('cancelled', 'Cancelled')
], string='State', default='draft', required=True)
notes = fields.Text(string='Notes')
company_id = fields.Many2one(
'res.company',
string='Company',
default=lambda self: self.env.company
)
lot_id = fields.Many2one(
'stock.production.lot',
string='Lot/Serial Number (Stock)',
help='Link to stock lot if available'
)
_sql_constraints = [
('serial_number_unique', 'unique(serial_number, company_id)',
'Serial number must be unique per company!')
]
@api.model
def create(self, vals):
if vals.get('serial_number', 'New') == 'New':
vals['serial_number'] = self._generate_serial_number(vals.get('product_id'))
return super(ManufacturingSerial, self).create(vals)
def _generate_serial_number(self, product_id=None):
"""Generate unique serial number"""
prefix = 'MFG'
if product_id:
product = self.env['product.product'].browse(product_id)
if product.default_code:
prefix = product.default_code[:6].upper()
# Generate sequential number
sequence = self.env['ir.sequence'].next_by_code('manufacturing.serial') or '0001'
# Add random suffix for extra uniqueness
random_suffix = ''.join(random.choices(string.ascii_uppercase + string.digits, k=4))
serial_number = f"{prefix}-{sequence}-{random_suffix}"
# Check if exists, regenerate if needed
if self.search([('serial_number', '=', serial_number)], limit=1):
return self._generate_serial_number(product_id)
return serial_number
def action_set_produced(self):
self.write({'state': 'produced'})
def action_set_delivered(self):
self.write({'state': 'delivered'})
def action_cancel(self):
self.write({'state': 'cancelled'})
def name_get(self):
result = []
for record in self:
name = f"{record.serial_number}"
if record.product_id:
name = f"{record.serial_number} - {record.product_id.name}"
result.append((record.id, name))
return result
@@ -0,0 +1,109 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api, _
from odoo.exceptions import UserError
class MrpProduction(models.Model):
_inherit = 'mrp.production'
serial_ids = fields.One2many(
'manufacturing.serial',
'mrp_production_id',
string='Serial Numbers',
readonly=True
)
serial_count = fields.Integer(
string='Serial Count',
compute='_compute_serial_count'
)
auto_generate_serial = fields.Boolean(
string='Auto Generate Serial',
default=True,
help='Automatically generate serial numbers when production is done'
)
@api.depends('serial_ids')
def _compute_serial_count(self):
for record in self:
record.serial_count = len(record.serial_ids)
def button_mark_done(self):
"""Override to generate serial numbers when marking as done"""
res = super(MrpProduction, self).button_mark_done()
for production in self:
if production.auto_generate_serial and production.product_id:
# Check if product needs serial tracking
if production.product_id.tracking in ['serial', 'lot'] or \
production.product_id.use_manufacturing_serial:
production._generate_manufacturing_serials()
return res
def _generate_manufacturing_serials(self):
"""Generate serial numbers for finished products"""
self.ensure_one()
SerialObj = self.env['manufacturing.serial']
# Calculate quantity to generate (based on product qty_done)
qty_to_generate = int(self.product_qty)
if qty_to_generate <= 0:
return
# Limit to reasonable number
if qty_to_generate > 1000:
raise UserError(_('Cannot generate more than 1000 serial numbers at once. Please reduce quantity.'))
serial_list = []
for i in range(qty_to_generate):
serial_vals = {
'product_id': self.product_id.id,
'mrp_production_id': self.id,
'production_date': fields.Datetime.now(),
'state': 'produced',
'company_id': self.company_id.id,
}
serial_list.append(serial_vals)
# Batch create serials
if serial_list:
SerialObj.create(serial_list)
return True
def action_view_serial_numbers(self):
"""Open serial numbers view"""
self.ensure_one()
return {
'name': _('Serial Numbers'),
'type': 'ir.actions.act_window',
'res_model': 'manufacturing.serial',
'view_mode': 'tree,form',
'domain': [('mrp_production_id', '=', self.id)],
'context': {
'default_mrp_production_id': self.id,
'default_product_id': self.product_id.id,
},
}
def action_generate_serials_manual(self):
"""Manual action to generate serials"""
for production in self:
if production.state in ['done', 'progress']:
production._generate_manufacturing_serials()
return {
'type': 'ir.actions.client',
'tag': 'display_notification',
'params': {
'title': _('Success'),
'message': _('Serial numbers generated successfully.'),
'type': 'success',
'sticky': False,
}
}
@@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
from odoo import models, fields, api
class ProductTemplate(models.Model):
_inherit = 'product.template'
use_manufacturing_serial = fields.Boolean(
string='Use Manufacturing Serial',
default=False,
help='Enable automatic serial number generation for manufacturing'
)
serial_count = fields.Integer(
string='Total Serials Generated',
compute='_compute_serial_count'
)
@api.depends('product_variant_ids.serial_ids')
def _compute_serial_count(self):
for template in self:
serials = self.env['manufacturing.serial'].search([
('product_id', 'in', template.product_variant_ids.ids)
])
template.serial_count = len(serials)
def action_view_serial_numbers(self):
"""View all serial numbers for this product"""
self.ensure_one()
return {
'name': 'Serial Numbers',
'type': 'ir.actions.act_window',
'res_model': 'manufacturing.serial',
'view_mode': 'tree,form',
'domain': [('product_id', 'in', self.product_variant_ids.ids)],
'context': {'default_product_id': self.product_variant_ids[0].id if self.product_variant_ids else False},
}
class ProductProduct(models.Model):
_inherit = 'product.product'
serial_ids = fields.One2many(
'manufacturing.serial',
'product_id',
string='Serial Numbers'
)
@@ -0,0 +1,4 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_manufacturing_serial_user,access_manufacturing_serial_user,model_manufacturing_serial,mrp.group_mrp_user,1,1,1,0
access_manufacturing_serial_manager,access_manufacturing_serial_manager,model_manufacturing_serial,mrp.group_mrp_manager,1,1,1,1
access_manufacturing_serial_stock_user,access_manufacturing_serial_stock_user,model_manufacturing_serial,stock.group_stock_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_manufacturing_serial_user access_manufacturing_serial_user model_manufacturing_serial mrp.group_mrp_user 1 1 1 0
3 access_manufacturing_serial_manager access_manufacturing_serial_manager model_manufacturing_serial mrp.group_mrp_manager 1 1 1 1
4 access_manufacturing_serial_stock_user access_manufacturing_serial_stock_user model_manufacturing_serial stock.group_stock_user 1 0 0 0
@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Manufacturing Serial Tree View -->
<record id="view_manufacturing_serial_tree" model="ir.ui.view">
<field name="name">manufacturing.serial.tree</field>
<field name="model">manufacturing.serial</field>
<field name="arch" type="xml">
<tree string="Manufacturing Serial Numbers" decoration-success="state=='produced'" decoration-info="state=='draft'" decoration-muted="state=='cancelled'">
<field name="serial_number"/>
<field name="product_id"/>
<field name="mrp_production_id"/>
<field name="production_date"/>
<field name="state"/>
<field name="company_id" groups="base.group_multi_company"/>
</tree>
</field>
</record>
<!-- Manufacturing Serial Form View -->
<record id="view_manufacturing_serial_form" model="ir.ui.view">
<field name="name">manufacturing.serial.form</field>
<field name="model">manufacturing.serial</field>
<field name="arch" type="xml">
<form string="Manufacturing Serial Number">
<header>
<button name="action_set_produced" string="Set Produced" type="object"
states="draft" class="oe_highlight"/>
<button name="action_set_delivered" string="Set Delivered" type="object"
states="produced" class="oe_highlight"/>
<button name="action_cancel" string="Cancel" type="object"
states="draft,produced" confirm="Are you sure you want to cancel this serial?"/>
<field name="state" widget="statusbar" statusbar_visible="draft,produced,delivered"/>
</header>
<sheet>
<div class="oe_button_box" name="button_box">
<!-- Add smart buttons here if needed -->
</div>
<group>
<group>
<field name="serial_number" readonly="1"/>
<field name="product_id"/>
<field name="mrp_production_id"/>
</group>
<group>
<field name="production_date"/>
<field name="lot_id"/>
<field name="company_id" groups="base.group_multi_company"/>
</group>
</group>
<notebook>
<page string="Notes">
<field name="notes" placeholder="Additional notes..."/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<!-- Manufacturing Serial Search View -->
<record id="view_manufacturing_serial_search" model="ir.ui.view">
<field name="name">manufacturing.serial.search</field>
<field name="model">manufacturing.serial</field>
<field name="arch" type="xml">
<search string="Search Serial Numbers">
<field name="serial_number"/>
<field name="product_id"/>
<field name="mrp_production_id"/>
<filter string="Draft" name="draft" domain="[('state','=','draft')]"/>
<filter string="Produced" name="produced" domain="[('state','=','produced')]"/>
<filter string="Delivered" name="delivered" domain="[('state','=','delivered')]"/>
<separator/>
<filter string="This Month" name="this_month"
domain="[('production_date','&gt;=', (context_today() - relativedelta(day=1)).strftime('%Y-%m-%d')), ('production_date','&lt;', (context_today() + relativedelta(months=1, day=1)).strftime('%Y-%m-%d'))]"/>
<group expand="0" string="Group By">
<filter string="Product" name="group_product" context="{'group_by':'product_id'}"/>
<filter string="Manufacturing Order" name="group_mrp" context="{'group_by':'mrp_production_id'}"/>
<filter string="State" name="group_state" context="{'group_by':'state'}"/>
<filter string="Production Date" name="group_date" context="{'group_by':'production_date'}"/>
</group>
</search>
</field>
</record>
<!-- Manufacturing Serial Action -->
<record id="action_manufacturing_serial" model="ir.actions.act_window">
<field name="name">Manufacturing Serial Numbers</field>
<field name="res_model">manufacturing.serial</field>
<field name="view_mode">tree,form</field>
<field name="search_view_id" ref="view_manufacturing_serial_search"/>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create your first manufacturing serial number
</p>
<p>
Serial numbers will be automatically generated when manufacturing orders are completed.
</p>
</field>
</record>
<!-- Menu Items -->
<menuitem id="menu_manufacturing_serial_root"
name="Manufacturing Serials"
parent="mrp.menu_mrp_root"
sequence="50"/>
<menuitem id="menu_manufacturing_serial"
name="Serial Numbers"
parent="menu_manufacturing_serial_root"
action="action_manufacturing_serial"
sequence="10"/>
<!-- IR Sequence for Serial Numbers -->
<record id="seq_manufacturing_serial" model="ir.sequence">
<field name="name">Manufacturing Serial Number</field>
<field name="code">manufacturing.serial</field>
<field name="prefix">S</field>
<field name="padding">6</field>
<field name="number_increment">1</field>
<field name="implementation">standard</field>
</record>
</odoo>
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- MRP Production Form View - Inherit -->
<record id="view_mrp_production_form_inherit_serial" model="ir.ui.view">
<field name="name">mrp.production.form.inherit.serial</field>
<field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_form_view"/>
<field name="arch" type="xml">
<!-- Add Smart Button -->
<xpath expr="//div[@name='button_box']" position="inside">
<button name="action_view_serial_numbers"
type="object"
class="oe_stat_button"
icon="fa-barcode"
attrs="{'invisible': [('serial_count', '=', 0)]}">
<field name="serial_count" widget="statinfo" string="Serials"/>
</button>
</xpath>
<!-- Add Auto Generate Serial Field -->
<xpath expr="//field[@name='product_id']" position="after">
<field name="auto_generate_serial"
attrs="{'invisible': [('state', 'in', ['done', 'cancel'])]}"/>
</xpath>
<!-- Add Serial Numbers Page -->
<xpath expr="//notebook" position="inside">
<page string="Serial Numbers" attrs="{'invisible': [('serial_count', '=', 0)]}">
<group>
<button name="action_generate_serials_manual"
string="Generate Serials Now"
type="object"
class="btn-primary"
attrs="{'invisible': ['|', ('state', 'not in', ['progress', 'done']), ('serial_count', '>', 0)]}"
help="Manually generate serial numbers for this production"/>
</group>
<field name="serial_ids" readonly="1">
<tree decoration-success="state=='produced'" decoration-info="state=='draft'">
<field name="serial_number"/>
<field name="product_id"/>
<field name="production_date"/>
<field name="state"/>
</tree>
</field>
</page>
</xpath>
</field>
</record>
<!-- MRP Production Tree View - Add Serial Count -->
<record id="view_mrp_production_tree_inherit_serial" model="ir.ui.view">
<field name="name">mrp.production.tree.inherit.serial</field>
<field name="model">mrp.production</field>
<field name="inherit_id" ref="mrp.mrp_production_tree_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='state']" position="before">
<field name="serial_count" string="Serials" optional="show"/>
</xpath>
</field>
</record>
</odoo>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Product Template Form View - Inherit -->
<record id="view_product_template_form_inherit_mfg_serial" model="ir.ui.view">
<field name="name">product.template.form.inherit.mfg.serial</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_form_view"/>
<field name="arch" type="xml">
<!-- Add Smart Button for Serial Numbers -->
<xpath expr="//div[@name='button_box']" position="inside">
<button name="action_view_serial_numbers"
type="object"
class="oe_stat_button"
icon="fa-barcode"
attrs="{'invisible': [('serial_count', '=', 0)]}">
<field name="serial_count" widget="statinfo" string="Mfg Serials"/>
</button>
</xpath>
<!-- Add Manufacturing Serial Field in Inventory Tab -->
<xpath expr="//page[@name='inventory']//group[@name='group_lots_and_weight']" position="after">
<group string="Manufacturing Serial" name="group_manufacturing_serial">
<field name="use_manufacturing_serial"
help="Enable automatic serial number generation when this product is manufactured"/>
</group>
</xpath>
</field>
</record>
<!-- Product Template Tree View - Show Serial Count -->
<record id="view_product_template_tree_inherit_mfg_serial" model="ir.ui.view">
<field name="name">product.template.tree.inherit.mfg.serial</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_tree_view"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='default_code']" position="after">
<field name="serial_count" string="Mfg Serials" optional="hide"/>
</xpath>
</field>
</record>
</odoo>