Merge lp:~acsone-openerp/stock-logistic-warehouse/7.0-inventory-hierarchical-fill-lga into lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-hierarchical

Proposed by Laetitia Gangloff (Acsone)
Status: Superseded
Proposed branch: lp:~acsone-openerp/stock-logistic-warehouse/7.0-inventory-hierarchical-fill-lga
Merge into: lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-hierarchical
Diff against target: 343 lines (+259/-14)
8 files modified
stock_inventory_hierarchical_location/__openerp__.py (+1/-1)
stock_inventory_hierarchical_location/inventory_hierarchical_location.py (+19/-9)
stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml (+1/-1)
stock_inventory_hierarchical_location/tests/__init__.py (+39/-0)
stock_inventory_hierarchical_location/tests/fill_inventory_test.py (+117/-0)
stock_inventory_hierarchical_location/wizard/__init__.py (+1/-0)
stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py (+76/-0)
stock_inventory_location/stock_inventory_location.py (+5/-3)
To merge this branch: bzr merge lp:~acsone-openerp/stock-logistic-warehouse/7.0-inventory-hierarchical-fill-lga
Reviewer Review Type Date Requested Status
Lionel Sausin - Initiatives/Numérigraphe has conflicts Needs Fixing
Review via email: mp+222965@code.launchpad.net

This proposal has been superseded by a proposal from 2014-06-12.

Description of the change

I make some change in the module stock_inventory_hierarchical_location.

The goal is to take account of sub-inventories in case of an exhaustive inventory in two case :
-confirm inventory
-fill inventory

To post a comment you must log in.
Revision history for this message
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote :

Thanks for your help.
I've just merged our own fixes of the day, will you please merge them to avoid conflicts ?

I think I understand what you're trying to do in fill_inventory and it's not exactly how we had it in v6 - which is broken right now in v7, and would require a patch on the code addons.
Your patch completely excludes the locations of sub-inventories, whereas we used to only exclude the generated inventory lines. That would allow us to "catch" the lines that could have been missing from sub-inventories, but since they're exhaustive anyway there should not be any.
So I guess your approach is correct.
I'll let Loïc decide, he's working on the problem too.

review: Needs Resubmitting (has conflicts)
Revision history for this message
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) :
review: Needs Fixing (has conflicts)

Unmerged revisions

39. By Laetitia Gangloff (Acsone)

stock_inventory_hierarchical_location: to fill inventory, check if it is an exhaustive fill to define if location should be exclude

38. By Laetitia Gangloff (Acsone)

stock_inventory_hierarchical_location: use sub-inventories to determine missing locations and to fill inventory with the fill_inventory wizard - move test in tests and add some python test for the previous issue / stock_inventory_location: correct a mysterious problem that hapenned when many inventory ids are passed

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'stock_inventory_hierarchical_location/__openerp__.py'
2--- stock_inventory_hierarchical_location/__openerp__.py 2014-06-10 14:04:38 +0000
3+++ stock_inventory_hierarchical_location/__openerp__.py 2014-06-12 15:33:45 +0000
4@@ -43,6 +43,6 @@
5 "data": [
6 "inventory_hierarchical_location_view.xml",
7 ],
8- "test": ["test/inventory_hierarchical_location_test.yml"],
9+ "test": ["tests/inventory_hierarchical_location_test.yml"],
10 "demo": ["inventory_hierarchical_location_demo.xml"],
11 }
12
13=== modified file 'stock_inventory_hierarchical_location/inventory_hierarchical_location.py'
14--- stock_inventory_hierarchical_location/inventory_hierarchical_location.py 2014-06-10 14:09:03 +0000
15+++ stock_inventory_hierarchical_location/inventory_hierarchical_location.py 2014-06-12 15:33:45 +0000
16@@ -44,6 +44,25 @@
17 return super(HierarchicalExhInventory, self).action_open(
18 cr, uid, ids, context=context)
19
20+ def _get_all_sub_inventories(self, cr, uid, ids, res, context=None):
21+ """Get the list of all sub inventories of a list inventories
22+ """
23+ for inventory in self.browse(cr, uid, ids, context=context):
24+ for i in inventory.inventory_ids:
25+ res.append(i.id)
26+ self._get_all_sub_inventories(cr, uid, [i.id], res, context)
27+ return res
28+
29+ def get_missing_locations(self, cr, uid, ids, context=None):
30+ """Compute the list of location_ids which are missing from the lines
31+
32+ Here, "missing" means the location is the inventory's location or one
33+ of it's children, and the inventory or a sub-inventory does not contain
34+ any line with this location."""
35+ # remove location of sub inventory
36+ inventory_ids = self._get_all_sub_inventories(cr, uid, ids, ids, context=context)
37+ return super(HierarchicalExhInventory, self).get_missing_locations(cr, uid, inventory_ids, context=context)
38+
39 # TODO v8: probably only keep the state "done"
40 def confirm_missing_locations(self, cr, uid, ids, context=None):
41 """Do something only if children state are confirm or done."""
42@@ -80,12 +99,3 @@
43 }
44 return {}
45
46- def _fill_location_lines(self, cr, uid, inventory_id, location_ids,
47- set_stock_zero, context=None):
48- """Add ids of children inventory into list """
49- children_inventory_ids = self.search(
50- cr, uid, [('parent_id', 'child_of', inventory_id)])
51- context['children_inventory_ids'] = children_inventory_ids
52- return super(HierarchicalExhInventory, self)._fill_location_lines(
53- cr, uid, inventory_id, location_ids, set_stock_zero,
54- context=context)
55
56=== modified file 'stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml'
57--- stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 2014-06-11 15:02:33 +0000
58+++ stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 2014-06-12 15:33:45 +0000
59@@ -5,7 +5,7 @@
60 <record model="ir.ui.view" id="stock_inventory_hierarchical_location_form_view">
61 <field name="name">hierarchical.inventory.location.form</field>
62 <field name="model">stock.inventory</field>
63- <field name="inherit_id" ref="stock.view_inventory_form" />
64+ <field name="inherit_id" ref="stock_inventory_hierarchical.stock_inventory_hierarchical_form_view" />
65 <field name="arch" type="xml">
66 <xpath expr="/form//field[@name='exhaustive']" position="attributes">
67 <attribute name="attrs">{'readonly':[('parent_id', '!=', False)]}</attribute>
68
69=== renamed directory 'stock_inventory_hierarchical_location/test' => 'stock_inventory_hierarchical_location/tests'
70=== added file 'stock_inventory_hierarchical_location/tests/__init__.py'
71--- stock_inventory_hierarchical_location/tests/__init__.py 1970-01-01 00:00:00 +0000
72+++ stock_inventory_hierarchical_location/tests/__init__.py 2014-06-12 15:33:45 +0000
73@@ -0,0 +1,39 @@
74+# -*- coding: utf-8 -*-
75+#
76+#
77+# Authors: Laetitia Gangloff
78+# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
79+# All Rights Reserved
80+#
81+# WARNING: This program as such is intended to be used by professional
82+# programmers who take the whole responsibility of assessing all potential
83+# consequences resulting from its eventual inadequacies and bugs.
84+# End users who are looking for a ready-to-use solution with commercial
85+# guarantees and support are strongly advised to contact a Free Software
86+# Service Company.
87+#
88+# This program is free software: you can redistribute it and/or modify
89+# it under the terms of the GNU Affero General Public License as
90+# published by the Free Software Foundation, either version 3 of the
91+# License, or (at your option) any later version.
92+#
93+# This program is distributed in the hope that it will be useful,
94+# but WITHOUT ANY WARRANTY; without even the implied warranty of
95+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
96+# GNU Affero General Public License for more details.
97+#
98+# You should have received a copy of the GNU Affero General Public License
99+# along with this program. If not, see <http://www.gnu.org/licenses/>.
100+#
101+#
102+
103+import fill_inventory_test
104+
105+fast_suite = [
106+]
107+
108+checks = [
109+ fill_inventory_test,
110+]
111+
112+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
113
114=== added file 'stock_inventory_hierarchical_location/tests/fill_inventory_test.py'
115--- stock_inventory_hierarchical_location/tests/fill_inventory_test.py 1970-01-01 00:00:00 +0000
116+++ stock_inventory_hierarchical_location/tests/fill_inventory_test.py 2014-06-12 15:33:45 +0000
117@@ -0,0 +1,117 @@
118+# -*- coding: utf-8 -*-
119+#
120+#
121+# Authors: Laetitia Gangloff
122+# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
123+# All Rights Reserved
124+#
125+# WARNING: This program as such is intended to be used by professional
126+# programmers who take the whole responsibility of assessing all potential
127+# consequences resulting from its eventual inadequacies and bugs.
128+# End users who are looking for a ready-to-use solution with commercial
129+# guarantees and support are strongly advised to contact a Free Software
130+# Service Company.
131+#
132+# This program is free software: you can redistribute it and/or modify
133+# it under the terms of the GNU Affero General Public License as
134+# published by the Free Software Foundation, either version 3 of the
135+# License, or (at your option) any later version.
136+#
137+# This program is distributed in the hope that it will be useful,
138+# but WITHOUT ANY WARRANTY; without even the implied warranty of
139+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
140+# GNU Affero General Public License for more details.
141+#
142+# You should have received a copy of the GNU Affero General Public License
143+# along with this program. If not, see <http://www.gnu.org/licenses/>.
144+#
145+#
146+
147+import openerp.tests.common as common
148+
149+DB = common.DB
150+ADMIN_USER_ID = common.ADMIN_USER_ID
151+
152+
153+class fill_inventory_test(common.TransactionCase):
154+
155+ def setUp(self):
156+ super(fill_inventory_test, self).setUp()
157+
158+ def test_missing_location(self):
159+ """
160+ Test that when confirm a parent inventory, the child location are not in the confirmation result
161+ """
162+ parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory_location')
163+ self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id])
164+ # confirm shelf 1 inventory
165+ inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id')
166+ self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
167+ missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
168+ self.assertEqual(len(missing_location), 1, "1 missing location should be find, because the inventory is empty")
169+ wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]})
170+ self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]})
171+ missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
172+ self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is confirmed")
173+ # confirm shelf 2 inventory
174+ inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id')
175+ self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
176+ missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
177+ self.assertEqual(len(missing_location), 1, "1 missing location should be fine, because the inventory is empty")
178+ self.registry('stock.inventory.line').create(self.cr, self.uid, {'product_id': self.ref('product.product_product_7'),
179+ 'product_uom': self.ref('product.product_uom_unit'),
180+ 'company_id': self.ref('base.main_company'),
181+ 'inventory_id': inventory_id,
182+ 'product_qty': 18.0,
183+ 'location_id': self.ref('stock.stock_location_14')})
184+ missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
185+ self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is filled")
186+ wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]})
187+ wizard = self.registry('stock.inventory.uninventoried.locations').browse(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]})
188+ self.assertEqual(len(wizard.location_ids), 0, "The wizard should not contain any lines but contains %s." % wizard.location_ids)
189+ self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]})
190+ # confirm parent inventory
191+ missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [parent_inventory_id])
192+ self.assertEqual(len(missing_location), 1, "Only 1 missing location should be find, because there is some location in child inventory")
193+
194+ def test_fill_inventory(self):
195+ """
196+ Test that when fill a parent inventory, the child location are not in the result
197+ """
198+ parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory_location')
199+ self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id])
200+ # confirm shelf 1 inventory
201+ inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id')
202+ self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
203+ wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_components'),
204+ 'recursive': True,
205+ 'exhaustive': True,
206+ 'set_stock_zero': True}, context={'active_ids': [inventory_id]})
207+ self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]})
208+ inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)])
209+ self.assertEqual(len(inventory_line_ids), 12, "12 inventory line is fount after filling inventory")
210+ # confirm shelf 2 inventory
211+ inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id')
212+ self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
213+ wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_14'),
214+ 'recursive': True,
215+ 'exhaustive': True,
216+ 'set_stock_zero': True}, context={'active_ids': [inventory_id]})
217+ self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]})
218+ inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)])
219+ self.assertEqual(len(inventory_line_ids), 4, "1 inventory line is fount after filling inventory")
220+ # confirm parent inventory
221+ wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_stock'),
222+ 'recursive': True,
223+ 'exhaustive': True,
224+ 'set_stock_zero': True}, context={'active_ids': [parent_inventory_id]})
225+ try:
226+ self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [parent_inventory_id]})
227+ except Exception:
228+ exception_happened = True
229+ pass
230+ self.assertTrue(exception_happened)
231+ inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', parent_inventory_id)])
232+ self.assertEqual(len(inventory_line_ids), 0, "No inventory line is fount after filling inventory")
233+
234+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
235
236=== modified file 'stock_inventory_hierarchical_location/wizard/__init__.py'
237--- stock_inventory_hierarchical_location/wizard/__init__.py 2014-04-02 10:04:21 +0000
238+++ stock_inventory_hierarchical_location/wizard/__init__.py 2014-06-12 15:33:45 +0000
239@@ -19,3 +19,4 @@
240 ##############################################################################
241
242 import stock_confirm_uninventoried_location
243+from . import stock_fill_location_inventory
244
245=== added file 'stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py'
246--- stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 1970-01-01 00:00:00 +0000
247+++ stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 2014-06-12 15:33:45 +0000
248@@ -0,0 +1,76 @@
249+# -*- coding: utf-8 -*-
250+#
251+#
252+# Authors: Laetitia Gangloff
253+# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
254+# All Rights Reserved
255+#
256+# WARNING: This program as such is intended to be used by professional
257+# programmers who take the whole responsibility of assessing all potential
258+# consequences resulting from its eventual inadequacies and bugs.
259+# End users who are looking for a ready-to-use solution with commercial
260+# guarantees and support are strongly advised to contact a Free Software
261+# Service Company.
262+#
263+# This program is free software: you can redistribute it and/or modify
264+# it under the terms of the GNU Affero General Public License as
265+# published by the Free Software Foundation, either version 3 of the
266+# License, or (at your option) any later version.
267+#
268+# This program is distributed in the hope that it will be useful,
269+# but WITHOUT ANY WARRANTY; without even the implied warranty of
270+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
271+# GNU Affero General Public License for more details.
272+#
273+# You should have received a copy of the GNU Affero General Public License
274+# along with this program. If not, see <http://www.gnu.org/licenses/>.
275+#
276+#
277+
278+from openerp.osv import orm
279+
280+
281+class FillInventoryWizard(orm.TransientModel):
282+ """If inventory as sub inventories, do not fill with sub inventories location"""
283+ _inherit = 'stock.fill.inventory'
284+
285+ def fill_inventory(self, cr, uid, ids, context=None):
286+ """ To Import stock inventory according to products available in the location and not already in a sub inventory
287+
288+ We split fill_inventory on many fill_inventory (one for each location)
289+ @param self: The object pointer.
290+ @param cr: A database cursor
291+ @param uid: ID of the user currently logged in
292+ @param ids: the ID or list of IDs if we want more than one
293+ @param context: A standard dictionary
294+ @return:
295+ """
296+ if context is None:
297+ context = {}
298+
299+ if ids and len(ids):
300+ ids = ids[0]
301+ else:
302+ return {'type': 'ir.actions.act_window_close'}
303+ fill_inventory = self.browse(cr, uid, ids, context=context)
304+ if fill_inventory.recursive and fill_inventory.exhaustive:
305+ exclude_location_ids = []
306+ for i in self.pool['stock.inventory'].browse(cr, uid, context['active_ids']):
307+ for sub_inventory in i.inventory_ids:
308+ # exclude these location
309+ exclude_location_ids.append(sub_inventory.location_id.id)
310+ location_ids = self.pool['stock.location'].search(cr, uid,
311+ [('location_id', 'child_of', [fill_inventory.location_id.id]),
312+ '!', ('location_id', 'child_of', exclude_location_ids)],
313+ order="id",
314+ context=context)
315+ for location_id in location_ids:
316+ super(FillInventoryWizard, self).fill_inventory(cr, uid,
317+ [self.copy(cr, uid, ids, {'location_id': location_id,
318+ 'recursive': False, }, context=context)],
319+ context=context)
320+ return {'type': 'ir.actions.act_window_close'}
321+ else:
322+ return super(FillInventoryWizard, self).fill_inventory(cr, uid, [ids], context=context)
323+
324+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
325
326=== modified file 'stock_inventory_location/stock_inventory_location.py'
327--- stock_inventory_location/stock_inventory_location.py 2014-06-11 15:01:17 +0000
328+++ stock_inventory_location/stock_inventory_location.py 2014-06-12 15:33:45 +0000
329@@ -195,9 +195,11 @@
330 ('location_id', 'child_of', inv_location_ids),
331 ('usage', '=', 'internal')], context=context))
332 # Find the locations already recorded in inventory lines
333- line_locations_ids = set([l.location_id.id
334- for l in i.inventory_line_id
335- for i in inventories])
336+ line_locations_ids = set()
337+ for i in inventories:
338+ for l in i.inventory_line_id:
339+ line_locations_ids.add(l.location_id.id)
340+
341 return list(inv_location_ids - line_locations_ids)
342
343 def confirm_missing_locations(self, cr, uid, ids, context=None):

Subscribers

People subscribed via source and target branches