diff --git a/setup/stock_release_channel_show_weight/odoo/addons/stock_release_channel_show_weight b/setup/stock_release_channel_show_weight/odoo/addons/stock_release_channel_show_weight new file mode 120000 index 0000000000..2818771b12 --- /dev/null +++ b/setup/stock_release_channel_show_weight/odoo/addons/stock_release_channel_show_weight @@ -0,0 +1 @@ +../../../../stock_release_channel_show_weight \ No newline at end of file diff --git a/setup/stock_release_channel_show_weight/setup.py b/setup/stock_release_channel_show_weight/setup.py new file mode 100644 index 0000000000..28c57bb640 --- /dev/null +++ b/setup/stock_release_channel_show_weight/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_release_channel_show_weight/README.rst b/stock_release_channel_show_weight/README.rst new file mode 100644 index 0000000000..edd2134150 --- /dev/null +++ b/stock_release_channel_show_weight/README.rst @@ -0,0 +1,79 @@ +================================== +Stock Release Channels show Weight +================================== + +.. + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! source digest: sha256:6d21986b669c172ec403d968cfeaf164789c75dc3e6e73553e2f49dd5c1ca26d + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png + :target: https://odoo-community.org/page/development-status + :alt: Beta +.. |badge2| image:: https://img.shields.io/badge/licence-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%2Fwms-lightgray.png?logo=github + :target: https://github.com/OCA/wms/tree/16.0/stock_release_channel_show_weight + :alt: OCA/wms +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/wms-16-0/wms-16-0-stock_release_channel_show_weight + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/builds?repo=OCA/wms&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Show the volume on the release channels + +Note: The weight computation is based on the estimated weight and not on the +measured shipping weight + +**Table of contents** + +.. contents:: + :local: + +Bug Tracker +=========== + +Bugs are tracked on `GitHub Issues `_. +In case of trouble, please check there if your issue has already been reported. +If you spotted it first, help us to smash it by providing a detailed and welcomed +`feedback `_. + +Do not contact contributors directly about support or help with technical issues. + +Credits +======= + +Authors +~~~~~~~ + +* BCIM + +Contributors +~~~~~~~~~~~~ + +* Jacques-Etienne Baudoux (BCIM) + +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. + +This module is part of the `OCA/wms `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/stock_release_channel_show_weight/__init__.py b/stock_release_channel_show_weight/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/stock_release_channel_show_weight/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_release_channel_show_weight/__manifest__.py b/stock_release_channel_show_weight/__manifest__.py new file mode 100644 index 0000000000..e1c266d127 --- /dev/null +++ b/stock_release_channel_show_weight/__manifest__.py @@ -0,0 +1,20 @@ +# Copyright 2023 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +{ + "name": "Stock Release Channels show Weight", + "summary": "Display weights of stock release channels", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "BCIM, Odoo Community Association (OCA)", + "website": "https://github.com/OCA/wms", + "depends": [ + "delivery", + "stock_release_channel", + ], + "data": [ + "views/release_channel.xml", + "data/decimal_precision.xml", + ], + "installable": True, +} diff --git a/stock_release_channel_show_weight/data/decimal_precision.xml b/stock_release_channel_show_weight/data/decimal_precision.xml new file mode 100644 index 0000000000..57e9ac1fb7 --- /dev/null +++ b/stock_release_channel_show_weight/data/decimal_precision.xml @@ -0,0 +1,6 @@ + + + Release Channel Weight + + + diff --git a/stock_release_channel_show_weight/models/__init__.py b/stock_release_channel_show_weight/models/__init__.py new file mode 100644 index 0000000000..a0504e8407 --- /dev/null +++ b/stock_release_channel_show_weight/models/__init__.py @@ -0,0 +1 @@ +from . import stock_release_channel diff --git a/stock_release_channel_show_weight/models/stock_release_channel.py b/stock_release_channel_show_weight/models/stock_release_channel.py new file mode 100644 index 0000000000..526da95d50 --- /dev/null +++ b/stock_release_channel_show_weight/models/stock_release_channel.py @@ -0,0 +1,127 @@ +# Copyright 2024 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from odoo import api, fields, models + + +class StockReleaseChannel(models.Model): + _inherit = "stock.release.channel" + + weight_uom_name = fields.Char( + string="Weight Unit of Measure label", compute="_compute_weight_uom_name" + ) + + def _compute_weight_uom_name(self): + self.weight_uom_name = self.env[ + "product.template" + ]._get_weight_uom_name_from_ir_config_parameter() + + weight_picking_all = fields.Float( + string="All Transfers Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_release_ready = fields.Float( + string="Release Ready Transfers Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_released = fields.Float( + string="Released Transfers Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_assigned = fields.Float( + string="Available Transfers Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_waiting = fields.Float( + string="Waiting Transfers Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_late = fields.Float( + string="Late Transfers Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_priority = fields.Float( + string="Priority Transfers Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_done = fields.Float( + string="Transfers Done WeightToday", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_picking_full_progress = fields.Float( + string="Full Progress Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_all = fields.Float( + string="All Moves (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_release_ready = fields.Float( + string="Release Ready Moves (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_released = fields.Float( + string="Released Moves (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_assigned = fields.Float( + string="Available Moves (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_waiting = fields.Float( + string="Waiting Moves (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_late = fields.Float( + string="Late Moves (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_priority = fields.Float( + string="Priority Moves (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + weight_move_done = fields.Float( + string="Moves Done Today (Estimate) Weight", + compute="_compute_picking_count", + digits="Release Channel Weight", + ) + + @api.model + def _get_picking_read_group_fields(self): + res = super()._get_picking_read_group_fields() + res += ["weight"] + return res + + @api.model + def _get_move_read_group_fields(self): + res = super()._get_move_read_group_fields() + res += ["weight"] + return res + + @api.model + def _get_picking_compute_fields(self): + res = super()._get_picking_compute_fields() + res += [("weight", "weight")] + return res + + @api.model + def _get_move_compute_fields(self): + res = super()._get_move_compute_fields() + res += [("weight", "weight")] + return res diff --git a/stock_release_channel_show_weight/readme/CONTRIBUTORS.rst b/stock_release_channel_show_weight/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..3c6c5c696a --- /dev/null +++ b/stock_release_channel_show_weight/readme/CONTRIBUTORS.rst @@ -0,0 +1 @@ +* Jacques-Etienne Baudoux (BCIM) diff --git a/stock_release_channel_show_weight/readme/DESCRIPTION.rst b/stock_release_channel_show_weight/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..2bb8927b55 --- /dev/null +++ b/stock_release_channel_show_weight/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +Show the weight on the release channels + +Note: The weight computation is based on the estimated weight and not on the +measured shipping weight diff --git a/stock_release_channel_show_weight/static/description/index.html b/stock_release_channel_show_weight/static/description/index.html new file mode 100644 index 0000000000..841744367d --- /dev/null +++ b/stock_release_channel_show_weight/static/description/index.html @@ -0,0 +1,423 @@ + + + + + + +Stock Release Channels show Weight + + + +
+

Stock Release Channels show Weight

+ + +

Beta License: AGPL-3 OCA/wms Translate me on Weblate Try me on Runboat

+

Show the volume on the release channels

+

Note: The weight computation is based on the estimated weight and not on the +measured shipping weight

+

Table of contents

+ +
+

Bug Tracker

+

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

+

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

+
+
+

Credits

+
+

Authors

+
    +
  • BCIM
  • +
+
+
+

Contributors

+ +
+
+

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.

+

This module is part of the OCA/wms project on GitHub.

+

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

+
+
+
+ + diff --git a/stock_release_channel_show_weight/tests/__init__.py b/stock_release_channel_show_weight/tests/__init__.py new file mode 100644 index 0000000000..b6ca01fad1 --- /dev/null +++ b/stock_release_channel_show_weight/tests/__init__.py @@ -0,0 +1 @@ +from . import test_channel_computed_fields diff --git a/stock_release_channel_show_weight/tests/test_channel_computed_fields.py b/stock_release_channel_show_weight/tests/test_channel_computed_fields.py new file mode 100644 index 0000000000..fa21fbd3e3 --- /dev/null +++ b/stock_release_channel_show_weight/tests/test_channel_computed_fields.py @@ -0,0 +1,146 @@ +# Copyright 2024 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html) + +from datetime import timedelta + +from odoo import fields + +from odoo.addons.stock_release_channel.tests.common import ChannelReleaseCase + + +class TestChannelComputedFields(ChannelReleaseCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.product1.weight = 1 + cls.product2.weight = 3 + cls.channel.picking_ids.move_ids._cal_move_weight() + cls.channel.picking_ids._cal_weight() + cls.channel.picking_ids._compute_shipping_weight() + + def assertWeight(self, suffix, product_qties): + weight = sum([product.weight * qty for product, qty in product_qties]) + for prefix in ["weight_picking", "weight_move"]: + field = f"{prefix}_{suffix}" + value = getattr(self.channel, field) + self.assertEqual( + weight, + value, + f"The value of {field} is {value} and not like expected {weight}", + ) + + def assertWeightFullProgress(self): + self.assertEqual( + self.channel.weight_picking_full_progress, + sum( + [ + self.channel.weight_picking_release_ready, + self.channel.weight_picking_released, + self.channel.weight_picking_done, + ] + ), + ) + + def test_computed_fields_counts_not_ready(self): + self.assertWeight("all", [(self.product1, 5 * 3), (self.product2, 5 * 3)]) + self.assertWeight("release_ready", []) + self.assertWeight("released", []) + self.assertWeight("assigned", []) + self.assertWeight("waiting", []) + self.assertWeight("late", []) + self.assertWeight("priority", []) + self.assertWeight("done", []) + self.assertWeightFullProgress() + + def test_computed_fields_counts_release_ready(self): + self._update_qty_in_location(self.loc_bin1, self.product1, 20.0) + self._update_qty_in_location(self.loc_bin1, self.product2, 20.0) + + self.assertWeight("all", [(self.product1, 5 * 3), (self.product2, 5 * 3)]) + self.assertWeight( + "release_ready", [(self.product1, 5 * 3), (self.product2, 5 * 3)] + ) + self.assertWeight("released", []) + self.assertWeight("assigned", []) + self.assertWeight("waiting", []) + self.assertWeight("late", []) + self.assertWeight("priority", []) + self.assertWeight("done", []) + self.assertWeightFullProgress() + + def test_computed_fields_counts_released(self): + self._update_qty_in_location(self.loc_bin1, self.product1, 20.0) + self._update_qty_in_location(self.loc_bin1, self.product2, 20.0) + self.picking.release_available_to_promise() + + self.assertWeight("all", [(self.product1, 5 * 3), (self.product2, 5 * 3)]) + self.assertWeight( + "release_ready", [(self.product1, 5 * 2), (self.product2, 5 * 2)] + ) + self.assertWeight("released", [(self.product1, 5), (self.product2, 5)]) + self.assertWeight("assigned", []) + self.assertWeight("waiting", [(self.product1, 5), (self.product2, 5)]) + self.assertWeight("late", []) + self.assertWeight("priority", []) + self.assertWeight("done", []) + self.assertWeightFullProgress() + + def test_computed_fields_counts_late(self): + self._update_qty_in_location(self.loc_bin1, self.product1, 20.0) + self._update_qty_in_location(self.loc_bin1, self.product2, 20.0) + self.picking.release_available_to_promise() + # FIXME late should measure late internal operations, not late deliveries + # pick_picking = self.picking.move_ids.move_orig_ids.picking_id + # pick_picking.scheduled_date = fields.Datetime.now() - timedelta(hours=1) + self.picking.scheduled_date = fields.Datetime.now() - timedelta(hours=1) + + self.assertWeight("all", [(self.product1, 5 * 3), (self.product2, 5 * 3)]) + self.assertWeight( + "release_ready", [(self.product1, 5 * 2), (self.product2, 5 * 2)] + ) + self.assertWeight("released", [(self.product1, 5), (self.product2, 5)]) + self.assertWeight("assigned", []) + self.assertWeight("waiting", [(self.product1, 5), (self.product2, 5)]) + self.assertWeight("late", [(self.product1, 5), (self.product2, 5)]) + self.assertWeight("priority", []) + self.assertWeight("done", []) + self.assertWeightFullProgress() + + def test_computed_fields_counts_pick_done(self): + self._update_qty_in_location(self.loc_bin1, self.product1, 20.0) + self._update_qty_in_location(self.loc_bin1, self.product2, 20.0) + self.picking.release_available_to_promise() + pick_picking = self.picking.move_ids.move_orig_ids.picking_id + self._action_done_picking(pick_picking) + + self.assertWeight("all", [(self.product1, 5 * 3), (self.product2, 5 * 3)]) + self.assertWeight( + "release_ready", [(self.product1, 5 * 2), (self.product2, 5 * 2)] + ) + self.assertWeight("released", [(self.product1, 5), (self.product2, 5)]) + self.assertWeight("assigned", [(self.product1, 5), (self.product2, 5)]) + self.assertWeight("waiting", []) + self.assertWeight("late", []) + self.assertWeight("priority", []) + self.assertWeight("done", []) + self.assertWeightFullProgress() + + def test_computed_fields_counts_ship_done(self): + self._update_qty_in_location(self.loc_bin1, self.product1, 20.0) + self._update_qty_in_location(self.loc_bin1, self.product2, 20.0) + self.picking.release_available_to_promise() + pick_picking = self.picking.move_ids.move_orig_ids.picking_id + self._action_done_picking(pick_picking) + self._action_done_picking(self.picking) + + self.assertWeight("all", [(self.product1, 5 * 3), (self.product2, 5 * 3)]) + self.assertWeight( + "release_ready", [(self.product1, 5 * 2), (self.product2, 5 * 2)] + ) + self.assertWeight("released", []) + self.assertWeight("assigned", []) + self.assertWeight("waiting", []) + self.assertWeight("late", []) + self.assertWeight("priority", []) + self.assertWeight("done", [(self.product1, 5), (self.product2, 5)]) + self.assertWeightFullProgress() diff --git a/stock_release_channel_show_weight/views/release_channel.xml b/stock_release_channel_show_weight/views/release_channel.xml new file mode 100644 index 0000000000..8017cb4927 --- /dev/null +++ b/stock_release_channel_show_weight/views/release_channel.xml @@ -0,0 +1,111 @@ + + + stock.release.channel + + + + + + + + + + + + + + + + + + + + + + + + + + stock.release.channel + kanban + + + +
+ + +
+
+ +
+ + +
+
+ +
+ + +
+
+ + + + +
+ + + +
+
+ +
+ + + +
+
+ +
+ + + +
+
+
+
+