From 3f4f54090f9a12a5ad61443df9bda945f7848df1 Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Baudoux Date: Thu, 11 Jul 2019 18:15:24 +0200 Subject: [PATCH 1/8] [ADD] stock_location_zone --- .../odoo/addons/stock_location_zone | 1 + setup/stock_location_zone/setup.py | 6 ++ stock_location_zone/README.rst | 85 +++++++++++++++++++ stock_location_zone/__init__.py | 1 + stock_location_zone/__manifest__.py | 24 ++++++ stock_location_zone/models/__init__.py | 3 + stock_location_zone/models/picking_type.py | 10 +++ stock_location_zone/models/picking_zone.py | 28 ++++++ stock_location_zone/models/stock_location.py | 41 +++++++++ stock_location_zone/readme/CONFIGURE.rst | 5 ++ stock_location_zone/readme/CONTRIBUTORS.rst | 2 + stock_location_zone/readme/DESCRIPTION.rst | 2 + .../security/ir.model.access.csv | 3 + stock_location_zone/views/picking_type.xml | 35 ++++++++ stock_location_zone/views/picking_zone.xml | 24 ++++++ stock_location_zone/views/stock_location.xml | 45 ++++++++++ 16 files changed, 315 insertions(+) create mode 120000 setup/stock_location_zone/odoo/addons/stock_location_zone create mode 100644 setup/stock_location_zone/setup.py create mode 100644 stock_location_zone/README.rst create mode 100644 stock_location_zone/__init__.py create mode 100644 stock_location_zone/__manifest__.py create mode 100644 stock_location_zone/models/__init__.py create mode 100644 stock_location_zone/models/picking_type.py create mode 100644 stock_location_zone/models/picking_zone.py create mode 100644 stock_location_zone/models/stock_location.py create mode 100644 stock_location_zone/readme/CONFIGURE.rst create mode 100644 stock_location_zone/readme/CONTRIBUTORS.rst create mode 100644 stock_location_zone/readme/DESCRIPTION.rst create mode 100644 stock_location_zone/security/ir.model.access.csv create mode 100644 stock_location_zone/views/picking_type.xml create mode 100644 stock_location_zone/views/picking_zone.xml create mode 100644 stock_location_zone/views/stock_location.xml diff --git a/setup/stock_location_zone/odoo/addons/stock_location_zone b/setup/stock_location_zone/odoo/addons/stock_location_zone new file mode 120000 index 000000000000..82bcffa0d0ad --- /dev/null +++ b/setup/stock_location_zone/odoo/addons/stock_location_zone @@ -0,0 +1 @@ +../../../stock_location_zone \ No newline at end of file diff --git a/setup/stock_location_zone/setup.py b/setup/stock_location_zone/setup.py new file mode 100644 index 000000000000..28c57bb64031 --- /dev/null +++ b/setup/stock_location_zone/setup.py @@ -0,0 +1,6 @@ +import setuptools + +setuptools.setup( + setup_requires=['setuptools-odoo'], + odoo_addon=True, +) diff --git a/stock_location_zone/README.rst b/stock_location_zone/README.rst new file mode 100644 index 000000000000..1f57cd2bad63 --- /dev/null +++ b/stock_location_zone/README.rst @@ -0,0 +1,85 @@ +=================== +Stock Location Zone +=================== + +.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !! 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%2Fstock--logistics--warehouse-lightgray.png?logo=github + :target: https://github.com/OCA/stock-logistics-warehouse/tree/12.0/stock_location_zone + :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-12-0/stock-logistics-warehouse-12-0-stock_location_zone + :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/12.0 + :alt: Try me on Runbot + +|badge1| |badge2| |badge3| |badge4| |badge5| + +Add coordinate attributes on stock location. +Define picking zone with links to picking type. + +**Table of contents** + +.. contents:: + :local: + +Configuration +============= + +In Inventory Settings, you must have: + + * Storage Locations + +Set coordinate attibute on the locations. + +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 +~~~~~~~ + +* BCIM +* Okia + +Contributors +~~~~~~~~~~~~ + +* Syvain Van Hoof (Okia sprl) +* 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/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_location_zone/__init__.py b/stock_location_zone/__init__.py new file mode 100644 index 000000000000..0650744f6bc6 --- /dev/null +++ b/stock_location_zone/__init__.py @@ -0,0 +1 @@ +from . import models diff --git a/stock_location_zone/__manifest__.py b/stock_location_zone/__manifest__.py new file mode 100644 index 000000000000..250ef43c96e3 --- /dev/null +++ b/stock_location_zone/__manifest__.py @@ -0,0 +1,24 @@ +# Copyright 2017 Syvain Van Hoof (Okia sprl) +# Copyright 2016-2019 Jacques-Etienne Baudoux (BCIM) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +{ + 'name': 'Stock Location Zone', + 'version': '12.0.1.0.0', + 'author': "BCIM, Okia, Odoo Community Association (OCA)", + 'website': "https://github.com/OCA/stock-logistics-warehouse", + 'summary': "Add coordinate attributes on stock location. " + "Define picking zone with links to picking type.", + 'category': 'Stock Management', + 'depends': [ + 'stock', + ], + 'data': [ + 'views/picking_zone.xml', + 'views/picking_type.xml', + 'views/stock_location.xml', + 'security/ir.model.access.csv', + ], + 'installable': True, + 'license': 'AGPL-3', +} diff --git a/stock_location_zone/models/__init__.py b/stock_location_zone/models/__init__.py new file mode 100644 index 000000000000..b24a792a99ba --- /dev/null +++ b/stock_location_zone/models/__init__.py @@ -0,0 +1,3 @@ +from . import picking_type +from . import picking_zone +from . import stock_location diff --git a/stock_location_zone/models/picking_type.py b/stock_location_zone/models/picking_type.py new file mode 100644 index 000000000000..0577c402d490 --- /dev/null +++ b/stock_location_zone/models/picking_type.py @@ -0,0 +1,10 @@ +# Copyright 2018-2019 Jacques-Etienne Baudoux (BCIM sprl) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class StockPickingType(models.Model): + _inherit = 'stock.picking.type' + + picking_zone_id = fields.Many2one('picking.zone', string='Picking Zone') diff --git a/stock_location_zone/models/picking_zone.py b/stock_location_zone/models/picking_zone.py new file mode 100644 index 000000000000..a49eae073b5b --- /dev/null +++ b/stock_location_zone/models/picking_zone.py @@ -0,0 +1,28 @@ +# Copyright 2017 Syvain Van Hoof (Okia sprl) +# Copyright 2017-2019 Jacques-Etienne Baudoux (BCIM sprl) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import fields, models + + +class PickingZone(models.Model): + _name = 'picking.zone' + + name = fields.Char('Name', required=True, translate=True) + code = fields.Char('Code', required=True) + picking_type_ids = fields.One2many( + 'stock.picking.type', 'picking_zone_id', + string='Picking Types') + location_name_format = fields.Char( + 'Location Name Format', + help="Format string that will compute the name of the location. " + "Use 'self' to access location object. Example: " + "'{self.area}-{self.corridor:0>2}.{self.rack:0>3}.{self.level:0>2}'") + + _sql_constraints = [ + ( + 'unique_picking_zone', + 'unique (code)', + 'The picking zone code must be unique', + ) + ] diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py new file mode 100644 index 000000000000..66e7285b0752 --- /dev/null +++ b/stock_location_zone/models/stock_location.py @@ -0,0 +1,41 @@ +# Copyright 2017 Sylvain Van Hoof +# Copyright 2018-2019 Jacques-Etienne Baudoux (BCIM sprl) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import _, api, fields, models + + +class StockLocation(models.Model): + _inherit = 'stock.location' + + kind = fields.Char('Kind', help="zone, area, bin, reserve, ...") + + picking_zone_id = fields.Many2one('picking.zone', string='Picking zone') + + # floor = fields.Char('Level', help="Floor level") + area = fields.Char('Area', oldname='zone') + corridor = fields.Char('Corridor', help="Street") + row = fields.Char('Row', help="Side in the street") + rack = fields.Char('Rack', oldname='shelf', help="House number") + level = fields.Char('Level', help="Height on the shelf") + posx = fields.Integer('Box (X)') + posy = fields.Integer('Box (Y)') + posz = fields.Integer('Box (Z)') + + _sql_constraints = [ + ( + 'unique_location_name', + 'UNIQUE(name, location_id)', + _('The location name must be unique'), + ) + ] + + @api.multi + @api.onchange('area', 'corridor', 'row', 'rack', 'level', + 'posx', 'posy', 'posz') + def _compute_name(self): + for location in self: + if not location.picking_zone_id.location_name_format: + continue + location.name = location.picking_zone_id.location_name_format.format( + self=location) diff --git a/stock_location_zone/readme/CONFIGURE.rst b/stock_location_zone/readme/CONFIGURE.rst new file mode 100644 index 000000000000..1d20f0c1ce78 --- /dev/null +++ b/stock_location_zone/readme/CONFIGURE.rst @@ -0,0 +1,5 @@ +In Inventory Settings, you must have: + + * Storage Locations + +Set coordinate attibute on the locations. diff --git a/stock_location_zone/readme/CONTRIBUTORS.rst b/stock_location_zone/readme/CONTRIBUTORS.rst new file mode 100644 index 000000000000..2cfff722a67a --- /dev/null +++ b/stock_location_zone/readme/CONTRIBUTORS.rst @@ -0,0 +1,2 @@ +* Syvain Van Hoof (Okia sprl) +* Jacques-Etienne Baudoux (BCIM) diff --git a/stock_location_zone/readme/DESCRIPTION.rst b/stock_location_zone/readme/DESCRIPTION.rst new file mode 100644 index 000000000000..ba44b8538e7e --- /dev/null +++ b/stock_location_zone/readme/DESCRIPTION.rst @@ -0,0 +1,2 @@ +Add coordinate attributes on stock location. +Define picking zone with links to picking type. diff --git a/stock_location_zone/security/ir.model.access.csv b/stock_location_zone/security/ir.model.access.csv new file mode 100644 index 000000000000..e15aeb626550 --- /dev/null +++ b/stock_location_zone/security/ir.model.access.csv @@ -0,0 +1,3 @@ +id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_picking_zone,access_picking_zone,model_picking_zone,base.group_user,1,0,0,0 +access_picking_zone_manager,access_picking_zone_manager,model_picking_zone,base.group_system,1,1,1,1 diff --git a/stock_location_zone/views/picking_type.xml b/stock_location_zone/views/picking_type.xml new file mode 100644 index 000000000000..ecf38ba29be9 --- /dev/null +++ b/stock_location_zone/views/picking_type.xml @@ -0,0 +1,35 @@ + + + + view.picking.type.tree.inherit + stock.picking.type + + + + + + + + + + view.picking.type.form.inherit + stock.picking.type + + + + + + + + + + view.picking.type.filter.inherit + stock.picking.type + + + + + + + + diff --git a/stock_location_zone/views/picking_zone.xml b/stock_location_zone/views/picking_zone.xml new file mode 100644 index 000000000000..534ce7d86ef2 --- /dev/null +++ b/stock_location_zone/views/picking_zone.xml @@ -0,0 +1,24 @@ + + + + picking.zone.view.tree + picking.zone + + + + + + + + + + + + diff --git a/stock_location_zone/views/stock_location.xml b/stock_location_zone/views/stock_location.xml new file mode 100644 index 000000000000..2e8205484440 --- /dev/null +++ b/stock_location_zone/views/stock_location.xml @@ -0,0 +1,45 @@ + + + + + stock.location.zone + stock.location + + + + + + + + + + + + + + + + + + + + + view.location.search.inherit + stock.location + + + + + + + + + + + + + + + + + From 33067e816f324a045796c9e60e837eab19f87b7b Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Baudoux Date: Thu, 11 Jul 2019 18:15:24 +0200 Subject: [PATCH 2/8] [ADD] stock_location_zone --- stock_location_zone/models/picking_zone.py | 3 ++- stock_location_zone/models/stock_location.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/stock_location_zone/models/picking_zone.py b/stock_location_zone/models/picking_zone.py index a49eae073b5b..5e2d8731397f 100644 --- a/stock_location_zone/models/picking_zone.py +++ b/stock_location_zone/models/picking_zone.py @@ -17,7 +17,8 @@ class PickingZone(models.Model): 'Location Name Format', help="Format string that will compute the name of the location. " "Use 'self' to access location object. Example: " - "'{self.area}-{self.corridor:0>2}.{self.rack:0>3}.{self.level:0>2}'") + "'{self.area}-{self.corridor:0>2}.{self.rack:0>3}" + ".{self.level:0>2}'") _sql_constraints = [ ( diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 66e7285b0752..19ad9b473188 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -37,5 +37,5 @@ def _compute_name(self): for location in self: if not location.picking_zone_id.location_name_format: continue - location.name = location.picking_zone_id.location_name_format.format( - self=location) + location.name = location.picking_zone_id.location_name_format\ + .format(self=location) From d9527d6e3cc0dd1df700d19815c4f0ad0d4da4b9 Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Baudoux Date: Mon, 15 Jul 2019 09:33:17 +0200 Subject: [PATCH 3/8] Refactoring --- .../odoo/addons/stock_location_zone | 2 +- stock_location_zone/__manifest__.py | 3 +- stock_location_zone/models/__init__.py | 3 +- stock_location_zone/models/picking_type.py | 10 - stock_location_zone/models/stock_location.py | 63 ++- ...{picking_zone.py => stock_picking_zone.py} | 16 +- .../security/ir.model.access.csv | 4 +- .../static/description/index.html | 433 ++++++++++++++++++ stock_location_zone/views/picking_type.xml | 35 -- stock_location_zone/views/picking_zone.xml | 24 - stock_location_zone/views/stock_location.xml | 4 +- .../views/stock_picking_zone.xml | 41 ++ 12 files changed, 538 insertions(+), 100 deletions(-) delete mode 100644 stock_location_zone/models/picking_type.py rename stock_location_zone/models/{picking_zone.py => stock_picking_zone.py} (54%) create mode 100644 stock_location_zone/static/description/index.html delete mode 100644 stock_location_zone/views/picking_type.xml delete mode 100644 stock_location_zone/views/picking_zone.xml create mode 100644 stock_location_zone/views/stock_picking_zone.xml diff --git a/setup/stock_location_zone/odoo/addons/stock_location_zone b/setup/stock_location_zone/odoo/addons/stock_location_zone index 82bcffa0d0ad..7d216d8f919f 120000 --- a/setup/stock_location_zone/odoo/addons/stock_location_zone +++ b/setup/stock_location_zone/odoo/addons/stock_location_zone @@ -1 +1 @@ -../../../stock_location_zone \ No newline at end of file +../../../../stock_location_zone \ No newline at end of file diff --git a/stock_location_zone/__manifest__.py b/stock_location_zone/__manifest__.py index 250ef43c96e3..95808d17e415 100644 --- a/stock_location_zone/__manifest__.py +++ b/stock_location_zone/__manifest__.py @@ -14,8 +14,7 @@ 'stock', ], 'data': [ - 'views/picking_zone.xml', - 'views/picking_type.xml', + 'views/stock_picking_zone.xml', 'views/stock_location.xml', 'security/ir.model.access.csv', ], diff --git a/stock_location_zone/models/__init__.py b/stock_location_zone/models/__init__.py index b24a792a99ba..408b07ec6496 100644 --- a/stock_location_zone/models/__init__.py +++ b/stock_location_zone/models/__init__.py @@ -1,3 +1,2 @@ -from . import picking_type -from . import picking_zone +from . import stock_picking_zone from . import stock_location diff --git a/stock_location_zone/models/picking_type.py b/stock_location_zone/models/picking_type.py deleted file mode 100644 index 0577c402d490..000000000000 --- a/stock_location_zone/models/picking_type.py +++ /dev/null @@ -1,10 +0,0 @@ -# Copyright 2018-2019 Jacques-Etienne Baudoux (BCIM sprl) -# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). - -from odoo import fields, models - - -class StockPickingType(models.Model): - _inherit = 'stock.picking.type' - - picking_zone_id = fields.Many2one('picking.zone', string='Picking Zone') diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 19ad9b473188..d3af3f07122c 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -8,12 +8,36 @@ class StockLocation(models.Model): _inherit = 'stock.location' - kind = fields.Char('Kind', help="zone, area, bin, reserve, ...") + # FIXME: add in selection: shuttle, tray (module vertical lift) + kind = fields.Selection([ + ('zone', 'Picking Zone'), + ('area', 'Area'), + ('bin', 'Bin'), + ], + string='Kind') - picking_zone_id = fields.Many2one('picking.zone', string='Picking zone') + picking_zone_id = fields.Many2one( + 'stock.picking.zone', + string='Picking zone') + + picking_type_id = fields.Many2one( + related='picking_zone_id.pick_type_id', + help="Picking type for operations from this location", + oldname='barcode_picking_type_id') + + area = fields.Char( + 'Area', + compute='_compute_area', store=True, + oldname='zone') + + @api.depends('name', 'kind', 'location_id.area') + def _compute_area(self): + for location in self: + if location.kind == 'area': + location.area = location.name + else: + location.area = location.location_id.area - # floor = fields.Char('Level', help="Floor level") - area = fields.Char('Area', oldname='zone') corridor = fields.Char('Corridor', help="Street") row = fields.Char('Row', help="Side in the street") rack = fields.Char('Rack', oldname='shelf', help="House number") @@ -22,6 +46,28 @@ class StockLocation(models.Model): posy = fields.Integer('Box (Y)') posz = fields.Integer('Box (Z)') + location_name_format = fields.Char( + 'Location Name Format', + help="Format string that will compute the name of the location. " + "Use location fields. Example: " + "'{area}-{corridor:0>2}.{rack:0>3}" + ".{level:0>2}'") + + @api.multi + @api.onchange('corridor', 'row', 'rack', 'level', + 'posx', 'posy', 'posz') + def _compute_name(self): + for location in self: + if not location.kind == 'bin': + continue + area = location + while not area.location_name_format: + if not area.location_id: + return + area = area.location_id + location.name = area.location_name_format\ + .format(**location.read()) + _sql_constraints = [ ( 'unique_location_name', @@ -30,12 +76,3 @@ class StockLocation(models.Model): ) ] - @api.multi - @api.onchange('area', 'corridor', 'row', 'rack', 'level', - 'posx', 'posy', 'posz') - def _compute_name(self): - for location in self: - if not location.picking_zone_id.location_name_format: - continue - location.name = location.picking_zone_id.location_name_format\ - .format(self=location) diff --git a/stock_location_zone/models/picking_zone.py b/stock_location_zone/models/stock_picking_zone.py similarity index 54% rename from stock_location_zone/models/picking_zone.py rename to stock_location_zone/models/stock_picking_zone.py index 5e2d8731397f..2cee46aca247 100644 --- a/stock_location_zone/models/picking_zone.py +++ b/stock_location_zone/models/stock_picking_zone.py @@ -6,19 +6,15 @@ class PickingZone(models.Model): - _name = 'picking.zone' + _name = 'stock.picking.zone' name = fields.Char('Name', required=True, translate=True) code = fields.Char('Code', required=True) - picking_type_ids = fields.One2many( - 'stock.picking.type', 'picking_zone_id', - string='Picking Types') - location_name_format = fields.Char( - 'Location Name Format', - help="Format string that will compute the name of the location. " - "Use 'self' to access location object. Example: " - "'{self.area}-{self.corridor:0>2}.{self.rack:0>3}" - ".{self.level:0>2}'") + pick_type_id = fields.Many2one( + 'stock.picking.type', + string='Pick Type', + help="Picking type for operations from this location", + ) _sql_constraints = [ ( diff --git a/stock_location_zone/security/ir.model.access.csv b/stock_location_zone/security/ir.model.access.csv index e15aeb626550..af447933955b 100644 --- a/stock_location_zone/security/ir.model.access.csv +++ b/stock_location_zone/security/ir.model.access.csv @@ -1,3 +1,3 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_picking_zone,access_picking_zone,model_picking_zone,base.group_user,1,0,0,0 -access_picking_zone_manager,access_picking_zone_manager,model_picking_zone,base.group_system,1,1,1,1 +access_picking_zone,access_picking_zone,model_stock_picking_zone,base.group_user,1,0,0,0 +access_picking_zone_manager,access_picking_zone_manager,model_stock_picking_zone,base.group_system,1,1,1,1 diff --git a/stock_location_zone/static/description/index.html b/stock_location_zone/static/description/index.html new file mode 100644 index 000000000000..8f68ab0bb566 --- /dev/null +++ b/stock_location_zone/static/description/index.html @@ -0,0 +1,433 @@ + + + + + + +Stock Location Zone + + + +
+

Stock Location Zone

+ + +

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

+

Add coordinate attributes on stock location. +Define picking zone with links to picking type.

+

Table of contents

+ +
+

Configuration

+

In Inventory Settings, you must have:

+
+
    +
  • Storage Locations
  • +
+
+

Set coordinate attibute on the locations.

+
+
+

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

+
    +
  • BCIM
  • +
  • Okia
  • +
+
+
+

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/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_location_zone/views/picking_type.xml b/stock_location_zone/views/picking_type.xml deleted file mode 100644 index ecf38ba29be9..000000000000 --- a/stock_location_zone/views/picking_type.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - - view.picking.type.tree.inherit - stock.picking.type - - - - - - - - - - view.picking.type.form.inherit - stock.picking.type - - - - - - - - - - view.picking.type.filter.inherit - stock.picking.type - - - - - - - - diff --git a/stock_location_zone/views/picking_zone.xml b/stock_location_zone/views/picking_zone.xml deleted file mode 100644 index 534ce7d86ef2..000000000000 --- a/stock_location_zone/views/picking_zone.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - picking.zone.view.tree - picking.zone - - - - - - - - - - - - diff --git a/stock_location_zone/views/stock_location.xml b/stock_location_zone/views/stock_location.xml index 2e8205484440..aa2fdd5b2900 100644 --- a/stock_location_zone/views/stock_location.xml +++ b/stock_location_zone/views/stock_location.xml @@ -9,10 +9,12 @@ - + + + diff --git a/stock_location_zone/views/stock_picking_zone.xml b/stock_location_zone/views/stock_picking_zone.xml new file mode 100644 index 000000000000..9c352b6a7755 --- /dev/null +++ b/stock_location_zone/views/stock_picking_zone.xml @@ -0,0 +1,41 @@ + + + + stock.picking.zone.view.filter + stock.picking.zone + + + + + + + + + stock.picking.zone.view.tree + stock.picking.zone + + + + + + + + + + + Picking Zones + stock.picking.zone + ir.actions.act_window + form + +

+ Define the picking zones of your warehouses +

+
+
+ + +
From 545a8b4299cb74b1839e1534bd3319038589d9f9 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 27 Aug 2019 11:22:50 +0200 Subject: [PATCH 4/8] Add corrections to stock_location_zone * Allow copy of stock locations (was blocked by constraint on unique name) * Correct loop in _compute_name returning too early if a record had no parent with a 'location_name_format' * Rename field pick_type_id to picking_type_id for coherency * Add missing _description on stock.picking.zone * Correct location_name_format format when the record is a NewId --- stock_location_zone/__manifest__.py | 2 +- stock_location_zone/models/stock_location.py | 29 ++++++++++++++----- .../models/stock_picking_zone.py | 5 ++-- .../views/stock_picking_zone.xml | 2 +- 4 files changed, 27 insertions(+), 11 deletions(-) diff --git a/stock_location_zone/__manifest__.py b/stock_location_zone/__manifest__.py index 95808d17e415..08b4873c023c 100644 --- a/stock_location_zone/__manifest__.py +++ b/stock_location_zone/__manifest__.py @@ -5,7 +5,7 @@ { 'name': 'Stock Location Zone', 'version': '12.0.1.0.0', - 'author': "BCIM, Okia, Odoo Community Association (OCA)", + 'author': "BCIM, Okia, Camptocamp, Odoo Community Association (OCA)", 'website': "https://github.com/OCA/stock-logistics-warehouse", 'summary': "Add coordinate attributes on stock location. " "Define picking zone with links to picking type.", diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index d3af3f07122c..01f5495e6086 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -21,7 +21,7 @@ class StockLocation(models.Model): string='Picking zone') picking_type_id = fields.Many2one( - related='picking_zone_id.pick_type_id', + related='picking_zone_id.picking_type_id', help="Picking type for operations from this location", oldname='barcode_picking_type_id') @@ -61,12 +61,28 @@ def _compute_name(self): if not location.kind == 'bin': continue area = location - while not area.location_name_format: - if not area.location_id: - return + while area and not area.location_name_format: area = area.location_id - location.name = area.location_name_format\ - .format(**location.read()) + if not area: + continue + template = area.location_name_format + # We don't want to use the full browse record as it would + # give too much access to internals for the users. + # We cannot use location.read() as we may have a NewId. + # We should have the record's values in the cache at this + # point. We must be cautious not to leak an environment through + # relational fields. + # values = self._convert_to_cache(location._cache) + location.name = template.format(**location._cache) + + @api.multi + @api.returns('self', lambda value: value.id) + def copy(self, default=None): + self.ensure_one() + default = dict(default or {}) + if 'name' not in default: + default['name'] = _("%s (copy)") % (self.name) + return super().copy(default=default) _sql_constraints = [ ( @@ -75,4 +91,3 @@ def _compute_name(self): _('The location name must be unique'), ) ] - diff --git a/stock_location_zone/models/stock_picking_zone.py b/stock_location_zone/models/stock_picking_zone.py index 2cee46aca247..57d586c11f9b 100644 --- a/stock_location_zone/models/stock_picking_zone.py +++ b/stock_location_zone/models/stock_picking_zone.py @@ -7,14 +7,15 @@ class PickingZone(models.Model): _name = 'stock.picking.zone' + _description = "Stock Picking Zone" name = fields.Char('Name', required=True, translate=True) code = fields.Char('Code', required=True) - pick_type_id = fields.Many2one( + picking_type_id = fields.Many2one( 'stock.picking.type', string='Pick Type', help="Picking type for operations from this location", - ) + ) _sql_constraints = [ ( diff --git a/stock_location_zone/views/stock_picking_zone.xml b/stock_location_zone/views/stock_picking_zone.xml index 9c352b6a7755..9ac330587a81 100644 --- a/stock_location_zone/views/stock_picking_zone.xml +++ b/stock_location_zone/views/stock_picking_zone.xml @@ -17,7 +17,7 @@ - +
From 00dd81476e6ee31158e02aeaeceddd32d98628bd Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 27 Aug 2019 11:36:37 +0200 Subject: [PATCH 5/8] fixup! Add corrections to stock_location_zone --- stock_location_zone/models/stock_location.py | 1 - 1 file changed, 1 deletion(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 01f5495e6086..40556b90726f 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -72,7 +72,6 @@ def _compute_name(self): # We should have the record's values in the cache at this # point. We must be cautious not to leak an environment through # relational fields. - # values = self._convert_to_cache(location._cache) location.name = template.format(**location._cache) @api.multi From dd28e0e0224347126b50f69ca937773bb1ed38e0 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Tue, 27 Aug 2019 13:59:46 +0200 Subject: [PATCH 6/8] Replace SQL unique constraint by a python one The new constraints prevents having 2 locations with the same name in the same zone. The SQL UNIQUE constraint was blocking the installation of some addons due to demo data creating, by default, some locations with the same name for the warehouses' locations. Alternative: we could create an INDEX UNIQUE (name, location_id) WHERE picking_zone_id IS NOT NULL But it depends if we want to check the whole tree or not. --- stock_location_zone/models/stock_location.py | 37 +++++++++++++++----- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 40556b90726f..8ac5232ee8c5 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -2,7 +2,7 @@ # Copyright 2018-2019 Jacques-Etienne Baudoux (BCIM sprl) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import _, api, fields, models +from odoo import _, api, exceptions, fields, models class StockLocation(models.Model): @@ -18,7 +18,9 @@ class StockLocation(models.Model): picking_zone_id = fields.Many2one( 'stock.picking.zone', - string='Picking zone') + string='Picking zone', + index=True, + ) picking_type_id = fields.Many2one( related='picking_zone_id.picking_type_id', @@ -83,10 +85,27 @@ def copy(self, default=None): default['name'] = _("%s (copy)") % (self.name) return super().copy(default=default) - _sql_constraints = [ - ( - 'unique_location_name', - 'UNIQUE(name, location_id)', - _('The location name must be unique'), - ) - ] + @api.constrains('name', 'picking_zone_id', 'location_id') + def _check_location_zone_unique_name(self): + """Check that no location has same name for a zone""" + for location in self: + # find zone of the location in parents + current = location + zone = current.picking_zone_id + while current and not zone: + current = current.location_id + zone = current.picking_zone_id + if not zone: + continue + # find all locations in the same zone + zone_locs = self.search([('picking_zone_id', '=', zone.id)]) + same_name_locs = self.search([ + ('id', 'child_of', zone_locs.ids), + ('id', '!=', location.id), + ('name', '=', location.name), + ]) + if same_name_locs: + raise exceptions.ValidationError( + _('Another location with the name "%s" exists in the same' + ' zone. Please use another name.') % (location.name,) + ) From 508519aa983fcfda67eb8030782af547726ebf7a Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 28 Aug 2019 13:41:11 +0200 Subject: [PATCH 7/8] Use unique index for unique location name per zone The python one was much too slow with large datasets. Here we only check one level (only when the zone is directly assigned), the previous SQL constraint was checking the locations of the same level only anyway. --- stock_location_zone/models/stock_location.py | 83 ++++++++++++++------ 1 file changed, 58 insertions(+), 25 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 8ac5232ee8c5..33d8b3517949 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -2,7 +2,32 @@ # Copyright 2018-2019 Jacques-Etienne Baudoux (BCIM sprl) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import _, api, exceptions, fields, models +from psycopg2 import sql + +from odoo import _, api, exceptions, fields, models, SUPERUSER_ID +from odoo.tools.sql import index_exists, _schema + + +def create_unique_index_where(cr, indexname, tablename, expressions, where): + """Create the given unique index unless it exists.""" + if index_exists(cr, indexname): + return + + args = ', '.join(expressions) + # pylint: disable=sql-injection + cr.execute( + sql.SQL( + 'CREATE UNIQUE INDEX {} ON {} ({}) WHERE {}').format( + sql.Identifier(indexname), + sql.Identifier(tablename), + sql.SQL(args), + sql.SQL(where), + ) + ) + _schema.debug( + "Table %r: created unique index %r (%s) WHERE {}", + tablename, indexname, args, where + ) class StockLocation(models.Model): @@ -85,27 +110,35 @@ def copy(self, default=None): default['name'] = _("%s (copy)") % (self.name) return super().copy(default=default) - @api.constrains('name', 'picking_zone_id', 'location_id') - def _check_location_zone_unique_name(self): - """Check that no location has same name for a zone""" - for location in self: - # find zone of the location in parents - current = location - zone = current.picking_zone_id - while current and not zone: - current = current.location_id - zone = current.picking_zone_id - if not zone: - continue - # find all locations in the same zone - zone_locs = self.search([('picking_zone_id', '=', zone.id)]) - same_name_locs = self.search([ - ('id', 'child_of', zone_locs.ids), - ('id', '!=', location.id), - ('name', '=', location.name), - ]) - if same_name_locs: - raise exceptions.ValidationError( - _('Another location with the name "%s" exists in the same' - ' zone. Please use another name.') % (location.name,) - ) + @api.model_cr + def init(self): + env = api.Environment(self._cr, SUPERUSER_ID, {}) + self._init_zone_index(env) + + def _init_zone_index(self, env): + """Add unique index on name per zone + + We cannot use _sql_constraints because it doesn't support + WHERE conditions. We need to apply the unique constraint + only within the same zone, otherwise the constraint fails + even on demo data (locations created automatically for + warehouses). + """ + index_name = 'stock_location_unique_name_zone_index' + create_unique_index_where( + env.cr, index_name, self._table, + ['name', 'picking_zone_id'], + 'picking_zone_id IS NOT NULL' + ) + + @classmethod + def _init_constraints_onchanges(cls): + # As the unique index created in this model acts as a unique + # constraints but cannot be registered in '_sql_constraints' + # (it doesn't support WHERE clause), associate an error + # message manually (reproduce what _sql_constraints does). + key = 'unique_name_zone' + message = ('Another location with the same name exists in the same' + ' zone. Please rename the location.') + cls.pool._sql_error[cls._table + '_' + key] = message + super()._init_constraints_onchanges() From a6998d67a653554a5c26b71a8bf428b8e7ba09e3 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Wed, 28 Aug 2019 14:20:11 +0200 Subject: [PATCH 8/8] Set Alpha development status * Add copyright header * Add myself as contributor of stock_location_zone * Fix lint --- stock_location_zone/__manifest__.py | 1 + stock_location_zone/models/stock_location.py | 6 +++--- stock_location_zone/readme/CONTRIBUTORS.rst | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/stock_location_zone/__manifest__.py b/stock_location_zone/__manifest__.py index 08b4873c023c..3ed81d847c12 100644 --- a/stock_location_zone/__manifest__.py +++ b/stock_location_zone/__manifest__.py @@ -19,5 +19,6 @@ 'security/ir.model.access.csv', ], 'installable': True, + 'development_status': 'Alpha', 'license': 'AGPL-3', } diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 33d8b3517949..d1bee86ce976 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -1,10 +1,11 @@ # Copyright 2017 Sylvain Van Hoof # Copyright 2018-2019 Jacques-Etienne Baudoux (BCIM sprl) +# Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from psycopg2 import sql -from odoo import _, api, exceptions, fields, models, SUPERUSER_ID +from odoo import _, api, fields, models, SUPERUSER_ID from odoo.tools.sql import index_exists, _schema @@ -37,8 +38,7 @@ class StockLocation(models.Model): kind = fields.Selection([ ('zone', 'Picking Zone'), ('area', 'Area'), - ('bin', 'Bin'), - ], + ('bin', 'Bin')], string='Kind') picking_zone_id = fields.Many2one( diff --git a/stock_location_zone/readme/CONTRIBUTORS.rst b/stock_location_zone/readme/CONTRIBUTORS.rst index 2cfff722a67a..8ef4d90eb11c 100644 --- a/stock_location_zone/readme/CONTRIBUTORS.rst +++ b/stock_location_zone/readme/CONTRIBUTORS.rst @@ -1,2 +1,3 @@ * Syvain Van Hoof (Okia sprl) * Jacques-Etienne Baudoux (BCIM) +* Guewen Baconnier (Camptocamp)