From a52586b4d40dd6908ad0e0c33161a1231251ef0c Mon Sep 17 00:00:00 2001 From: sbejaoui Date: Wed, 8 Mar 2023 13:10:43 +0100 Subject: [PATCH] [ADD] - add stock_release_channel_geoengine --- .github/workflows/test.yml | 2 +- .../addons/stock_release_channel_geoengine | 1 + .../stock_release_channel_geoengine/setup.py | 6 + stock_release_channel_geoengine/README.rst | 92 ++++ stock_release_channel_geoengine/__init__.py | 1 + .../__manifest__.py | 17 + .../models/__init__.py | 3 + .../models/res_partner.py | 30 ++ .../models/stock_picking.py | 22 + .../models/stock_release_channel.py | 16 + .../readme/CONFIGURE.rst | 4 + .../readme/CONTRIBUTORS.rst | 2 + .../readme/DESCRIPTION.rst | 4 + .../readme/INSTALL.rst | 3 + .../static/description/icon.png | 0 .../static/description/index.html | 440 ++++++++++++++++++ .../tests/__init__.py | 1 + .../tests/common.py | 36 ++ .../test_stock_release_channel_geoengine.py | 92 ++++ .../views/res_partner.xml | 29 ++ .../views/stock_release_channel.xml | 129 +++++ 21 files changed, 929 insertions(+), 1 deletion(-) create mode 120000 setup/stock_release_channel_geoengine/odoo/addons/stock_release_channel_geoengine create mode 100644 setup/stock_release_channel_geoengine/setup.py create mode 100644 stock_release_channel_geoengine/README.rst create mode 100644 stock_release_channel_geoengine/__init__.py create mode 100644 stock_release_channel_geoengine/__manifest__.py create mode 100644 stock_release_channel_geoengine/models/__init__.py create mode 100644 stock_release_channel_geoengine/models/res_partner.py create mode 100644 stock_release_channel_geoengine/models/stock_picking.py create mode 100644 stock_release_channel_geoengine/models/stock_release_channel.py create mode 100644 stock_release_channel_geoengine/readme/CONFIGURE.rst create mode 100644 stock_release_channel_geoengine/readme/CONTRIBUTORS.rst create mode 100644 stock_release_channel_geoengine/readme/DESCRIPTION.rst create mode 100644 stock_release_channel_geoengine/readme/INSTALL.rst create mode 100644 stock_release_channel_geoengine/static/description/icon.png create mode 100644 stock_release_channel_geoengine/static/description/index.html create mode 100644 stock_release_channel_geoengine/tests/__init__.py create mode 100644 stock_release_channel_geoengine/tests/common.py create mode 100644 stock_release_channel_geoengine/tests/test_stock_release_channel_geoengine.py create mode 100644 stock_release_channel_geoengine/views/res_partner.xml create mode 100644 stock_release_channel_geoengine/views/stock_release_channel.xml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f1b2b9fd6cc..4387299556e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -42,7 +42,7 @@ jobs: name: test with OCB services: postgres: - image: postgres:12.0 + image: postgis/postgis:12-3.3 env: POSTGRES_USER: odoo POSTGRES_PASSWORD: odoo diff --git a/setup/stock_release_channel_geoengine/odoo/addons/stock_release_channel_geoengine b/setup/stock_release_channel_geoengine/odoo/addons/stock_release_channel_geoengine new file mode 120000 index 00000000000..fbb030dcaeb --- /dev/null +++ b/setup/stock_release_channel_geoengine/odoo/addons/stock_release_channel_geoengine @@ -0,0 +1 @@ +../../../../stock_release_channel_geoengine \ No newline at end of file diff --git a/setup/stock_release_channel_geoengine/setup.py b/setup/stock_release_channel_geoengine/setup.py new file mode 100644 index 00000000000..28c57bb6403 --- /dev/null +++ b/setup/stock_release_channel_geoengine/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_release_channel_geoengine/README.rst b/stock_release_channel_geoengine/README.rst new file mode 100644 index 00000000000..bb1266133eb --- /dev/null +++ b/stock_release_channel_geoengine/README.rst @@ -0,0 +1,92 @@ +=============================== +Stock Release Channel Geoengine +=============================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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%2Fwms-lightgray.png?logo=github + :target: https://github.com/OCA/wms/tree/16.0/stock_release_channel_geoengine + :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_geoengine + :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/wms&target_branch=16.0 + :alt: Try me on Runboat + +|badge1| |badge2| |badge3| |badge4| |badge5| + +This module enhance release channels with the addition of +a delivery zone that can be selected by the delivery manager through the UI. +If a zone is specified, the release channel will exclusively select deliveries +for partners who are localized within that zone. + +**Table of contents** + +.. contents:: + :local: + +Installation +============ + +In order to determine if a contact belongs to a geographical zone, +this module relies on the `base_geoengine` addon. Thus, the `postgis` extension +module for `postgresql` is needed for this purpose. + +Configuration +============= + +- On the release channel, check `Restrict To Delivery Zone`. +- Select the delivery zone. +- To exclude certain partners from selection based on their location, you can + uncheck the "Delivery based on geo-localization?" option in the partner view. + +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 +~~~~~~~~~~~~ + +* Laurent Mignon +* Souheil Bejaoui + +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_geoengine/__init__.py b/stock_release_channel_geoengine/__init__.py new file mode 100644 index 00000000000..0650744f6bc --- /dev/null +++ b/stock_release_channel_geoengine/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_release_channel_geoengine/__manifest__.py b/stock_release_channel_geoengine/__manifest__.py new file mode 100644 index 00000000000..967dce06a42 --- /dev/null +++ b/stock_release_channel_geoengine/__manifest__.py @@ -0,0 +1,17 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +{ + "name": "Stock Release Channel Geoengine", + "summary": """Release channel based on geo-localization""", + "version": "16.0.1.0.0", + "license": "AGPL-3", + "author": "ACSONE SA/NV,Odoo Community Association (OCA)", + "website": "https://github.com/OCA/wms", + "depends": ["geoengine_partner", "stock_release_channel"], + "data": [ + "views/res_partner.xml", + "views/stock_release_channel.xml", + ], + "demo": [], +} diff --git a/stock_release_channel_geoengine/models/__init__.py b/stock_release_channel_geoengine/models/__init__.py new file mode 100644 index 00000000000..f561e6c4334 --- /dev/null +++ b/stock_release_channel_geoengine/models/__init__.py @@ -0,0 +1,3 @@ +from . import stock_release_channel +from . import res_partner +from . import stock_picking diff --git a/stock_release_channel_geoengine/models/res_partner.py b/stock_release_channel_geoengine/models/res_partner.py new file mode 100644 index 00000000000..ed3aad78311 --- /dev/null +++ b/stock_release_channel_geoengine/models/res_partner.py @@ -0,0 +1,30 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models + + +class ResPartner(models.Model): + + _inherit = "res.partner" + + in_geo_release_channel = fields.Boolean( + string="Delivery based on geo-localization?", + help="Include in release channels based on geographic zones", + default=True, + ) + stock_release_channel_ids = fields.Many2many( + comodel_name="stock.release.channel", + string="Release Channels", + compute="_compute_stock_release_channel_id", + ) + + @api.depends("geo_point", "in_geo_release_channel") + def _compute_stock_release_channel_id(self): + for rec in self: + if not rec.geo_point or not rec.in_geo_release_channel: + rec.stock_release_channel_ids = False + continue + rec.stock_release_channel_ids = rec.stock_release_channel_ids.search( + [("delivery_zone", "geo_intersect", rec.geo_point)] + ) diff --git a/stock_release_channel_geoengine/models/stock_picking.py b/stock_release_channel_geoengine/models/stock_picking.py new file mode 100644 index 00000000000..a5705ca77fe --- /dev/null +++ b/stock_release_channel_geoengine/models/stock_picking.py @@ -0,0 +1,22 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo import models + + +class StockPicking(models.Model): + + _inherit = "stock.picking" + + def _get_release_channel_possible_candidate_domain(self): + self.ensure_one() + domain = super()._get_release_channel_possible_candidate_domain() + if self.partner_id.in_geo_release_channel: + domain += [ + "|", + ("restrict_to_delivery_zone", "=", False), + ("delivery_zone", "geo_intersect", self.partner_id.geo_point), + ] + else: + domain += [("restrict_to_delivery_zone", "=", False)] + return domain diff --git a/stock_release_channel_geoengine/models/stock_release_channel.py b/stock_release_channel_geoengine/models/stock_release_channel.py new file mode 100644 index 00000000000..e26b999051d --- /dev/null +++ b/stock_release_channel_geoengine/models/stock_release_channel.py @@ -0,0 +1,16 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +import logging + +from odoo import fields, models + +_logger = logging.getLogger(__name__) + + +class StockReleaseChannel(models.Model): + + _inherit = "stock.release.channel" + + restrict_to_delivery_zone = fields.Boolean() + delivery_zone = fields.GeoMultiPolygon() diff --git a/stock_release_channel_geoengine/readme/CONFIGURE.rst b/stock_release_channel_geoengine/readme/CONFIGURE.rst new file mode 100644 index 00000000000..2d8c453106b --- /dev/null +++ b/stock_release_channel_geoengine/readme/CONFIGURE.rst @@ -0,0 +1,4 @@ +- On the release channel, check `Restrict To Delivery Zone`. +- Select the delivery zone. +- To exclude certain partners from selection based on their location, you can + uncheck the "Delivery based on geo-localization?" option in the partner view. diff --git a/stock_release_channel_geoengine/readme/CONTRIBUTORS.rst b/stock_release_channel_geoengine/readme/CONTRIBUTORS.rst new file mode 100644 index 00000000000..7bbe49c97ff --- /dev/null +++ b/stock_release_channel_geoengine/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Laurent Mignon +* Souheil Bejaoui diff --git a/stock_release_channel_geoengine/readme/DESCRIPTION.rst b/stock_release_channel_geoengine/readme/DESCRIPTION.rst new file mode 100644 index 00000000000..c07c5d9fc02 --- /dev/null +++ b/stock_release_channel_geoengine/readme/DESCRIPTION.rst @@ -0,0 +1,4 @@ +This module enhance release channels with the addition of +a delivery zone that can be selected by the delivery manager through the UI. +If a zone is specified, the release channel will exclusively select deliveries +for partners who are localized within that zone. diff --git a/stock_release_channel_geoengine/readme/INSTALL.rst b/stock_release_channel_geoengine/readme/INSTALL.rst new file mode 100644 index 00000000000..4e3686720e2 --- /dev/null +++ b/stock_release_channel_geoengine/readme/INSTALL.rst @@ -0,0 +1,3 @@ +In order to determine if a contact belongs to a geographical zone, +this module relies on the `base_geoengine` addon. Thus, the `postgis` extension +module for `postgresql` is needed for this purpose. diff --git a/stock_release_channel_geoengine/static/description/icon.png b/stock_release_channel_geoengine/static/description/icon.png new file mode 100644 index 00000000000..e69de29bb2d diff --git a/stock_release_channel_geoengine/static/description/index.html b/stock_release_channel_geoengine/static/description/index.html new file mode 100644 index 00000000000..1236ac2d310 --- /dev/null +++ b/stock_release_channel_geoengine/static/description/index.html @@ -0,0 +1,440 @@ + + + + + + +Stock Release Channel Geoengine + + + +
+

Stock Release Channel Geoengine

+ + +

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

+

This module enhance release channels with the addition of +a delivery zone that can be selected by the delivery manager through the UI. +If a zone is specified, the release channel will exclusively select deliveries +for partners who are localized within that zone.

+

Table of contents

+ +
+

Installation

+

In order to determine if a contact belongs to a geographical zone, +this module relies on the base_geoengine addon. Thus, the postgis extension +module for postgresql is needed for this purpose.

+
+
+

Configuration

+
    +
  • On the release channel, check Restrict To Delivery Zone.
  • +
  • Select the delivery zone.
  • +
  • To exclude certain partners from selection based on their location, you can +uncheck the “Delivery based on geo-localization?” option in the partner view.
  • +
+
+
+

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/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_geoengine/tests/__init__.py b/stock_release_channel_geoengine/tests/__init__.py new file mode 100644 index 00000000000..827e306e126 --- /dev/null +++ b/stock_release_channel_geoengine/tests/__init__.py @@ -0,0 +1 @@ +from . import test_stock_release_channel_geoengine diff --git a/stock_release_channel_geoengine/tests/common.py b/stock_release_channel_geoengine/tests/common.py new file mode 100644 index 00000000000..226232d89f1 --- /dev/null +++ b/stock_release_channel_geoengine/tests/common.py @@ -0,0 +1,36 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from shapely.geometry.multipolygon import MultiPolygon +from shapely.geometry.polygon import Point, Polygon + +from odoo.addons.stock_release_channel.tests.common import ChannelReleaseCase + + +class TestStockReleaseChannelGeoengineCommon(ChannelReleaseCase): + @classmethod + def setUpClass(cls): + super().setUpClass() + cls.multipolygon = MultiPolygon( + [ + Polygon( + [ + [3.157493, 50.776306], + [3.157075, 50.776594], + [3.156601, 50.777019], + [3.156126, 50.777434], + [3.155595, 50.777824], + ] + ) + ] + ) + cls.empty_multipolygon = MultiPolygon([Polygon()]) + cls.point1 = Point(3.157493, 50.776306) + cls.point2 = Point(3.157075, 50.776594) + cls.point3 = Point(3.156601, 50.777019) + cls.outside_point = Point(708922.106609628, 5870795.4022844) + cls.channel = cls.env.ref("stock_release_channel.stock_release_channel_default") + cls.channel.delivery_zone = cls.multipolygon + cls.channel.restrict_to_delivery_zone = True + cls.pickings = cls.picking + cls.picking2 + cls.picking3 + cls.pickings.write({"release_channel_id": False}) diff --git a/stock_release_channel_geoengine/tests/test_stock_release_channel_geoengine.py b/stock_release_channel_geoengine/tests/test_stock_release_channel_geoengine.py new file mode 100644 index 00000000000..e2b72955020 --- /dev/null +++ b/stock_release_channel_geoengine/tests/test_stock_release_channel_geoengine.py @@ -0,0 +1,92 @@ +# Copyright 2023 ACSONE SA/NV +# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). + +from odoo.tools import mute_logger + +from .common import TestStockReleaseChannelGeoengineCommon + + +class TestStockReleaseChannelGeoengine(TestStockReleaseChannelGeoengineCommon): + @mute_logger("odoo.addons.stock_release_channel.models.stock_release_channel") + def test_assign_based_on_location_1(self): + """ + test assigning one picking based on location + """ + self.delivery_address_1.geo_point = self.point1 + self.pickings.assign_release_channel() + self.assertEqual(self.picking.release_channel_id, self.channel) + self.assertFalse((self.picking2 | self.picking3).release_channel_id) + + def test_assign_based_on_location_2(self): + """ + test assigning all picking based on location + """ + self.delivery_address_1.geo_point = self.point1 + self.delivery_address_2.geo_point = self.point2 + self.other_partner.geo_point = self.point3 + self.pickings.assign_release_channel() + self.assertEqual(self.picking.release_channel_id, self.channel) + self.assertEqual(self.picking2.release_channel_id, self.channel) + self.assertEqual(self.picking3.release_channel_id, self.channel) + + @mute_logger("odoo.addons.stock_release_channel.models.stock_release_channel") + def test_no_partner_geo_point(self): + """ + test assigning to release channel without geo-localizing partners + """ + self.pickings.assign_release_channel() + self.assertFalse(self.pickings.release_channel_id) + + @mute_logger("odoo.addons.stock_release_channel.models.stock_release_channel") + def test_partner_not_in_geo_release_channel(self): + """ + test assigning to release channel a geo-localized partner but marked as not + in_geo_release_channel + """ + self.delivery_address_1.geo_point = self.point1 + self.delivery_address_1.in_geo_release_channel = False + self.pickings.assign_release_channel() + self.assertFalse(self.pickings.release_channel_id) + + @mute_logger("odoo.addons.stock_release_channel.models.stock_release_channel") + def test_assign_outside_delivery_zone(self): + """ + test assigning to release channel a geo-localized partner outside delivery zone + """ + self.delivery_address_1.geo_point = self.outside_point + self.delivery_address_2.geo_point = self.point2 + self.other_partner.geo_point = self.point3 + self.assertFalse( + self.channel.delivery_zone.covers(self.delivery_address_1.geo_point) + ) + self.pickings.assign_release_channel() + self.assertFalse(self.picking.release_channel_id) + self.assertEqual(self.picking2.release_channel_id, self.channel) + self.assertEqual(self.picking3.release_channel_id, self.channel) + + @mute_logger("odoo.addons.stock_release_channel.models.stock_release_channel") + def test_assign_not_geo_channel(self): + """ + test default behavior for release channel without delivery zone + """ + self.pickings.assign_release_channel() + self.assertFalse(self.pickings.release_channel_id) + self.channel.restrict_to_delivery_zone = False + self.pickings.assign_release_channel() + self.assertEqual(self.picking.release_channel_id, self.channel) + self.assertEqual(self.picking2.release_channel_id, self.channel) + self.assertEqual(self.picking3.release_channel_id, self.channel) + + def test_partner_release_channel(self): + """ + test release channel is correctly set based on partner location + """ + self.assertFalse(self.other_partner.stock_release_channel_ids) + self.other_partner.geo_point = self.point1 + self.assertEqual(self.other_partner.stock_release_channel_ids, self.channel) + self.other_partner.geo_point = self.outside_point + self.assertFalse(self.other_partner.stock_release_channel_ids) + self.other_partner.geo_point = self.point1 + self.assertEqual(self.other_partner.stock_release_channel_ids, self.channel) + self.other_partner.in_geo_release_channel = False + self.assertFalse(self.other_partner.stock_release_channel_ids) diff --git a/stock_release_channel_geoengine/views/res_partner.xml b/stock_release_channel_geoengine/views/res_partner.xml new file mode 100644 index 00000000000..d212040915b --- /dev/null +++ b/stock_release_channel_geoengine/views/res_partner.xml @@ -0,0 +1,29 @@ + + + + + + res.partner + + + + + + + + + + + + + + diff --git a/stock_release_channel_geoengine/views/stock_release_channel.xml b/stock_release_channel_geoengine/views/stock_release_channel.xml new file mode 100644 index 00000000000..63f37379a1b --- /dev/null +++ b/stock_release_channel_geoengine/views/stock_release_channel.xml @@ -0,0 +1,129 @@ + + + + + + stock.release.channel + + + + + + + + + + + + + + + + + + + +
+ + + +
+
    +
  • Warehouse:
  • +
  • To Release:
  • +
  • To Do:
  • +
  • Done Today:
  • +
  • Waiting:
  • +
  • Late:
  • +
  • Priority:
  • +
+
+
+
+
+
+ + stock.release.channel +
+ + + + Geographic zones + + basic + #33ccff + 0.6 + + + + + + osm + OSM layer + + + + + + kanban + + + + + + geoengine + + + + + + tree + + + + + + form + + + +