diff --git a/setup/stock_measuring_device/odoo/addons/stock_measuring_device b/setup/stock_measuring_device/odoo/addons/stock_measuring_device new file mode 120000 index 000000000..03db46a1b --- /dev/null +++ b/setup/stock_measuring_device/odoo/addons/stock_measuring_device @@ -0,0 +1 @@ +../../../../stock_measuring_device \ No newline at end of file diff --git a/setup/stock_measuring_device/setup.py b/setup/stock_measuring_device/setup.py new file mode 100644 index 000000000..28c57bb64 --- /dev/null +++ b/setup/stock_measuring_device/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_measuring_device/README.rst b/stock_measuring_device/README.rst new file mode 100644 index 000000000..514274ec8 --- /dev/null +++ b/stock_measuring_device/README.rst @@ -0,0 +1,126 @@ +====================== +Stock Measuring Device +====================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Alpha-red.png + :target: https://odoo-community.org/page/development-status + :alt: Alpha +.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png + :target: http://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 +.. |badge3| image:: https://img.shields.io/badge/github-OCA%2Fstock--logistics--warehouse-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-warehouse/tree/14.0/stock_measuring_device + :alt: OCA/stock-logistics-warehouse +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/stock-logistics-warehouse-14-0/stock-logistics-warehouse-14-0-stock_measuring_device + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/153/14.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Different manufacturers produce devices which are able to measure and weigh +packages and parcels. Each brand has a different communication protocol. This +module provides an framework to interface such devices with Odoo. + +.. IMPORTANT:: + This is an alpha version, the data model and design can change at any time without warning. + Only for development or testing purpose, do not use in production. + `More details on development status `_ + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +This module by itself does not do anything. + +You will need to install a module implementing the communication with your +device. Look for modules with a name starting with stock_measuring_device. + +Configuration +============= + +The first step is to configure the Packaging Types (Pallet, Box, ...) in Inventory > Configuration > Product Packaging Types. + +Configure the measuring device in Inventory > Configuration > Measuring +Devices, don't forget to set the device type, and any other additional +parameters. + +Usage +===== + +Use the "Wizard" button on a Measuring Device to open the screen and take +measurements. + +Known issues / Roadmap +====================== + +* The UI could get some improvements +* Being able to open the measurement screen from a product would be nice + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us smashing it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* Camptocamp + +Contributors +~~~~~~~~~~~~ + +* Patrick Tombez +* Alexandre Fayolle +* Carlos Serra Toro +* `Trobz `_: + * Hai Lang + +Other credits +~~~~~~~~~~~~~ + +The migration of this module from 13.0 to 14.0 was financially supported by Camptocamp + +Maintainers +~~~~~~~~~~~ + +This module is maintained by the OCA. + +.. image:: https://odoo-community.org/logo.png + :alt: Odoo Community Association + :target: https://odoo-community.org + +OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use. + +.. |maintainer-gurneyalex| image:: https://github.com/gurneyalex.png?size=40px + :target: https://github.com/gurneyalex + :alt: gurneyalex + +Current `maintainer `__: + +|maintainer-gurneyalex| + +This module is part of the `OCA/stock-logistics-warehouse `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_measuring_device/__init__.py b/stock_measuring_device/__init__.py new file mode 100644 index 000000000..0b1d65aed --- /dev/null +++ b/stock_measuring_device/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import components +from . import models +from . import wizard diff --git a/stock_measuring_device/__manifest__.py b/stock_measuring_device/__manifest__.py new file mode 100644 index 000000000..75c053204 --- /dev/null +++ b/stock_measuring_device/__manifest__.py @@ -0,0 +1,34 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +{ + "name": "Stock Measuring Device", + "summary": "Implement a common interface for measuring and weighing devices", + "version": "14.0.1.0.0", + "category": "Warehouse", + "author": "Camptocamp, Odoo Community Association (OCA)", + "license": "AGPL-3", + "depends": [ + "component", + "barcodes", + "stock", + "web_tree_dynamic_colored_field", + "product_packaging_dimension", + "product_packaging_type_required", + "product_dimension", + # To refresh wizard screen or pop-up message on the wizard + "web_notify", + "web_ir_actions_act_view_reload", + ], + "data": [ + "security/ir.model.access.csv", + "data/uom.xml", + "views/assets.xml", + "views/measuring_device_view.xml", + "wizard/measuring_wizard.xml", + "views/menu.xml", + ], + "website": "https://github.com/OCA/stock-logistics-warehouse", + "installable": True, + "development_status": "Alpha", + "maintainers": ["gurneyalex"], +} diff --git a/stock_measuring_device/components/__init__.py b/stock_measuring_device/components/__init__.py new file mode 100644 index 000000000..f1c2b4985 --- /dev/null +++ b/stock_measuring_device/components/__init__.py @@ -0,0 +1,3 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import measuring_device_component diff --git a/stock_measuring_device/components/measuring_device_component.py b/stock_measuring_device/components/measuring_device_component.py new file mode 100644 index 000000000..d2b63aa09 --- /dev/null +++ b/stock_measuring_device/components/measuring_device_component.py @@ -0,0 +1,45 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +import logging + +from odoo.addons.component.core import AbstractComponent + +_logger = logging.getLogger(__name__) + + +class MeasuringDevice(AbstractComponent): + _name = "measuring.device.base" + _collection = "measuring.device" + + def test_device(self): + """Test that the device is properly configured. + + Override to e.g. test the connection parameter or send a test command. + + :return: True on success, False otherwise""" + return True + + def preprocess_measures(self, measures): + """perform required parsing, key mapping and possible unit conversion + + :param measures: a dictionary passed to _update_packaging_measures + :return: a dictionary containing values that will be written on the + wizard line + """ + return measures + + def post_update_packaging_measures(self, measures, packaging, wizard_line): + """hook called after the update of the packaging or wizard line update. + + This method can be called to send notifications for instance. + + :return: None""" + + def get_measure(self): + """Get a measure from the device + + the implementation must communicate with the device to trigger a + measure. If this can be done synchronously, call + _update_packaging_measures() to get the update""" + raise NotImplementedError() diff --git a/stock_measuring_device/data/uom.xml b/stock_measuring_device/data/uom.xml new file mode 100644 index 000000000..543ab39ea --- /dev/null +++ b/stock_measuring_device/data/uom.xml @@ -0,0 +1,9 @@ + + + + + mm + + smaller + + diff --git a/stock_measuring_device/i18n/stock_measuring_device.pot b/stock_measuring_device/i18n/stock_measuring_device.pot new file mode 100644 index 000000000..835e086ec --- /dev/null +++ b/stock_measuring_device/i18n/stock_measuring_device.pot @@ -0,0 +1,315 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * stock_measuring_device +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 13.0\n" +"Report-Msgid-Bugs-To: \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: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard___barcode_scanned +msgid "Barcode Scanned" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Cancel Scan" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Close" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__create_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__create_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__create_uid +msgid "Created by" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__create_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__create_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__create_date +msgid "Created on" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__device_id +msgid "Device" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__device_type +msgid "Device Type" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__display_name +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__display_name +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__display_name +msgid "Display Name" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Fullscreen" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__barcode +msgid "GTIN" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__height +msgid "Height (mm)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__id +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__id +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__id +msgid "ID" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__is_measured +msgid "Is Measured" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__is_unit_line +msgid "Is Unit Line" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device____last_update +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard____last_update +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line____last_update +msgid "Last Modified on" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__write_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__write_uid +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__write_uid +msgid "Last Updated by" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__write_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__write_date +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__write_date +msgid "Last Updated on" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__packaging_length +msgid "Length (mm)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__line_ids +msgid "Line" +msgstr "" + +#. module: stock_measuring_device +#: code:addons/stock_measuring_device/models/measuring_device.py:0 +#, python-format +msgid "Measurement Wizard" +msgstr "" + +#. module: stock_measuring_device +#: code:addons/stock_measuring_device/wizard/measuring_wizard_line.py:0 +#, python-format +msgid "Measurement machine already in use." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.actions.act_window,name:stock_measuring_device.action_measuring_device_form +#: model:ir.model.fields,field_description:stock_measuring_device.field_stock_warehouse__measuring_device_ids +#: model:ir.ui.menu,name:stock_measuring_device.menu_measuring_device +msgid "Measuring Devices" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_measuring_device +msgid "Measuring and Weighing Device" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_product_packaging__measuring_device_id +msgid "Measuring device which will scan the package" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__name +msgid "Name" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields.selection,name:stock_measuring_device.selection__measuring_device__state__not_ready +msgid "Not Ready" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__name +msgid "Packaging" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__packaging_id +msgid "Packaging (rel)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__packaging_type_id +msgid "Packaging Type" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard__product_id +msgid "Product" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_product_packaging +msgid "Product Packaging" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__qty +msgid "Quantity" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields.selection,name:stock_measuring_device.selection__measuring_device__state__ready +msgid "Ready" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Refresh" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__required +msgid "Required" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Retrieve Product" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Save" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_wizard +msgid "Scan" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__scan_requested +msgid "Scan Requested" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__sequence +msgid "Sequence" +msgstr "" + +#. module: stock_measuring_device +#: code:addons/stock_measuring_device/models/product_packaging.py:0 +#, python-format +msgid "" +"Several packagings ({}) found to update by device {}. Will update the first:" +" {}" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__state +msgid "State" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,help:stock_measuring_device.field_product_packaging__measuring_device_id +msgid "" +"Technical field set when an operator uses the device to scan this package" +msgstr "" + +#. module: stock_measuring_device +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_device_form +msgid "Test Device" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.constraint,message:stock_measuring_device.constraint_measuring_device_name_uniq +msgid "The name of the measuring/weighing device must be unique." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,help:stock_measuring_device.field_measuring_device__device_type +msgid "" +"The type of device (e.g. zippcube, cubiscan...) depending on which module " +"are installed." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,help:stock_measuring_device.field_measuring_wizard___barcode_scanned +msgid "Value of the last barcode scanned." +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__volume +msgid "Volume (m³)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_stock_warehouse +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_device__warehouse_id +msgid "Warehouse" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__max_weight +msgid "Weight (kg)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__width +msgid "Width (mm)" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model.fields,field_description:stock_measuring_device.field_measuring_wizard_line__wizard_id +#: model_terms:ir.ui.view,arch_db:stock_measuring_device.view_measuring_device_form +msgid "Wizard" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_measuring_wizard +msgid "measuring Wizard" +msgstr "" + +#. module: stock_measuring_device +#: model:ir.model,name:stock_measuring_device.model_measuring_wizard_line +msgid "measuring Wizard Line" +msgstr "" + +#. module: stock_measuring_device +#: model:uom.uom,name:stock_measuring_device.product_uom_mm +msgid "mm" +msgstr "" diff --git a/stock_measuring_device/models/__init__.py b/stock_measuring_device/models/__init__.py new file mode 100644 index 000000000..5bdb916aa --- /dev/null +++ b/stock_measuring_device/models/__init__.py @@ -0,0 +1,5 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +from . import measuring_device +from . import product_packaging +from . import stock_warehouse diff --git a/stock_measuring_device/models/measuring_device.py b/stock_measuring_device/models/measuring_device.py new file mode 100644 index 000000000..036173431 --- /dev/null +++ b/stock_measuring_device/models/measuring_device.py @@ -0,0 +1,112 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +import logging + +from odoo import _, fields, models + +_logger = logging.getLogger(__name__) + + +class MeasuringDevice(models.Model): + _name = "measuring.device" + _inherit = "collection.base" + _description = "Measuring and Weighing Device" + _order = "warehouse_id, name" + + name = fields.Char("Name", required=True) + warehouse_id = fields.Many2one("stock.warehouse", "Warehouse", required=True) + device_type = fields.Selection( + selection=[], + help="The type of device (e.g. zippcube, cubiscan...) " + "depending on which module are installed.", + ) + state = fields.Selection( + [("not_ready", "Not Ready"), ("ready", "Ready")], + default="not_ready", + readonly=True, + copy=False, + ) + + _sql_constraints = [ + ( + "name_uniq", + "unique (name)", + "The name of the measuring/weighing device must be unique.", + ), + ] + + def _get_measuring_device(self): + with self.work_on(self._name) as work_ctx: + return work_ctx.component(usage=self.device_type) + + def open_wizard(self): + res = { + "name": _("Measurement Wizard"), + "res_model": "measuring.wizard", + "type": "ir.actions.act_window", + "view_id": False, + "view_mode": "form", + "context": {"default_device_id": self.id}, + "target": "fullscreen", + "flags": { + "withControlPanel": False, + "form_view_initial_mode": "edit", + "no_breadcrumbs": True, + }, + } + if self._is_being_used(): + pack = self.env["product.packaging"].search( + [("measuring_device_id", "=", self.id)], limit=1 + ) + res["context"]["default_product_id"] = pack.product_id.id + return res + + def _is_being_used(self): + self.ensure_one() + return bool( + self.env["product.packaging"].search_count( + [("measuring_device_id", "=", self.id)] + ) + ) + + def _update_packaging_measures(self, measures): + self.ensure_one() + measures = self._get_measuring_device().preprocess_measures(measures) + line_domain = [ + ("wizard_id.device_id", "=", self.id), + ("scan_requested", "=", True), + ] + + packaging = self.env["product.packaging"]._measuring_device_find_assigned(self) + if packaging: + line_domain += [("packaging_id", "=", packaging.id)] + else: + line_domain += [ + ("packaging_id", "=", False), + ("is_unit_line", "=", True), + ] + + wizard_line = self.env["measuring.wizard.line"].search( + line_domain, + order="write_date DESC", + limit=1, + ) + if not wizard_line: + _logger.warning("No wizard line found for this measure.") + packaging.write(measures) + else: + measures.update({"scan_requested": False, "is_measured": True}) + wizard_line.write(measures) + + self._get_measuring_device().post_update_packaging_measures( + measures, packaging, wizard_line + ) + return packaging + + def test_device(self): + for rec in self: + success = rec._get_measuring_device().test_device() + if success and rec.state == "not_ready": + rec.state = "ready" + elif not success and rec.state == "ready": + rec.state = "not_ready" diff --git a/stock_measuring_device/models/product_packaging.py b/stock_measuring_device/models/product_packaging.py new file mode 100644 index 000000000..753a029e2 --- /dev/null +++ b/stock_measuring_device/models/product_packaging.py @@ -0,0 +1,50 @@ +# Copyright 2021 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) +import logging + +from odoo import _, fields, models + +_logger = logging.getLogger(__name__) + + +class ProductPackaging(models.Model): + _inherit = "product.packaging" + + measuring_device_id = fields.Many2one( + "measuring.device", + copy=False, + string="Measuring device which will scan the package", + help="Technical field set when an operator uses the device " + "to scan this package", + index=True, + ) + + def _measuring_device_assign(self, device): + """Assign the measuring device to the current product packaging""" + # self can be an empty recordset, for the unit line which updates the + # product info + if self: + self.measuring_device_id = device + + def _measuring_device_release(self): + """Free the measuring device from the current product packaging""" + # self can be an empty recordset, for the unit line which updates the + # product info + if self: + self.measuring_device_id = False + + def _measuring_device_find_assigned(self, device): + """search packaging being assigned to the specified device""" + packaging = self.search( + [("measuring_device_id", "=", device.id)], order="write_date DESC", limit=2 + ) + if len(packaging) > 1: + warning_msg = _( + "Several packagings ({}) found to update by " + "device {}. Will update the first: {}".format( + packaging, self.name, packaging[0] + ) + ) + _logger.warning(warning_msg) + packaging = packaging[0] + return packaging diff --git a/stock_measuring_device/models/stock_warehouse.py b/stock_measuring_device/models/stock_warehouse.py new file mode 100644 index 000000000..83328dc42 --- /dev/null +++ b/stock_measuring_device/models/stock_warehouse.py @@ -0,0 +1,12 @@ +# Copyright 2019 Camptocamp SA +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html) + +from odoo import fields, models + + +class StockWarehouse(models.Model): + _inherit = "stock.warehouse" + + measuring_device_ids = fields.One2many( + "measuring.device", "warehouse_id", string="Measuring Devices" + ) diff --git a/stock_measuring_device/readme/CONFIGURE.rst b/stock_measuring_device/readme/CONFIGURE.rst new file mode 100644 index 000000000..e270c3f15 --- /dev/null +++ b/stock_measuring_device/readme/CONFIGURE.rst @@ -0,0 +1,5 @@ +The first step is to configure the Packaging Types (Pallet, Box, ...) in Inventory > Configuration > Product Packaging Types. + +Configure the measuring device in Inventory > Configuration > Measuring +Devices, don't forget to set the device type, and any other additional +parameters. diff --git a/stock_measuring_device/readme/CONTRIBUTORS.rst b/stock_measuring_device/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000..15cd741ee --- /dev/null +++ b/stock_measuring_device/readme/CONTRIBUTORS.rst @@ -0,0 +1,5 @@ +* Patrick Tombez +* Alexandre Fayolle +* Carlos Serra Toro +* `Trobz `_: + * Hai Lang diff --git a/stock_measuring_device/readme/CREDITS.rst b/stock_measuring_device/readme/CREDITS.rst new file mode 100644 index 000000000..f37ebe757 --- /dev/null +++ b/stock_measuring_device/readme/CREDITS.rst @@ -0,0 +1 @@ +The migration of this module from 13.0 to 14.0 was financially supported by Camptocamp diff --git a/stock_measuring_device/readme/DESCRIPTION.rst b/stock_measuring_device/readme/DESCRIPTION.rst new file mode 100644 index 000000000..66bb0cf1c --- /dev/null +++ b/stock_measuring_device/readme/DESCRIPTION.rst @@ -0,0 +1,3 @@ +Different manufacturers produce devices which are able to measure and weigh +packages and parcels. Each brand has a different communication protocol. This +module provides an framework to interface such devices with Odoo. diff --git a/stock_measuring_device/readme/INSTALL.rst b/stock_measuring_device/readme/INSTALL.rst new file mode 100644 index 000000000..c3448c214 --- /dev/null +++ b/stock_measuring_device/readme/INSTALL.rst @@ -0,0 +1,4 @@ +This module by itself does not do anything. + +You will need to install a module implementing the communication with your +device. Look for modules with a name starting with stock_measuring_device. diff --git a/stock_measuring_device/readme/ROADMAP.rst b/stock_measuring_device/readme/ROADMAP.rst new file mode 100644 index 000000000..3d608500b --- /dev/null +++ b/stock_measuring_device/readme/ROADMAP.rst @@ -0,0 +1,2 @@ +* The UI could get some improvements +* Being able to open the measurement screen from a product would be nice diff --git a/stock_measuring_device/readme/USAGE.rst b/stock_measuring_device/readme/USAGE.rst new file mode 100644 index 000000000..a346d91b2 --- /dev/null +++ b/stock_measuring_device/readme/USAGE.rst @@ -0,0 +1,2 @@ +Use the "Wizard" button on a Measuring Device to open the screen and take +measurements. diff --git a/stock_measuring_device/security/ir.model.access.csv b/stock_measuring_device/security/ir.model.access.csv new file mode 100644 index 000000000..5929da64c --- /dev/null +++ b/stock_measuring_device/security/ir.model.access.csv @@ -0,0 +1,5 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_measuring_device_inventory_manager,measuring.device.inventory.manager,stock_measuring_device.model_measuring_device,stock.group_stock_manager,1,1,1,1 +access_measuring_device_inventory_user,measuring.device.inventory.user,stock_measuring_device.model_measuring_device,stock.group_stock_user,1,0,0,0 +access_measuring_wizard,access_measuring_wizard,model_measuring_wizard,base.group_user,1,1,1,1 +access_measuring_wizard_line,access_measuring_wizard_line,model_measuring_wizard_line,base.group_user,1,1,1,1 diff --git a/stock_measuring_device/static/description/icon.png b/stock_measuring_device/static/description/icon.png new file mode 100644 index 000000000..3a0328b51 Binary files /dev/null and b/stock_measuring_device/static/description/icon.png differ diff --git a/stock_measuring_device/static/description/index.html b/stock_measuring_device/static/description/index.html new file mode 100644 index 000000000..1a39b8cc5 --- /dev/null +++ b/stock_measuring_device/static/description/index.html @@ -0,0 +1,473 @@ + + + + + + +Stock Measuring Device + + + +
+

Stock Measuring Device

+ + +

Alpha License: AGPL-3 OCA/stock-logistics-warehouse Translate me on Weblate Try me on Runbot

+

Different manufacturers produce devices which are able to measure and weigh +packages and parcels. Each brand has a different communication protocol. This +module provides an framework to interface such devices with Odoo.

+
+

Important

+

This is an alpha version, the data model and design can change at any time without warning. +Only for development or testing purpose, do not use in production. +More details on development status

+
+

Table of contents

+ +
+

Installation

+

This module by itself does not do anything.

+

You will need to install a module implementing the communication with your +device. Look for modules with a name starting with stock_measuring_device.

+
+
+

Configuration

+

The first step is to configure the Packaging Types (Pallet, Box, …) in Inventory > Configuration > Product Packaging Types.

+

Configure the measuring device in Inventory > Configuration > Measuring +Devices, don’t forget to set the device type, and any other additional +parameters.

+
+
+

Usage

+

Use the “Wizard” button on a Measuring Device to open the screen and take +measurements.

+
+
+

Known issues / Roadmap

+
    +
  • The UI could get some improvements
  • +
  • Being able to open the measurement screen from a product would be nice
  • +
+
+
+

Bug Tracker

+

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

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • Camptocamp
  • +
+
+
+

Contributors

+ +
+
+

Other credits

+

The migration of this module from 13.0 to 14.0 was financially supported by Camptocamp

+
+
+

Maintainers

+

This module is maintained by the OCA.

+Odoo Community Association +

OCA, or the Odoo Community Association, is a nonprofit organization whose +mission is to support the collaborative development of Odoo features and +promote its widespread use.

+

Current maintainer:

+

gurneyalex

+

This module is part of the OCA/stock-logistics-warehouse project on GitHub.

+

You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute.

+
+
+
+ + diff --git a/stock_measuring_device/static/src/js/measuring_wizard.js b/stock_measuring_device/static/src/js/measuring_wizard.js new file mode 100644 index 000000000..89b5a5358 --- /dev/null +++ b/stock_measuring_device/static/src/js/measuring_wizard.js @@ -0,0 +1,60 @@ +odoo.define("stock_measuring_device.measuring_wizard", function (require) { + "use strict"; + + var FormController = require("web.FormController"); + + FormController.include({ + init: function () { + this._super.apply(this, arguments); + if (this.modelName === "measuring.wizard") { + this.call( + "bus_service", + "addChannel", + "notify_measuring_wizard_screen" + ); + this.call( + "bus_service", + "on", + "notification", + this, + this.measuring_wizard_bus_notification + ); + this.call("bus_service", "startPolling"); + } + }, + measuring_wizard_bus_notification: function (notifications) { + var self = this; + _.each(notifications, function (notification) { + var channel = notification[0]; + var message = notification[1]; + if (channel === "notify_measuring_wizard_screen") { + if (message.action === "refresh") { + self.measuring_wizard_bus_action_refresh(message.params); + } + } + }); + }, + measuring_wizard_bus_action_refresh: function (params) { + var selectedIds = this.getSelectedIds(); + if (!selectedIds.length || params.model !== this.modelName) { + return; + } + var currentId = selectedIds[0]; + if (params.id === currentId) { + this.reload(); + } + }, + destroy: function () { + if (this.modelName === "measuring.wizard") { + this.call( + "bus_service", + "deleteChannel", + "notify_measuring_wizard_screen" + ); + } + this._super.apply(this, arguments); + }, + }); + + return {}; +}); diff --git a/stock_measuring_device/static/src/scss/measuring_wizard.scss b/stock_measuring_device/static/src/scss/measuring_wizard.scss new file mode 100644 index 000000000..507cfc3bd --- /dev/null +++ b/stock_measuring_device/static/src/scss/measuring_wizard.scss @@ -0,0 +1,33 @@ +.o_web_client.o_fullscreen { + .o_form_view.measuring_wizard { + font-size: 16px; + + @include media-breakpoint-up(x1) { + font-size: 18px; + } + + .btn { + font-size: 1em; + padding: 1em; + margin: 0 5px; + } + + .o_data_cell:not(.o_list_button) { + padding: 0.75em; + font-size: 1.5em; + margin: 0 5px; + } + + .table-responsive { + overflow: hidden; + } + + .o_field_many2one input.o_input { + font-size: 1.5em; + } + + .o_form_statusbar { + display: none; + } + } +} diff --git a/stock_measuring_device/views/assets.xml b/stock_measuring_device/views/assets.xml new file mode 100644 index 000000000..8be276756 --- /dev/null +++ b/stock_measuring_device/views/assets.xml @@ -0,0 +1,20 @@ + + +