From f2e741ed9225dd4819fbb670aafcbe844ee7ccef Mon Sep 17 00:00:00 2001 From: hda Date: Wed, 25 Jan 2023 13:56:54 +0100 Subject: [PATCH 01/12] [16.0][ADD] delivery_estimated_package_quantity_by_weight --- .../README.rst | 96 ++++ .../__init__.py | 1 + .../__manifest__.py | 16 + ...y_estimated_package_quantity_by_weight.pot | 66 +++ .../i18n/fr_BE.po | 66 +++ .../models/__init__.py | 2 + .../models/delivery_carrier.py | 21 + .../models/stock_picking.py | 113 +++++ .../readme/CONTRIBUTORS.rst | 2 + .../readme/DESCRIPTION.rst | 15 + .../readme/USAGE.rst | 4 + .../static/description/index.html | 450 +++++++++++++++++ .../tests/__init__.py | 1 + .../tests/test_stock_picking.py | 478 ++++++++++++++++++ .../views/delivery_carrier_views.xml | 35 ++ .../views/stock_picking_views.xml | 56 ++ 16 files changed, 1422 insertions(+) create mode 100644 delivery_estimated_package_quantity_by_weight/README.rst create mode 100644 delivery_estimated_package_quantity_by_weight/__init__.py create mode 100644 delivery_estimated_package_quantity_by_weight/__manifest__.py create mode 100644 delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot create mode 100644 delivery_estimated_package_quantity_by_weight/i18n/fr_BE.po create mode 100644 delivery_estimated_package_quantity_by_weight/models/__init__.py create mode 100644 delivery_estimated_package_quantity_by_weight/models/delivery_carrier.py create mode 100644 delivery_estimated_package_quantity_by_weight/models/stock_picking.py create mode 100644 delivery_estimated_package_quantity_by_weight/readme/CONTRIBUTORS.rst create mode 100644 delivery_estimated_package_quantity_by_weight/readme/DESCRIPTION.rst create mode 100644 delivery_estimated_package_quantity_by_weight/readme/USAGE.rst create mode 100644 delivery_estimated_package_quantity_by_weight/static/description/index.html create mode 100644 delivery_estimated_package_quantity_by_weight/tests/__init__.py create mode 100644 delivery_estimated_package_quantity_by_weight/tests/test_stock_picking.py create mode 100644 delivery_estimated_package_quantity_by_weight/views/delivery_carrier_views.xml create mode 100644 delivery_estimated_package_quantity_by_weight/views/stock_picking_views.xml diff --git a/delivery_estimated_package_quantity_by_weight/README.rst b/delivery_estimated_package_quantity_by_weight/README.rst new file mode 100644 index 0000000000..dc8e9825e5 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/README.rst @@ -0,0 +1,96 @@ +============================================= +Delivery Estimated Package Quantity By Weight +============================================= + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! This file is generated by oca-gen-addon-readme !! + !! changes will be overwritten. !! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +.. |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%2Fdelivery--carrier-lightgray.png?logo=github + :target: https://github.com/OCA/delivery-carrier/tree/16.0/delivery_estimated_package_quantity_by_weight + :alt: OCA/delivery-carrier +.. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png + :target: https://translation.odoo-community.org/projects/delivery-carrier-16-0/delivery-carrier-16-0-delivery_estimated_package_quantity_by_weight + :alt: Translate me on Weblate +.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png + :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/delivery-carrier&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module computes the amount of packages a picking out should have +depending on the weight of the products and the limit fixed by the carrier. +It's fully independent of the delivery_package_number module. + +A warning is given if the number of packages for the picking out is above what +is considered as the theoretical number of packages for this picking and the +chosen carrier. The goal is to minimize the number of packages billed by the +carrier. + +The chosen strategy for the theoretical number of packages is as follow: + * Split the product_weights into as many items as we have + * Try to fit the heaviest product with the lightest. + If it does not work then the heaviest should have a box for itself + * While the weight of products does not exceed the limit, continue adding + products in the same package + +**Table of contents** + +.. contents:: + :local: + +Usage +===== + +Here are some limitations of the module: + * Product packagings are not supported + * Multiple package types having different max weight for a shipping method + are not supported + +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 +~~~~~~~ + +* ACSONE SA/NV + +Contributors +~~~~~~~~~~~~ + +* Lindsay Marion +* Hughes Damry + +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/delivery-carrier `_ project on GitHub. + +You are welcome to contribute. To learn how please visit https://odoo-community.org/page/Contribute. diff --git a/delivery_estimated_package_quantity_by_weight/__init__.py b/delivery_estimated_package_quantity_by_weight/__init__.py new file mode 100644 index 0000000000..0650744f6b --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/delivery_estimated_package_quantity_by_weight/__manifest__.py b/delivery_estimated_package_quantity_by_weight/__manifest__.py new file mode 100644 index 0000000000..2f49e84b3a --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/__manifest__.py @@ -0,0 +1,16 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +{ + "name": "Delivery Estimated Package Quantity By Weight", + "summary": """ + Compute the amount of packages a picking out should have depending on the + weight of the products and the limit fixed by the carrier""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "website": "https://github.com/OCA/delivery-carrier", + "author": "ACSONE SA/NV, Odoo Community Association (OCA)", + "depends": ["stock", "delivery"], + "data": ["views/delivery_carrier_views.xml", "views/stock_picking_views.xml"], + "installable": True, +} diff --git a/delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot b/delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot new file mode 100644 index 0000000000..60ab439974 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot @@ -0,0 +1,66 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * delivery_estimated_package_quantity_by_weight +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-03-13 13:22+0000\n" +"PO-Revision-Date: 2023-03-13 13:22+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: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_delivery_carrier__maximum_weight_per_package +msgid "Maximum weight per package" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model_terms:ir.ui.view,arch_db:delivery_estimated_package_quantity_by_weight.stock_picking_form_view +msgid "Number of packages" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__number_of_packages_done +msgid "Number of packages in a picking out" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__is_number_of_packages_visible +msgid "Number of packages visible" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model,name:delivery_estimated_package_quantity_by_weight.model_delivery_carrier +msgid "Shipping Methods" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model_terms:ir.ui.view,arch_db:delivery_estimated_package_quantity_by_weight.stock_picking_form_view +msgid "The number of packages outranged the adviced number of packages" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__theoretical_number_of_packages +msgid "Theoretical number of packages in a picking out" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__is_number_of_packages_outranged +msgid "Too many packages compared to the theoretical number" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model,name:delivery_estimated_package_quantity_by_weight.model_stock_picking +msgid "Transfer" +msgstr "" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_delivery_carrier__weight_uom_name +msgid "Weight unit of measure label" +msgstr "" diff --git a/delivery_estimated_package_quantity_by_weight/i18n/fr_BE.po b/delivery_estimated_package_quantity_by_weight/i18n/fr_BE.po new file mode 100644 index 0000000000..c49e2d21ad --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/i18n/fr_BE.po @@ -0,0 +1,66 @@ +# Translation of Odoo Server. +# This file contains the translation of the following modules: +# * delivery_estimated_package_quantity_by_weight +# +msgid "" +msgstr "" +"Project-Id-Version: Odoo Server 16.0+e\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2023-03-13 13:22+0000\n" +"PO-Revision-Date: 2023-03-13 13:22+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: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_delivery_carrier__maximum_weight_per_package +msgid "Maximum weight per package" +msgstr "Poids maximum par colis" + +#. module: delivery_estimated_package_quantity_by_weight +#: model_terms:ir.ui.view,arch_db:delivery_estimated_package_quantity_by_weight.stock_picking_form_view +msgid "Number of packages" +msgstr "Le nombre de colis est visible" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__number_of_packages_done +msgid "Number of packages in a picking out" +msgstr "Nombre de colis recommandé" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__is_number_of_packages_visible +msgid "Number of packages visible" +msgstr "Le nombre de colis est visible" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model,name:delivery_estimated_package_quantity_by_weight.model_delivery_carrier +msgid "Shipping Methods" +msgstr "Modes de livraison" + +#. module: delivery_estimated_package_quantity_by_weight +#: model_terms:ir.ui.view,arch_db:delivery_estimated_package_quantity_by_weight.stock_picking_form_view +msgid "The number of packages outranged the adviced number of packages" +msgstr "Le nombre de colis dépasse le nombre de colis recommandé" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__theoretical_number_of_packages +msgid "Theoretical number of packages in a picking out" +msgstr "Nombre de colis recommandé" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_stock_picking__is_number_of_packages_outranged +msgid "Too many packages compared to the theoretical number" +msgstr "Trop de colis en comparaison du nombre de colis recommandé" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model,name:delivery_estimated_package_quantity_by_weight.model_stock_picking +msgid "Transfer" +msgstr "Transfert" + +#. module: delivery_estimated_package_quantity_by_weight +#: model:ir.model.fields,field_description:delivery_estimated_package_quantity_by_weight.field_delivery_carrier__weight_uom_name +msgid "Weight unit of measure label" +msgstr "" diff --git a/delivery_estimated_package_quantity_by_weight/models/__init__.py b/delivery_estimated_package_quantity_by_weight/models/__init__.py new file mode 100644 index 0000000000..66690e69a9 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/models/__init__.py @@ -0,0 +1,2 @@ +from . import stock_picking +from . import delivery_carrier diff --git a/delivery_estimated_package_quantity_by_weight/models/delivery_carrier.py b/delivery_estimated_package_quantity_by_weight/models/delivery_carrier.py new file mode 100644 index 0000000000..51265b3b74 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/models/delivery_carrier.py @@ -0,0 +1,21 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import fields, models + + +class DeliveryCarrier(models.Model): + + _inherit = "delivery.carrier" + + maximum_weight_per_package = fields.Float(string="Maximum weight per package") + weight_uom_name = fields.Char( + string="Weight unit of measure label", compute="_compute_weight_uom_name" + ) + + def _compute_weight_uom_name(self): + weight_uom_name = self.env[ + "product.template" + ]._get_weight_uom_name_from_ir_config_parameter() + for rec in self: + rec.weight_uom_name = weight_uom_name diff --git a/delivery_estimated_package_quantity_by_weight/models/stock_picking.py b/delivery_estimated_package_quantity_by_weight/models/stock_picking.py new file mode 100644 index 0000000000..0125e8af21 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/models/stock_picking.py @@ -0,0 +1,113 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class StockPicking(models.Model): + + _inherit = "stock.picking" + + theoretical_number_of_packages = fields.Integer( + "Theoretical number of packages in a picking out", + compute="_compute_theoretical_number_of_packages", + ) + number_of_packages_done = fields.Integer( + "Number of packages in a picking out", + compute="_compute_number_of_packages_done", + ) + is_number_of_packages_visible = fields.Boolean( + "Number of packages visible", + compute="_compute_is_number_of_packages_visible", + ) + is_number_of_packages_outranged = fields.Boolean( + "Too many packages compared to the theoretical number", + compute="_compute_is_number_of_packages_outranged", + ) + + @api.depends( + "picking_type_code", "carrier_id", "carrier_id.maximum_weight_per_package" + ) + def _compute_is_number_of_packages_visible(self): + + for rec in self: + if ( + rec.picking_type_code == "outgoing" + and rec.carrier_id.maximum_weight_per_package + ): + rec.is_number_of_packages_visible = True + else: + rec.is_number_of_packages_visible = False + + @api.depends("is_number_of_packages_visible", "move_ids") + def _compute_theoretical_number_of_packages(self): + for rec in self: + if rec.is_number_of_packages_visible: + products_weights = rec.move_ids.mapped("product_id.weight") + number_of_items = rec.move_ids.mapped("product_uom_qty") + rec.theoretical_number_of_packages = rec._number_of_packages( + products_weights, + number_of_items, + rec.carrier_id.maximum_weight_per_package, + ) + else: + rec.theoretical_number_of_packages = False + + @api.depends( + "is_number_of_packages_visible", + "move_line_ids", + "move_line_ids.result_package_id", + ) + def _compute_number_of_packages_done(self): + for rec in self: + if rec.is_number_of_packages_visible: + rec.number_of_packages_done = len( + rec.mapped("move_line_ids.result_package_id") + ) + else: + rec.number_of_packages_done = False + + @api.depends("theoretical_number_of_packages", "number_of_packages_done") + def _compute_is_number_of_packages_outranged(self): + for rec in self: + if rec.is_number_of_packages_visible: + rec.is_number_of_packages_outranged = ( + rec.number_of_packages_done > rec.theoretical_number_of_packages + ) + else: + rec.is_number_of_packages_outranged = False + + def _number_of_packages( + self, products_weights, number_of_items, maximum_weight_per_package + ): + + # Split the product_weights into as many items as we haves + products_weights_list = [] + for weight, number in zip(products_weights, number_of_items): + for _i in range(int(number)): + products_weights_list.append(weight) + + products_weights_list.sort() + + i = 0 + weight = 0 + j = len(products_weights_list) - 1 + theoretical_number_of_packages = 0 + while i <= j: + theoretical_number_of_packages += 1 + # Try to fit the heaviest product with the lightest. + # If it does not work, then the heaviest should have + # a box to itself + weight = products_weights_list[i] + products_weights_list[j] + while weight <= maximum_weight_per_package: + i += 1 + if i < j: + # While the weight of products does not exceed the limit, + # continue adding products in the same package + weight += products_weights_list[i] + else: + break + + j -= 1 + + return theoretical_number_of_packages diff --git a/delivery_estimated_package_quantity_by_weight/readme/CONTRIBUTORS.rst b/delivery_estimated_package_quantity_by_weight/readme/CONTRIBUTORS.rst new file mode 100644 index 0000000000..dce2965a6b --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Lindsay Marion +* Hughes Damry diff --git a/delivery_estimated_package_quantity_by_weight/readme/DESCRIPTION.rst b/delivery_estimated_package_quantity_by_weight/readme/DESCRIPTION.rst new file mode 100644 index 0000000000..180174290a --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/readme/DESCRIPTION.rst @@ -0,0 +1,15 @@ +This module computes the amount of packages a picking out should have +depending on the weight of the products and the limit fixed by the carrier. +It's fully independent of the delivery_package_number module. + +A warning is given if the number of packages for the picking out is above what +is considered as the theoretical number of packages for this picking and the +chosen carrier. The goal is to minimize the number of packages billed by the +carrier. + +The chosen strategy for the theoretical number of packages is as follow: + * Split the product_weights into as many items as we have + * Try to fit the heaviest product with the lightest. + If it does not work then the heaviest should have a box for itself + * While the weight of products does not exceed the limit, continue adding + products in the same package diff --git a/delivery_estimated_package_quantity_by_weight/readme/USAGE.rst b/delivery_estimated_package_quantity_by_weight/readme/USAGE.rst new file mode 100644 index 0000000000..2ecf22c985 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/readme/USAGE.rst @@ -0,0 +1,4 @@ +Here are some limitations of the module: + * Product packagings are not supported + * Multiple package types having different max weight for a shipping method + are not supported diff --git a/delivery_estimated_package_quantity_by_weight/static/description/index.html b/delivery_estimated_package_quantity_by_weight/static/description/index.html new file mode 100644 index 0000000000..cbd86d4ac3 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/static/description/index.html @@ -0,0 +1,450 @@ + + + + + + +Delivery Estimated Package Quantity By Weight + + + +
+

Delivery Estimated Package Quantity By Weight

+ + +

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

+

This module computes the amount of packages a picking out should have +depending on the weight of the products and the limit fixed by the carrier. +It’s fully independent of the delivery_package_number module.

+

A warning is given if the number of packages for the picking out is above what +is considered as the theoretical number of packages for this picking and the +chosen carrier. The goal is to minimize the number of packages billed by the +carrier.

+
+
The chosen strategy for the theoretical number of packages is as follow:
+
    +
  • Split the product_weights into as many items as we haves
  • +
  • Try to fit the heaviest product with the lightest. +If it does not work, then the heaviest should have a box for itself
  • +
  • While the weight of products does not exceed the limit, continue adding +products in the same package
  • +
+
+
+

Table of contents

+ +
+

Usage

+
+
Here are some limitations of the module:
+
    +
  • Product packagings are not supported
  • +
  • Multiple package types having different max weight for a shipping method +are not supported
  • +
+
+
+
+
+

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

+
    +
  • ACSONE SA/NV
  • +
+
+
+

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/delivery-carrier project on GitHub.

+

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

+
+
+
+ + diff --git a/delivery_estimated_package_quantity_by_weight/tests/__init__.py b/delivery_estimated_package_quantity_by_weight/tests/__init__.py new file mode 100644 index 0000000000..438bdb918c --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_picking diff --git a/delivery_estimated_package_quantity_by_weight/tests/test_stock_picking.py b/delivery_estimated_package_quantity_by_weight/tests/test_stock_picking.py new file mode 100644 index 0000000000..51b0c0ea92 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/tests/test_stock_picking.py @@ -0,0 +1,478 @@ +# Copyright 2021 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo.tests.common import TransactionCase + + +class TestStockPicking(TransactionCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.env = cls.env(context=dict(cls.env.context, tracking_disable=True)) + cls.product_carrier = cls.env["product.product"].create( + { + "name": "Product Carrier", + "sale_ok": False, + "type": "service", + } + ) + + cls.partner = cls.env["res.partner"].create( + {"name": "Unittest partner", "ref": "12344566777878"} + ) + + cls.delivery_carrier = cls.env["delivery.carrier"].create( + { + "name": "Unittest delivery carrier", + "maximum_weight_per_package": 37, + "product_id": cls.product_carrier.id, + } + ) + + cls.package_type = cls.env["stock.package.type"].create( + { + "name": "Pack Type 1", + } + ) + + cls.warehouse_1 = cls.env["stock.warehouse"].create( + { + "name": "Base Warehouse", + "reception_steps": "one_step", + "delivery_steps": "pick_ship", + "code": "BWH", + } + ) + + cls.product1 = cls.env["product.product"].create( + { + "name": "Product 1", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0001", + "default_code": "12341", + } + ) + cls.product_template1 = cls.product1.product_tmpl_id + cls.product_template1.weight = 25 + + cls.product2 = cls.env["product.product"].create( + { + "name": "Product 2", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0002", + "default_code": "12342", + } + ) + cls.product_template2 = cls.product2.product_tmpl_id + cls.product_template2.weight = 30 + + cls.product3 = cls.env["product.product"].create( + { + "name": "Product 3", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0003", + "default_code": "12343", + } + ) + cls.product_template3 = cls.product3.product_tmpl_id + cls.product_template3.weight = 30 + + cls.product4 = cls.env["product.product"].create( + { + "name": "Product 4", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0004", + "default_code": "12344", + } + ) + cls.product_template4 = cls.product4.product_tmpl_id + cls.product_template4.weight = 0.3 + + cls.product5 = cls.env["product.product"].create( + { + "name": "Product 5", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0005", + "default_code": "12345", + } + ) + cls.product_template5 = cls.product5.product_tmpl_id + cls.product_template5.weight = 3 + + cls.product6 = cls.env["product.product"].create( + { + "name": "Product 6", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0006", + "default_code": "12346", + } + ) + cls.product_template6 = cls.product6.product_tmpl_id + cls.product_template6.weight = 8 + + cls.product7 = cls.env["product.product"].create( + { + "name": "Product 7", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0007", + "default_code": "12347", + } + ) + cls.product_template7 = cls.product7.product_tmpl_id + cls.product_template7.weight = 0.6 + + cls.product8 = cls.env["product.product"].create( + { + "name": "Product 8", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0008", + "default_code": "12348", + } + ) + cls.product_template8 = cls.product8.product_tmpl_id + cls.product_template8.weight = 2 + + cls.product9 = cls.env["product.product"].create( + { + "name": "Product 9", + "sale_ok": True, + "type": "product", + "list_price": 10, + "barcode": "XXX0009", + "default_code": "12349", + } + ) + cls.product_template9 = cls.product9.product_tmpl_id + cls.product_template9.weight = 12 + + cls.products = [ + cls.product1, + cls.product2, + cls.product3, + cls.product4, + cls.product5, + cls.product6, + cls.product7, + cls.product8, + cls.product9, + ] + cls.so = cls._confirm_sale_order( + partner=cls.partner, products=cls.products, carrier=cls.delivery_carrier + ) + + cls.location_model = cls.env["stock.location"] + cls.stock_location = cls.location_model.create({"name": "stock_loc"}) + cls.customer_location = cls.location_model.create({"name": "customer_loc"}) + cls.picking_type_out = cls.env.ref("stock.picking_type_out") + + @classmethod + def _confirm_sale_order(cls, partner=None, products=None, qty=10, carrier=None): + if partner is None: + partner = cls.partner + if products is None: + products = [cls.product1] + warehouse = cls.warehouse_1 + Sale = cls.env["sale.order"] + lines = [ + ( + 0, + 0, + { + "name": p.name, + "product_id": p.id, + "product_uom_qty": qty, + "product_uom": p.uom_id.id, + "price_unit": 1, + }, + ) + for p in products + ] + so_values = { + "partner_id": partner.id, + "warehouse_id": warehouse.id, + "order_line": lines, + } + if carrier: + so_values["carrier_id"] = carrier.id + + so = Sale.create(so_values) + so.action_confirm() + return so + + def test_all_products(self): + """ + Data: + All the products are in the SO, some are heavy, others light + Test case: + Check the number of packages in the shipping. Each box should not exceed 37 kg + We have a lot of products in this shipping: + 10 product1 with weight of 25kg each => 250kg + 10 product2 with weight of 30kg each => 300kg + 10 product3 with weight of 30kg each => 300kg + 10 product4 with weight of 0.3kg each => 3kg + 10 product5 with weight of 3kg each => 30kg + 10 product6 with weight of 8kg each => 80kg + 10 product7 with weight of 0.6kg each => 6kg + 10 product8 with weight of 2kg each => 20kg + 10 product9 with weight of 12kg each => 120kg + + We will have a list of weights: + [0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3,0.3, + 0.6,0.6,0.6,0.6,0.6,0.6,0.6,0.6,0.6,0.6, + 2,2,2,2,2,2,2,2,2,2, + 3,3,3,3,3,3,3,3,3,3, + 8,8,8,8,8,8,8,8,8,8, + 12,12,12,12,12,12,12,12,12,12, + 25,25,25,25,25,25,25,25,25,25, + 30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30] + + + All the 0.3kg products will go in one pack with one 30 and 6 products of + 0.6kg leading to a pack of 36.6kg => 1 pack + 4 products of 0.6kg will go with another of 30 and 2 of 2 leading to a + second pack of 36.4kg => 1 pack + 3 products of 2 kg will go with one of 30 leading to 36kg => 1 pack + 3 products of 2 kg will go with one of 30 leading to 36kg => 1 pack + 2 products of 2 kg will go with one of 30 and one of 3 leading to 37kg + => 1 pack + 2 products of 3 kg will go with one of 30 leading to 36kg => 1 pack + 2 products of 3 kg will go with one of 30 leading to 36kg => 1 pack + 2 products of 3 kg will go with one of 30 leading to 36kg => 1 pack + 2 products of 3 kg will go with one of 30 leading to 36kg => 1 pack + 1 products of 3 kg will go with one of 30 leading to 36kg => 1 pack + 10 packs of 30 + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 1 product of 8 and 1 product of 25 leading to 32kg => 1 pack + 3 products of 12 leading to 36 kg => 1 pack + 3 products of 12 leading to 36 kg => 1 pack + 3 products of 12 leading to 36 kg => 1 pack + 1 remaining of 12 => 1 pack + + Expected result: + 34 packages + """ + ship = self.so.mapped("picking_ids").filtered( + lambda p: p.picking_type_code == "outgoing" + ) + + ship._compute_theoretical_number_of_packages() + self.assertEqual(ship.theoretical_number_of_packages, 34) + + def test_light_products(self): + """ + Data: + Only light products are considered here + Test case: + Check the number of packages in the shipping. Each box should not exceed + 37 kg + Expected result: + 1 package is enough + """ + + products = [ + self.product4, + self.product5, + self.product6, + self.product7, + self.product8, + self.product9, + ] + lines = [ + ( + 0, + 0, + { + "name": p.name, + "product_id": p.id, + "product_uom_qty": 1, + "product_uom": p.uom_id.id, + "price_unit": 1, + }, + ) + for p in products + ] + so_values = { + "partner_id": self.partner.id, + "warehouse_id": self.warehouse_1.id, + "carrier_id": self.delivery_carrier.id, + "order_line": lines, + } + + new_so = self.env["sale.order"].create(so_values) + new_so.action_confirm() + ship = new_so.mapped("picking_ids").filtered( + lambda p: p.picking_type_code == "outgoing" + ) + + ship._compute_theoretical_number_of_packages() + self.assertEqual(ship.theoretical_number_of_packages, 1) + + def test_one_product(self): + """ + Data: + Only one product is considered here + Test case: + Check the number of packages in the shipping. Each box should not exceed + 37 kg + Expected result: + 1 package is enough + """ + + so_values = { + "partner_id": self.partner.id, + "warehouse_id": self.warehouse_1.id, + "carrier_id": self.delivery_carrier.id, + "order_line": [ + ( + 0, + 0, + { + "name": self.product4.name, + "product_id": self.product4.id, + "product_uom_qty": 1, + "product_uom": self.product4.uom_id.id, + "price_unit": 1, + }, + ) + ], + } + + new_so = self.env["sale.order"].create(so_values) + new_so.action_confirm() + ship = new_so.mapped("picking_ids").filtered( + lambda p: p.picking_type_code == "outgoing" + ) + + ship._compute_theoretical_number_of_packages() + self.assertEqual(ship.theoretical_number_of_packages, 1) + + def test_heavy_products(self): + """ + Data: + Only heavy products are considered here + Test case: + Check the number of packages in the shipping. Each box should not exceed + 37 kg + Expected result: + 30 packages are needed, one by product + """ + products = [self.product1, self.product2, self.product3] + lines = [ + ( + 0, + 0, + { + "name": p.name, + "product_id": p.id, + "product_uom_qty": 10, + "product_uom": p.uom_id.id, + "price_unit": 1, + }, + ) + for p in products + ] + so_values = { + "partner_id": self.partner.id, + "warehouse_id": self.warehouse_1.id, + "carrier_id": self.delivery_carrier.id, + "order_line": lines, + } + + new_so = self.env["sale.order"].create(so_values) + new_so.action_confirm() + ship = new_so.mapped("picking_ids").filtered( + lambda p: p.picking_type_code == "outgoing" + ) + + ship._compute_theoretical_number_of_packages() + self.assertEqual(ship.theoretical_number_of_packages, 30) + + def test_put_in_pack(self): + """ + Create a picking for 2 units of product 9 (weight = 12) and carrier max weight + for package = 37 + - theoretical_number_of_packages = 1 and is_number_of_packages_visible = True + and number_of_packages_done = 0 and is_number_of_packages_outranged = False + Make put in pack each time with quantity_done = 1 + - number_of_packages_done = 1 and is_number_of_packages_outranged still False + Make put in pack each time with quantity_done = 2 + - number_of_packages_done = 2 and is_number_of_packages_outranged = True + Validate the picking to show the outranged is non blocking + - picking state is done + """ + picking = self.env["stock.picking"].create( + { + "picking_type_id": self.picking_type_out.id, + "location_id": self.stock_location.id, + "location_dest_id": self.customer_location.id, + "carrier_id": self.delivery_carrier.id, + } + ) + self.env["stock.move"].create( + { + "name": self.product9.name, + "product_id": self.product9.id, + "product_uom_qty": 2, + "product_uom": self.product9.uom_id.id, + "picking_id": picking.id, + "location_id": self.stock_location.id, + "location_dest_id": self.customer_location.id, + } + ) + picking.action_confirm() + self.assertTrue(picking.is_number_of_packages_visible) + self.assertEqual(picking.theoretical_number_of_packages, 1) + self.assertEqual(picking.number_of_packages_done, 0) + self.assertFalse(picking.is_number_of_packages_outranged) + # make a first put in pack with quantity done 1 + picking.move_ids.quantity_done = 1 + pack_action = picking.action_put_in_pack() + pack_action_ctx = pack_action["context"] + pack_wiz = ( + self.env["choose.delivery.package"] + .with_context(**pack_action_ctx) + .create({"delivery_package_type_id": self.package_type.id}) + ) + pack_wiz.action_put_in_pack() + self.assertEqual(picking.number_of_packages_done, 1) + self.assertFalse(picking.is_number_of_packages_outranged) + # make a second put in pack with quantity done 2 + picking.move_ids.quantity_done = 2 + pack_action = picking.action_put_in_pack() + pack_action_ctx = pack_action["context"] + pack_wiz = ( + self.env["choose.delivery.package"] + .with_context(**pack_action_ctx) + .create({"delivery_package_type_id": self.package_type.id}) + ) + pack_wiz.action_put_in_pack() + self.assertEqual(picking.number_of_packages_done, 2) + self.assertTrue(picking.is_number_of_packages_outranged) + # validate the picking + picking.button_validate() + self.assertEqual(picking.state, "done") diff --git a/delivery_estimated_package_quantity_by_weight/views/delivery_carrier_views.xml b/delivery_estimated_package_quantity_by_weight/views/delivery_carrier_views.xml new file mode 100644 index 0000000000..1395c891f2 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/views/delivery_carrier_views.xml @@ -0,0 +1,35 @@ + + + + + + delivery.carrier.form (in delivery_number_package_theoretical) + delivery.carrier + + + + + + + + delivery.carrier.tree (in delivery_number_package_theoretical) + delivery.carrier + + + + + + + + + diff --git a/delivery_estimated_package_quantity_by_weight/views/stock_picking_views.xml b/delivery_estimated_package_quantity_by_weight/views/stock_picking_views.xml new file mode 100644 index 0000000000..d405b2f733 --- /dev/null +++ b/delivery_estimated_package_quantity_by_weight/views/stock_picking_views.xml @@ -0,0 +1,56 @@ + + + + + + stock.picking.form (in delivery_number_package_theoretical) + stock.picking + + +
+ + +
+ + +

+

+
+

+ + / +

+
+
+
+
+ +
From 76bbcdcbd5f2f44384b131ddbe78454a7c68944c Mon Sep 17 00:00:00 2001 From: oca-ci Date: Wed, 12 Jul 2023 09:19:16 +0000 Subject: [PATCH 02/12] [UPD] Update delivery_estimated_package_quantity_by_weight.pot --- .../i18n/delivery_estimated_package_quantity_by_weight.pot | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot b/delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot index 60ab439974..0eebeecd2c 100644 --- a/delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot +++ b/delivery_estimated_package_quantity_by_weight/i18n/delivery_estimated_package_quantity_by_weight.pot @@ -4,10 +4,8 @@ # msgid "" msgstr "" -"Project-Id-Version: Odoo Server 16.0+e\n" +"Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2023-03-13 13:22+0000\n" -"PO-Revision-Date: 2023-03-13 13:22+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" From 5925e63410dee650117948efc75be7b019a79b88 Mon Sep 17 00:00:00 2001 From: OCA-git-bot Date: Wed, 12 Jul 2023 09:32:16 +0000 Subject: [PATCH 03/12] [UPD] README.rst --- .../README.rst | 8 ++++---- .../static/description/index.html | 10 +++++----- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/delivery_estimated_package_quantity_by_weight/README.rst b/delivery_estimated_package_quantity_by_weight/README.rst index dc8e9825e5..0ae6fdec84 100644 --- a/delivery_estimated_package_quantity_by_weight/README.rst +++ b/delivery_estimated_package_quantity_by_weight/README.rst @@ -19,11 +19,11 @@ Delivery Estimated Package Quantity By Weight .. |badge4| image:: https://img.shields.io/badge/weblate-Translate%20me-F47D42.png :target: https://translation.odoo-community.org/projects/delivery-carrier-16-0/delivery-carrier-16-0-delivery_estimated_package_quantity_by_weight :alt: Translate me on Weblate -.. |badge5| image:: https://img.shields.io/badge/runboat-Try%20me-875A7B.png - :target: https://runboat.odoo-community.org/webui/builds.html?repo=OCA/delivery-carrier&target_branch=16.0 - :alt: Try me on Runboat +.. |badge5| image:: https://img.shields.io/badge/runbot-Try%20me-875A7B.png + :target: https://runbot.odoo-community.org/runbot/99/16.0 + :alt: Try me on Runbot -|badge1| |badge2| |badge3| |badge4| |badge5| +|badge1| |badge2| |badge3| |badge4| |badge5| This module computes the amount of packages a picking out should have depending on the weight of the products and the limit fixed by the carrier. diff --git a/delivery_estimated_package_quantity_by_weight/static/description/index.html b/delivery_estimated_package_quantity_by_weight/static/description/index.html index cbd86d4ac3..ab36b9ddc1 100644 --- a/delivery_estimated_package_quantity_by_weight/static/description/index.html +++ b/delivery_estimated_package_quantity_by_weight/static/description/index.html @@ -3,7 +3,7 @@ - + Delivery Estimated Package Quantity By Weight