From 72b0c92f8c1a55d0a48f502cac11e14e096b21bc Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 11 Sep 2019 12:04:32 +0200 Subject: [PATCH 01/10] Rework stock_location_zone --- stock_location_zone/__manifest__.py | 5 +- stock_location_zone/models/__init__.py | 1 - stock_location_zone/models/stock_location.py | 135 ++++++++++-------- .../models/stock_picking_zone.py | 26 ---- stock_location_zone/readme/CONFIGURE.rst | 5 - stock_location_zone/readme/CONTRIBUTORS.rst | 1 + stock_location_zone/readme/DESCRIPTION.rst | 12 +- .../security/ir.model.access.csv | 3 - stock_location_zone/views/stock_location.xml | 34 ++--- .../views/stock_picking_zone.xml | 41 ------ 10 files changed, 97 insertions(+), 166 deletions(-) delete mode 100644 stock_location_zone/models/stock_picking_zone.py delete mode 100644 stock_location_zone/readme/CONFIGURE.rst delete mode 100644 stock_location_zone/security/ir.model.access.csv delete mode 100644 stock_location_zone/views/stock_picking_zone.xml diff --git a/stock_location_zone/__manifest__.py b/stock_location_zone/__manifest__.py index 3ed81d847..c1249a352 100644 --- a/stock_location_zone/__manifest__.py +++ b/stock_location_zone/__manifest__.py @@ -7,16 +7,13 @@ 'version': '12.0.1.0.0', '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.", + 'summary': "Classify locations with zones.", 'category': 'Stock Management', 'depends': [ 'stock', ], 'data': [ - 'views/stock_picking_zone.xml', 'views/stock_location.xml', - 'security/ir.model.access.csv', ], 'installable': True, 'development_status': 'Alpha', diff --git a/stock_location_zone/models/__init__.py b/stock_location_zone/models/__init__.py index 408b07ec6..88493e35d 100644 --- a/stock_location_zone/models/__init__.py +++ b/stock_location_zone/models/__init__.py @@ -1,2 +1 @@ -from . import stock_picking_zone from . import stock_location diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index d1bee86ce..a937c934b 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -34,82 +34,93 @@ def create_unique_index_where(cr, indexname, tablename, expressions, where): class StockLocation(models.Model): _inherit = 'stock.location' - # FIXME: add in selection: shuttle, tray (module vertical lift) - kind = fields.Selection([ - ('zone', 'Picking Zone'), - ('area', 'Area'), - ('bin', 'Bin')], - string='Kind') + is_zone = fields.Boolean( + string='Is a zone location?', + help='Mark to define this location as a zone', + ) - picking_zone_id = fields.Many2one( - 'stock.picking.zone', - string='Picking zone', + zone_location_id = fields.Many2one( + 'stock.location', + string='Location zone', + compute='_compute_zone_location_id', + store=True, index=True, ) - picking_type_id = fields.Many2one( - related='picking_zone_id.picking_type_id', - help="Picking type for operations from this location", - oldname='barcode_picking_type_id') + location_kind = fields.Selection( + [ + ('zone', 'Zone'), + ('area', 'Area'), + ('bin', 'Bin'), + ('stock', 'Main Stock'), + ('other', 'Other'), + ], + string='Location Kind', + compute='_compute_location_kind', + help='Group location according to their kinds:' + '* Zone: locations that are flagged as being zones' + '* Area: locations with children that are part of a zone' + '* Bin: locations without children that are part of a zone' + '* Stock: internal locations whose parent is a view' + '* Other: any other location', + ) area = fields.Char( 'Area', - compute='_compute_area', store=True, - oldname='zone') + compute='_compute_area', + store=True, + ) - @api.depends('name', 'kind', 'location_id.area') + @api.depends('is_zone', 'usage', 'location_id.usage', 'zone_location_id', + 'child_ids') + def _compute_location_kind(self): + for location in self: + if location.is_zone: + location.location_kind = 'zone' + continue + # Internal locations whose parent is view are main stocks + if ( + location.usage == 'internal' + and location.location_id.usage == 'view' + ): + location.location_kind = 'stock' + continue + # Internal locations having a zone and no children are bins + if ( + location.usage == 'internal' + and location.zone_location_id + and not location.child_ids + ): + location.location_kind = 'bin' + continue + # Internal locations having a zone and children are areas + if ( + location.usage == 'internal' + and location.zone_location_id + and not location.child_ids + ): + location.location_kind = 'area' + continue + # All the rest are other locations + location.location_kind = 'other' + + @api.depends('is_zone', 'location_id.zone_location_id') + def _compute_zone_location_id(self): + for location in self: + if location.is_zone: + location.zone_location_id = location + else: + location.zone_location_id = \ + location.location_id.zone_location_id + + @api.depends('name', 'location_kind', 'location_id.area') def _compute_area(self): for location in self: - if location.kind == 'area': + if location.location_kind == 'area': location.area = location.name else: location.area = location.location_id.area - 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)') - - 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 area and not area.location_name_format: - area = area.location_id - 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. - 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) - @api.model_cr def init(self): env = api.Environment(self._cr, SUPERUSER_ID, {}) diff --git a/stock_location_zone/models/stock_picking_zone.py b/stock_location_zone/models/stock_picking_zone.py deleted file mode 100644 index 57d586c11..000000000 --- a/stock_location_zone/models/stock_picking_zone.py +++ /dev/null @@ -1,26 +0,0 @@ -# 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 = 'stock.picking.zone' - _description = "Stock Picking Zone" - - name = fields.Char('Name', required=True, translate=True) - code = fields.Char('Code', required=True) - picking_type_id = fields.Many2one( - 'stock.picking.type', - string='Pick Type', - help="Picking type for operations from this location", - ) - - _sql_constraints = [ - ( - 'unique_picking_zone', - 'unique (code)', - 'The picking zone code must be unique', - ) - ] diff --git a/stock_location_zone/readme/CONFIGURE.rst b/stock_location_zone/readme/CONFIGURE.rst deleted file mode 100644 index 1d20f0c1c..000000000 --- a/stock_location_zone/readme/CONFIGURE.rst +++ /dev/null @@ -1,5 +0,0 @@ -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 index 8ef4d90eb..0425dda61 100644 --- a/stock_location_zone/readme/CONTRIBUTORS.rst +++ b/stock_location_zone/readme/CONTRIBUTORS.rst @@ -1,3 +1,4 @@ * Syvain Van Hoof (Okia sprl) * Jacques-Etienne Baudoux (BCIM) * Guewen Baconnier (Camptocamp) +* Akim Juillerat diff --git a/stock_location_zone/readme/DESCRIPTION.rst b/stock_location_zone/readme/DESCRIPTION.rst index ba44b8538..02fe9ddb4 100644 --- a/stock_location_zone/readme/DESCRIPTION.rst +++ b/stock_location_zone/readme/DESCRIPTION.rst @@ -1,2 +1,10 @@ -Add coordinate attributes on stock location. -Define picking zone with links to picking type. +This module introduces Zone concept on stock locations to allow better +classification of stock locations in a warehouse. + +Locations are then classified by location kinds that could be: + +* Zone: locations that are flagged as being zones +* Area: locations with children that are part of a zone +* Bin: locations without children that are part of a zone +* Stock: internal locations whose parent is a view +* Other: any other location diff --git a/stock_location_zone/security/ir.model.access.csv b/stock_location_zone/security/ir.model.access.csv deleted file mode 100644 index af4479339..000000000 --- a/stock_location_zone/security/ir.model.access.csv +++ /dev/null @@ -1,3 +0,0 @@ -id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -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/views/stock_location.xml b/stock_location_zone/views/stock_location.xml index aa2fdd5b2..05e95c33f 100644 --- a/stock_location_zone/views/stock_location.xml +++ b/stock_location_zone/views/stock_location.xml @@ -6,22 +6,14 @@ stock.location - + + + - - - - - - - + + - - - - - @@ -30,17 +22,15 @@ stock.location - - - - - - - - + + + + + + + - diff --git a/stock_location_zone/views/stock_picking_zone.xml b/stock_location_zone/views/stock_picking_zone.xml deleted file mode 100644 index 9ac330587..000000000 --- a/stock_location_zone/views/stock_picking_zone.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - 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 e9390a4bac12c08bacdf3ffd7a55faa020bf482f Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 11 Sep 2019 12:08:08 +0200 Subject: [PATCH 02/10] Simplify constraint --- stock_location_zone/models/stock_location.py | 67 +++----------------- 1 file changed, 8 insertions(+), 59 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index a937c934b..92b715200 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -3,32 +3,7 @@ # 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, 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 - ) +from odoo import api, fields, models class StockLocation(models.Model): @@ -71,6 +46,13 @@ class StockLocation(models.Model): store=True, ) + _sql_constraints = [ + 'name_zone_unique', + 'unique(name, zone_location_id)', + 'Another location with the same name exists in the same zone. ' + 'Please rename the location.', + ] + @api.depends('is_zone', 'usage', 'location_id.usage', 'zone_location_id', 'child_ids') def _compute_location_kind(self): @@ -120,36 +102,3 @@ class StockLocation(models.Model): location.area = location.name else: location.area = location.location_id.area - - @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 5a39ba95c256a76859db959bcf4169df19477835 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 11 Sep 2019 13:06:36 +0200 Subject: [PATCH 03/10] Restore copy function --- stock_location_zone/models/stock_location.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 92b715200..a2057ae51 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -3,7 +3,7 @@ # Copyright 2019 Camptocamp SA # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import api, fields, models +from odoo import api, fields, models, _ class StockLocation(models.Model): @@ -102,3 +102,12 @@ class StockLocation(models.Model): location.area = location.name else: location.area = location.location_id.area + + @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) From 2731ca8bd4839f3586fc8e08b56c9fb81991dc17 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 11 Sep 2019 15:09:22 +0200 Subject: [PATCH 04/10] fixup! Simplify constraint --- stock_location_zone/models/stock_location.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index a2057ae51..9f575cb76 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -48,7 +48,8 @@ class StockLocation(models.Model): _sql_constraints = [ 'name_zone_unique', - 'unique(name, zone_location_id)', + 'EXCLUDE (name WITH =), (zone_location_id WITH=) ' + 'WHERE (zone_location_id IS NOT NULL)', 'Another location with the same name exists in the same zone. ' 'Please rename the location.', ] From f6ae66137cfff2751476db4a43557bad3c458cb7 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 11 Sep 2019 16:40:59 +0200 Subject: [PATCH 05/10] fixup! Rework stock_location_zone --- stock_location_zone/models/stock_location.py | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 9f575cb76..f3a17320f 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -40,12 +40,6 @@ class StockLocation(models.Model): '* Other: any other location', ) - area = fields.Char( - 'Area', - compute='_compute_area', - store=True, - ) - _sql_constraints = [ 'name_zone_unique', 'EXCLUDE (name WITH =), (zone_location_id WITH=) ' @@ -96,14 +90,6 @@ class StockLocation(models.Model): location.zone_location_id = \ location.location_id.zone_location_id - @api.depends('name', 'location_kind', 'location_id.area') - def _compute_area(self): - for location in self: - if location.location_kind == 'area': - location.area = location.name - else: - location.area = location.location_id.area - @api.multi @api.returns('self', lambda value: value.id) def copy(self, default=None): From 3941e03284200070d6779132de951a440a87212e Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Wed, 11 Sep 2019 17:00:08 +0200 Subject: [PATCH 06/10] fixup! fixup! Simplify constraint --- stock_location_zone/models/stock_location.py | 16 ++++++++-------- stock_location_zone/views/stock_location.xml | 1 - 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index f3a17320f..b9c20857d 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -10,7 +10,7 @@ class StockLocation(models.Model): _inherit = 'stock.location' is_zone = fields.Boolean( - string='Is a zone location?', + string='Is a Zone Location?', help='Mark to define this location as a zone', ) @@ -40,13 +40,13 @@ class StockLocation(models.Model): '* Other: any other location', ) - _sql_constraints = [ + _sql_constraints = [( 'name_zone_unique', - 'EXCLUDE (name WITH =), (zone_location_id WITH=) ' - 'WHERE (zone_location_id IS NOT NULL)', - 'Another location with the same name exists in the same zone. ' - 'Please rename the location.', - ] + 'EXCLUDE (name WITH =, zone_location_id WITH =)' + ' WHERE (zone_location_id IS NOT NULL)', + 'Another location with the same name exists in the same zone.' + ' Please rename the location.' + )] @api.depends('is_zone', 'usage', 'location_id.usage', 'zone_location_id', 'child_ids') @@ -74,7 +74,7 @@ class StockLocation(models.Model): if ( location.usage == 'internal' and location.zone_location_id - and not location.child_ids + and location.child_ids ): location.location_kind = 'area' continue diff --git a/stock_location_zone/views/stock_location.xml b/stock_location_zone/views/stock_location.xml index 05e95c33f..a5911aa2d 100644 --- a/stock_location_zone/views/stock_location.xml +++ b/stock_location_zone/views/stock_location.xml @@ -12,7 +12,6 @@ - From 7a204204762430cc94534a1291488364560f45d2 Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 13 Sep 2019 10:27:22 +0200 Subject: [PATCH 07/10] Remove unique constraint on location's name It prevents other addons to work properly such as the vertical lift. We remove the constraint for now, maybe to be re-introduced later in a more permissive way. --- stock_location_zone/models/stock_location.py | 8 -------- 1 file changed, 8 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index b9c20857d..d65a070fc 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -40,14 +40,6 @@ class StockLocation(models.Model): '* Other: any other location', ) - _sql_constraints = [( - 'name_zone_unique', - 'EXCLUDE (name WITH =, zone_location_id WITH =)' - ' WHERE (zone_location_id IS NOT NULL)', - 'Another location with the same name exists in the same zone.' - ' Please rename the location.' - )] - @api.depends('is_zone', 'usage', 'location_id.usage', 'zone_location_id', 'child_ids') def _compute_location_kind(self): From fc0c26ffa709890ab1e318333c505496656d222b Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 13 Sep 2019 13:01:07 +0200 Subject: [PATCH 08/10] Improve performance * Compute the 'zone' fields in the same method * Remove the dependency on 'zone_location_id', which seems to take a lot of time if not an infinite loop --- stock_location_zone/models/stock_location.py | 37 +++++++++++--------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index d65a070fc..2e306aeed 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -17,7 +17,7 @@ class StockLocation(models.Model): zone_location_id = fields.Many2one( 'stock.location', string='Location zone', - compute='_compute_zone_location_id', + compute='_compute_location_zone', store=True, index=True, ) @@ -31,7 +31,7 @@ class StockLocation(models.Model): ('other', 'Other'), ], string='Location Kind', - compute='_compute_location_kind', + compute='_compute_location_zone', help='Group location according to their kinds:' '* Zone: locations that are flagged as being zones' '* Area: locations with children that are part of a zone' @@ -40,13 +40,27 @@ class StockLocation(models.Model): '* Other: any other location', ) - @api.depends('is_zone', 'usage', 'location_id.usage', 'zone_location_id', - 'child_ids') - def _compute_location_kind(self): + @api.depends('is_zone', 'usage', 'location_id.usage', 'child_ids', + 'location_id.is_zone') + def _compute_location_zone(self): for location in self: if location.is_zone: location.location_kind = 'zone' + location.zone_location_id = location continue + + # Get the zone from the parents + parent = location.location_id + while parent: + if parent.is_zone: + zone_location = parent + break + parent = parent.location_id + else: + zone_location = self.browse() + + location.zone_location_id = zone_location + # Internal locations whose parent is view are main stocks if ( location.usage == 'internal' @@ -57,7 +71,7 @@ class StockLocation(models.Model): # Internal locations having a zone and no children are bins if ( location.usage == 'internal' - and location.zone_location_id + and zone_location and not location.child_ids ): location.location_kind = 'bin' @@ -65,7 +79,7 @@ class StockLocation(models.Model): # Internal locations having a zone and children are areas if ( location.usage == 'internal' - and location.zone_location_id + and zone_location and location.child_ids ): location.location_kind = 'area' @@ -73,15 +87,6 @@ class StockLocation(models.Model): # All the rest are other locations location.location_kind = 'other' - @api.depends('is_zone', 'location_id.zone_location_id') - def _compute_zone_location_id(self): - for location in self: - if location.is_zone: - location.zone_location_id = location - else: - location.zone_location_id = \ - location.location_id.zone_location_id - @api.multi @api.returns('self', lambda value: value.id) def copy(self, default=None): From 5853edb512c66dad75c82bea0c1b17e979a07a7a Mon Sep 17 00:00:00 2001 From: Guewen Baconnier Date: Fri, 20 Sep 2019 15:20:42 +0200 Subject: [PATCH 09/10] Add area location relation So we can use it in group-by and filters. Note that we can have several levels of areas... only the top-level will be used. This commit fixes the computed field dependencies: _compute_location_kind should have a dependency on both it's parent's location_kind and on its child_ids to know if we are in a bin. This can't work without triggering an infinite loop. The trick used here is to split the computation of 'zone_location_id + area_location_id' in one computed method, and move the computation of the kind in a different method with triggers an the current record's zone_location + area_location_id, but not on the parent. Plus the zone_location_id and area_location_id do not depend anymore on the parent's kind, which is the reason for the infinite loop. --- stock_location_zone/models/stock_location.py | 92 ++++++++++++-------- stock_location_zone/views/stock_location.xml | 3 + 2 files changed, 57 insertions(+), 38 deletions(-) diff --git a/stock_location_zone/models/stock_location.py b/stock_location_zone/models/stock_location.py index 2e306aeed..a7628b803 100644 --- a/stock_location_zone/models/stock_location.py +++ b/stock_location_zone/models/stock_location.py @@ -16,11 +16,17 @@ class StockLocation(models.Model): zone_location_id = fields.Many2one( 'stock.location', - string='Location zone', - compute='_compute_location_zone', + string='Location Zone', + compute='_compute_zone_location_id', store=True, index=True, ) + area_location_id = fields.Many2one( + 'stock.location', + string='Location Area', + compute='_compute_zone_location_id', + store=True, + ) location_kind = fields.Selection( [ @@ -31,61 +37,71 @@ class StockLocation(models.Model): ('other', 'Other'), ], string='Location Kind', - compute='_compute_location_zone', - help='Group location according to their kinds:' - '* Zone: locations that are flagged as being zones' - '* Area: locations with children that are part of a zone' - '* Bin: locations without children that are part of a zone' - '* Stock: internal locations whose parent is a view' + compute='_compute_location_kind', + store=True, + help='Group location according to their kinds: ' + '* Zone: locations that are flagged as being zones ' + '* Area: locations with children that are part of a zone ' + '* Bin: locations without children that are part of a zone ' + '* Stock: internal locations whose parent is a view ' '* Other: any other location', ) - @api.depends('is_zone', 'usage', 'location_id.usage', 'child_ids', - 'location_id.is_zone') - def _compute_location_zone(self): + @api.depends('is_zone', 'location_id.zone_location_id', + 'location_id.area_location_id') + def _compute_zone_location_id(self): for location in self: + location.zone_location_id = self.browse() + location.area_location_id = self.browse() if location.is_zone: - location.location_kind = 'zone' location.zone_location_id = location continue - - # Get the zone from the parents parent = location.location_id - while parent: - if parent.is_zone: - zone_location = parent - break - parent = parent.location_id - else: - zone_location = self.browse() + if parent.zone_location_id: + location.zone_location_id = parent.zone_location_id + # If we have more than one level of area in a zone, + # the grouping is done by the first level + if parent.area_location_id: + location.area_location_id = parent.area_location_id + else: + location.area_location_id = location - location.zone_location_id = zone_location - - # Internal locations whose parent is view are main stocks - if ( - location.usage == 'internal' - and location.location_id.usage == 'view' - ): - location.location_kind = 'stock' + @api.depends('usage', 'location_id.usage', + 'child_ids', + 'area_location_id', + 'zone_location_id') + def _compute_location_kind(self): + for location in self: + if location.zone_location_id and not location.area_location_id: + location.location_kind = 'zone' continue - # Internal locations having a zone and no children are bins + + parent = location.location_id if ( location.usage == 'internal' - and zone_location + and parent.usage == 'view' + ): + # Internal locations whose parent is view are main stocks + location.location_kind = 'stock' + elif ( + # Internal locations having a zone and no children are bins + location.usage == 'internal' + and location.zone_location_id + and location.area_location_id and not location.child_ids ): location.location_kind = 'bin' - continue - # Internal locations having a zone and children are areas - if ( + elif ( location.usage == 'internal' - and zone_location + and location.zone_location_id + and location.area_location_id and location.child_ids ): + # Internal locations having a zone and children are areas location.location_kind = 'area' - continue - # All the rest are other locations - location.location_kind = 'other' + else: + # All the rest are other locations + location.location_kind = 'other' @api.multi @api.returns('self', lambda value: value.id) diff --git a/stock_location_zone/views/stock_location.xml b/stock_location_zone/views/stock_location.xml index a5911aa2d..e5624822b 100644 --- a/stock_location_zone/views/stock_location.xml +++ b/stock_location_zone/views/stock_location.xml @@ -12,6 +12,7 @@ + @@ -25,9 +26,11 @@ + + From 61c7f9634057c0d6da24cfcdc542dd92e6251170 Mon Sep 17 00:00:00 2001 From: Akim Juillerat Date: Tue, 12 Nov 2019 12:39:04 +0100 Subject: [PATCH 10/10] Apply suggestions from code review Co-Authored-By: Jacques-Etienne Baudoux --- stock_location_zone/readme/DESCRIPTION.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stock_location_zone/readme/DESCRIPTION.rst b/stock_location_zone/readme/DESCRIPTION.rst index 02fe9ddb4..7b3ca7af2 100644 --- a/stock_location_zone/readme/DESCRIPTION.rst +++ b/stock_location_zone/readme/DESCRIPTION.rst @@ -3,8 +3,8 @@ classification of stock locations in a warehouse. Locations are then classified by location kinds that could be: -* Zone: locations that are flagged as being zones -* Area: locations with children that are part of a zone +* Zone: locations that are flagged as being zones. Zones are subdivisions of the warehouse for splitting picking operations. A picking operator work in a zone and can pick from any location of the zone. +* Area: locations with children that are part of a zone. Areas are subdivisions of the warehouse for put-away operations. Each area has storage characteristics and strategy, e.g. area for pallets, shelf for boxes... * Bin: locations without children that are part of a zone * Stock: internal locations whose parent is a view * Other: any other location