Merge lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-hierarchical into lp:stock-logistic-warehouse
- 7.0-inventory-hierarchical
- Merge into 7.0
Status: | Rejected |
---|---|
Rejected by: | Pedro Manuel Baeza |
Proposed branch: | lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-hierarchical |
Merge into: | lp:stock-logistic-warehouse |
Prerequisite: | lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-location |
Diff against target: |
1935 lines (+1799/-0) 23 files modified
stock_inventory_hierarchical/__init__.py (+28/-0) stock_inventory_hierarchical/__openerp__.py (+46/-0) stock_inventory_hierarchical/exceptions.py (+26/-0) stock_inventory_hierarchical/hierarchical_inventory.py (+202/-0) stock_inventory_hierarchical/hierarchical_inventory_demo.xml (+17/-0) stock_inventory_hierarchical/hierarchical_inventory_view.xml (+84/-0) stock_inventory_hierarchical/i18n/fr.po (+116/-0) stock_inventory_hierarchical/i18n/stock_inventory_hierarchical.pot (+116/-0) stock_inventory_hierarchical/test/hierarchical_inventory_test.yml (+96/-0) stock_inventory_hierarchical_location/__init__.py (+22/-0) stock_inventory_hierarchical_location/__openerp__.py (+49/-0) stock_inventory_hierarchical_location/i18n/fr.po (+164/-0) stock_inventory_hierarchical_location/i18n/stock_inventory_hierarchical_location.pot (+166/-0) stock_inventory_hierarchical_location/inventory_hierarchical_location.py (+102/-0) stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml (+28/-0) stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml (+37/-0) stock_inventory_hierarchical_location/tests/__init__.py (+39/-0) stock_inventory_hierarchical_location/tests/fill_inventory_test.py (+118/-0) stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml (+56/-0) stock_inventory_hierarchical_location/wizard/__init__.py (+22/-0) stock_inventory_hierarchical_location/wizard/generate_inventory.py (+134/-0) stock_inventory_hierarchical_location/wizard/generate_inventory_view.xml (+42/-0) stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py (+89/-0) |
To merge this branch: | bzr merge lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-hierarchical |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Fayolle - camptocamp | Needs Resubmitting | ||
Lionel Sausin - Initiatives/Numérigraphe (community) | co-author | Abstain | |
Laetitia Gangloff (Acsone) | Pending | ||
Review via email: mp+223882@code.launchpad.net |
This proposal supersedes a proposal from 2014-03-12.
Commit message
Description of the change
Code cleanup and Bug fixes.
This proposal lets users compose inventories with sub-inventories in
a hierarchical tree.
This is useful in medium/large warehouses where
several teams must work in parallel to make inventories.
The module stock_inventory
stock_inventory
Thanks to Laetitia GANGLOFF from Ascone for her contribution.
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : Posted in a previous version of this proposal | # |
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : Posted in a previous version of this proposal | # |
Loïc and I are still working on this proposal. Good progress was made: we re-aligned the features with v8 in mind, and improved the code style and the views.
Acsone joined in and we're still making tests, and I hope Loïc can make a new proposal in the coming days.
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) : | # |
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : | # |
Loïc just noticed a bug when clearing locations in exhaustive and structured inventories, related to Bug #1197467.
When confirming the parent inventory, the children inventories' locations are not excluded from the exhaustivity check, and lines with qty=0 are unduly added to the parent inventory.
I'm fixing this as fast as I can.
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : | # |
Fixed partly here and partly in lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-location
- 47. By Numérigraphe
-
[IMP] add button to open subinventories and progresbar on inventory header.
- 48. By Numérigraphe
-
[IMP] French translation
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
The source code management for this project has been moved to https:/
Could you resubmit this MP on the new site?
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : | # |
I've finally resubmitted this as part of the pull request at https:/
Please reject the merge proposal here to make it clear it won't be processed on Launchpad.
Unmerged revisions
- 48. By Numérigraphe
-
[IMP] French translation
- 47. By Numérigraphe
-
[IMP] add button to open subinventories and progresbar on inventory header.
- 46. By Laetitia Gangloff (Acsone)
-
[MERGE] raise the same exception as the standard so the other parts of the code can catch it properly
- 45. By Numérigraphe
-
[MERGE] no-change commit to close acsone's MP
- 44. By Numérigraphe
-
[MERGE] take subinventories into account when validating an exhaustive structured inventory
- 43. By Numérigraphe
-
[MERGE] fixes from 7.0-inventory-
location - 42. By Loïc Bellier - Numérigraphe
-
[MERGE]: Exception fault fixed by ACSONE.
- 41. By Loïc Bellier - Numérigraphe
-
[MERGE]: Fix some bugs. Add Merge Proposal of Laetitia Gangloff from ASCONE and thanks to her.
- 40. By Loïc Bellier - Numérigraphe
-
[MERGE]: merge from dev branch
- 39. By Loïc Bellier - Numérigraphe
-
[MERGE]: From dev branch
Preview Diff
1 | === added directory 'stock_inventory_hierarchical' |
2 | === added file 'stock_inventory_hierarchical/__init__.py' |
3 | --- stock_inventory_hierarchical/__init__.py 1970-01-01 00:00:00 +0000 |
4 | +++ stock_inventory_hierarchical/__init__.py 2014-07-01 11:47:18 +0000 |
5 | @@ -0,0 +1,28 @@ |
6 | +# -*- coding: utf-8 -*- |
7 | +############################################################################## |
8 | +# |
9 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
10 | +# |
11 | +# This program is free software: you can redistribute it and/or modify |
12 | +# it under the terms of the GNU General Public License as published by |
13 | +# the Free Software Foundation, either version 3 of the License, or |
14 | +# (at your option) any later version. |
15 | +# |
16 | +# This program is distributed in the hope that it will be useful, |
17 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | +# GNU General Public License for more details. |
20 | +# |
21 | +# You should have received a copy of the GNU General Public License |
22 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
23 | +# |
24 | +############################################################################## |
25 | + |
26 | +# This package-wide list keeps the names of the field that must be |
27 | +# propagated from root inventories to their children. |
28 | +# Add field names in the Model's definition. |
29 | +PARENT_VALUES = [] |
30 | + |
31 | +import hierarchical_inventory |
32 | +# Bring the main exception into the package's scope for easier reuse |
33 | +from .exceptions import HierarchicalInventoryException |
34 | |
35 | === added file 'stock_inventory_hierarchical/__openerp__.py' |
36 | --- stock_inventory_hierarchical/__openerp__.py 1970-01-01 00:00:00 +0000 |
37 | +++ stock_inventory_hierarchical/__openerp__.py 2014-07-01 11:47:18 +0000 |
38 | @@ -0,0 +1,46 @@ |
39 | +# -*- coding: utf-8 -*- |
40 | +############################################################################## |
41 | +# |
42 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
43 | +# |
44 | +# This program is free software: you can redistribute it and/or modify |
45 | +# it under the terms of the GNU General Public License as published by |
46 | +# the Free Software Foundation, either version 3 of the License, or |
47 | +# (at your option) any later version. |
48 | +# |
49 | +# This program is distributed in the hope that it will be useful, |
50 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
51 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
52 | +# GNU General Public License for more details. |
53 | +# |
54 | +# You should have received a copy of the GNU General Public License |
55 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
56 | +# |
57 | +############################################################################## |
58 | + |
59 | +{ |
60 | + "name": "Hierarchical Physical Inventory", |
61 | + "version": "1.1", |
62 | + "depends": ["stock"], |
63 | + "author": "Numérigraphe", |
64 | + "category": "Warehouse Management", |
65 | + "description": """ |
66 | +Hierarchical structure for Physical Inventories and sub-Inventories |
67 | +=================================================================== |
68 | + |
69 | +This module adds a parent-child relationship between Physical Inventories, to |
70 | +help users manage complex inventories. |
71 | +Using several inventories, you can distribute the counting to several persons |
72 | +and still keep a clear overview of global Inventory's status. |
73 | + |
74 | +OpenERP will make sure the status of the Inventory and it's Sub-Inventories are |
75 | +consistent. |
76 | +""", |
77 | + "data": ["hierarchical_inventory_view.xml"], |
78 | + "test": ["test/hierarchical_inventory_test.yml"], |
79 | + "demo": ["hierarchical_inventory_demo.xml"], |
80 | + "images": [ |
81 | + "inventory_form.png", |
82 | + "inventory_form_actions.png", |
83 | + ], |
84 | +} |
85 | |
86 | === added file 'stock_inventory_hierarchical/exceptions.py' |
87 | --- stock_inventory_hierarchical/exceptions.py 1970-01-01 00:00:00 +0000 |
88 | +++ stock_inventory_hierarchical/exceptions.py 2014-07-01 11:47:18 +0000 |
89 | @@ -0,0 +1,26 @@ |
90 | +# -*- coding: utf-8 -*- |
91 | +############################################################################## |
92 | +# |
93 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
94 | +# |
95 | +# This program is free software: you can redistribute it and/or modify |
96 | +# it under the terms of the GNU General Public License as published by |
97 | +# the Free Software Foundation, either version 3 of the License, or |
98 | +# (at your option) any later version. |
99 | +# |
100 | +# This program is distributed in the hope that it will be useful, |
101 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
102 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
103 | +# GNU General Public License for more details. |
104 | +# |
105 | +# You should have received a copy of the GNU General Public License |
106 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
107 | +# |
108 | +############################################################################## |
109 | + |
110 | +from openerp.osv import orm |
111 | + |
112 | + |
113 | +class HierarchicalInventoryException(orm.except_orm): |
114 | + """The operation is not possible for a hierarchical inventory""" |
115 | + pass |
116 | |
117 | === added file 'stock_inventory_hierarchical/hierarchical_inventory.py' |
118 | --- stock_inventory_hierarchical/hierarchical_inventory.py 1970-01-01 00:00:00 +0000 |
119 | +++ stock_inventory_hierarchical/hierarchical_inventory.py 2014-07-01 11:47:18 +0000 |
120 | @@ -0,0 +1,202 @@ |
121 | +# -*- coding: utf-8 -*- |
122 | +############################################################################## |
123 | +# |
124 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
125 | +# |
126 | +# This program is free software: you can redistribute it and/or modify |
127 | +# it under the terms of the GNU General Public License as published by |
128 | +# the Free Software Foundation, either version 3 of the License, or |
129 | +# (at your option) any later version. |
130 | +# |
131 | +# This program is distributed in the hope that it will be useful, |
132 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
133 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
134 | +# GNU General Public License for more details. |
135 | +# |
136 | +# You should have received a copy of the GNU General Public License |
137 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
138 | +# |
139 | +############################################################################## |
140 | + |
141 | +from openerp.osv import orm, fields |
142 | +from openerp.tools.translate import _ |
143 | + |
144 | +from .exceptions import HierarchicalInventoryException |
145 | + |
146 | +# Add the date to the list of fields we must propagate to children inventories |
147 | +from . import PARENT_VALUES |
148 | +PARENT_VALUES.append('date') |
149 | + |
150 | + |
151 | +class HierarchicalInventory(orm.Model): |
152 | + _inherit = 'stock.inventory' |
153 | + |
154 | + _parent_store = True |
155 | + _parent_order = 'date, name' |
156 | + _order = 'parent_left' |
157 | + |
158 | + def name_get(self, cr, uid, ids, context=None): |
159 | + """Show the parent inventory's name in the name of the children |
160 | + |
161 | + :param dict context: the ``inventory_display`` key can be |
162 | + used to select the short version of the |
163 | + inventory name (without the direct parent), |
164 | + when set to ``'short'``. The default is |
165 | + the long version.""" |
166 | + if context is None: |
167 | + context = {} |
168 | + if context.get('inventory_display') == 'short': |
169 | + # Short name context: just do the usual stuff |
170 | + return super(HierarchicalInventory, self).name_get( |
171 | + cr, uid, ids, context=context) |
172 | + if isinstance(ids, (list, tuple)) and not len(ids): |
173 | + return [] |
174 | + if isinstance(ids, (long, int)): |
175 | + ids = [ids] |
176 | + reads = self.read(cr, uid, ids, ['name', 'parent_id'], context=context) |
177 | + res = [] |
178 | + for record in reads: |
179 | + name = record['name'] |
180 | + if record['parent_id']: |
181 | + name = record['parent_id'][1] + ' / ' + name |
182 | + res.append((record['id'], name)) |
183 | + return res |
184 | + |
185 | + def name_search(self, cr, uid, name='', args=None, operator='ilike', |
186 | + context=None, limit=100): |
187 | + """Enable search on value returned by name_get ("parent / child")""" |
188 | + if not args: |
189 | + args = [] |
190 | + if not context: |
191 | + context = {} |
192 | + if name: |
193 | + # Make sure name_search is symmetric to name_get |
194 | + name = name.split(' / ')[-1] |
195 | + ids = self.search(cr, uid, [('name', operator, name)] + args, |
196 | + limit=limit, context=context) |
197 | + else: |
198 | + ids = self.search(cr, uid, args, limit=limit, context=context) |
199 | + return self.name_get(cr, uid, ids, context=context) |
200 | + |
201 | + def _complete_name(self, cr, uid, ids, field_name, arg, context=None): |
202 | + """Function-field wrapper to get the complete name from name_get""" |
203 | + res = self.name_get(cr, uid, ids, context=context) |
204 | + return dict(res) |
205 | + |
206 | + def _progress_rate(self, cr, uid, ids, field_name, arg, context=None): |
207 | + """Rate of (sub)inventories done/total""" |
208 | + rates = {} |
209 | + for current_id in ids: |
210 | + nb = self.search( |
211 | + cr, uid, [('parent_id', 'child_of', current_id)], |
212 | + context=context, count=True) |
213 | + if not nb: |
214 | + # No inventory, consider it's 0% done |
215 | + rates[current_id] = 0 |
216 | + continue |
217 | + nb_done = self.search( |
218 | + cr, uid, [('parent_id', 'child_of', current_id), |
219 | + ('state', '=', 'done')], |
220 | + context=context, count=True) |
221 | + rates[current_id] = 100 * nb_done / nb |
222 | + return rates |
223 | + |
224 | + _columns = { |
225 | + # name_get() only changes the default name of the record, not the |
226 | + # content of the field "name" so we add another field for that |
227 | + 'complete_name': fields.function( |
228 | + _complete_name, type="char", |
229 | + string='Complete reference'), |
230 | + 'parent_id': fields.many2one( |
231 | + 'stock.inventory', 'Parent Inventory', ondelete='cascade', readonly=True, |
232 | + states={'draft': [('readonly', False)]}), |
233 | + 'inventory_ids': fields.one2many( |
234 | + 'stock.inventory', 'parent_id', 'List of Sub-inventories', |
235 | + readonly=True, states={'draft': [('readonly', False)]}), |
236 | + 'parent_left': fields.integer('Parent Left', select=1), |
237 | + 'parent_right': fields.integer('Parent Right', select=1), |
238 | + 'progress_rate': fields.function( |
239 | + _progress_rate, string='Progress', type='float'), |
240 | + } |
241 | + |
242 | + _constraints = [ |
243 | + (orm.Model._check_recursion, |
244 | + 'Error: You can not create recursive inventories.', |
245 | + ['parent_id']), |
246 | + ] |
247 | + |
248 | + def create(self, cr, uid, vals, context=None): |
249 | + """Copy selected values from parent to child""" |
250 | + if vals and vals.get('parent_id'): |
251 | + existing_fields = self.fields_get_keys(cr, uid, context=context) |
252 | + parent_values = self.read(cr, uid, [vals['parent_id']], |
253 | + PARENT_VALUES, context=context) |
254 | + vals = vals.copy() |
255 | + vals.update({field: parent_values[0][field] |
256 | + for field in PARENT_VALUES |
257 | + if field in existing_fields}) |
258 | + return super(HierarchicalInventory, self).create( |
259 | + cr, uid, vals, context=context) |
260 | + |
261 | + def write(self, cr, uid, ids, vals, context=None): |
262 | + """Copy selected values from parent to children""" |
263 | + if context is None: |
264 | + context = {} |
265 | + |
266 | + values = super(HierarchicalInventory, self).write( |
267 | + cr, uid, ids, vals, context=context) |
268 | + if not vals or context.get('norecurse', False): |
269 | + return values |
270 | + |
271 | + # filter the fields we want to propagate |
272 | + children_values = { |
273 | + field: vals[field] for field in PARENT_VALUES if field in vals |
274 | + } |
275 | + if not children_values: |
276 | + return values |
277 | + |
278 | + if not isinstance(ids, list): |
279 | + ids = [ids] |
280 | + # The context disables recursion - children are already included |
281 | + return self.write( |
282 | + cr, uid, self.search(cr, uid, [('parent_id', 'child_of', ids)]), |
283 | + children_values, context=dict(context, norecurse=True)) |
284 | + |
285 | + def action_cancel_inventory(self, cr, uid, ids, context=None): |
286 | + """Cancel inventory only if all the parents are canceled""" |
287 | + inventories = self.browse(cr, uid, ids, context=context) |
288 | + for inventory in inventories: |
289 | + while inventory.parent_id: |
290 | + inventory = inventory.parent_id |
291 | + if inventory.state != 'cancel': |
292 | + raise HierarchicalInventoryException( |
293 | + _('Warning'), |
294 | + _('One of the parent Inventories is not canceled.')) |
295 | + return super(HierarchicalInventory, |
296 | + self).action_cancel_inventory(cr, uid, ids, |
297 | + context=context) |
298 | + |
299 | + def action_confirm(self, cr, uid, ids, context=None): |
300 | + """Confirm inventory only if all the children are confirmed""" |
301 | + children_count = self.search( |
302 | + cr, uid, [('parent_id', 'child_of', ids), |
303 | + ('state', 'not in', ['confirm', 'done'])], |
304 | + context=context, count=True) |
305 | + if children_count > 1: |
306 | + raise HierarchicalInventoryException( |
307 | + _('Warning'), |
308 | + _('Some Sub-inventories are not confirmed.')) |
309 | + return super(HierarchicalInventory, self).action_confirm( |
310 | + cr, uid, ids, context=context) |
311 | + |
312 | + def action_done(self, cr, uid, ids, context=None): |
313 | + """Perform validation only if all the children states are 'done'.""" |
314 | + children_count = self.search(cr, uid, [('parent_id', 'child_of', ids), |
315 | + ('state', '!=', 'done')], |
316 | + context=context, count=True) |
317 | + if children_count > 1: |
318 | + raise HierarchicalInventoryException( |
319 | + _('Warning'), |
320 | + _('Some Sub-inventories are not validated.')) |
321 | + return super(HierarchicalInventory, self).action_done( |
322 | + cr, uid, ids, context=context) |
323 | |
324 | === added file 'stock_inventory_hierarchical/hierarchical_inventory_demo.xml' |
325 | --- stock_inventory_hierarchical/hierarchical_inventory_demo.xml 1970-01-01 00:00:00 +0000 |
326 | +++ stock_inventory_hierarchical/hierarchical_inventory_demo.xml 2014-07-01 11:47:18 +0000 |
327 | @@ -0,0 +1,17 @@ |
328 | +<?xml version="1.0" encoding="utf-8"?> |
329 | +<openerp> |
330 | + <data noupdate="0"> |
331 | + <!-- Example Inventory with Sub-Inventories. --> |
332 | + <record id="stock_inventory_parent0" model="stock.inventory"> |
333 | + <field name="name">Main Inventory</field> |
334 | + </record> |
335 | + <record id="child_1_id" model="stock.inventory"> |
336 | + <field name="name">Sub-Inventory 1</field> |
337 | + <field name="parent_id" ref="stock_inventory_parent0" /> |
338 | + </record> |
339 | + <record id="child_2_id" model="stock.inventory"> |
340 | + <field name="name">Sub-Inventory 2</field> |
341 | + <field name="parent_id" ref="stock_inventory_parent0" /> |
342 | + </record> |
343 | + </data> |
344 | +</openerp> |
345 | |
346 | === added file 'stock_inventory_hierarchical/hierarchical_inventory_view.xml' |
347 | --- stock_inventory_hierarchical/hierarchical_inventory_view.xml 1970-01-01 00:00:00 +0000 |
348 | +++ stock_inventory_hierarchical/hierarchical_inventory_view.xml 2014-07-01 11:47:18 +0000 |
349 | @@ -0,0 +1,84 @@ |
350 | +<?xml version="1.0" encoding="utf-8"?> |
351 | +<openerp> |
352 | + <data> |
353 | + <!-- Add parent_id and number of Sub-inventories to form view --> |
354 | + <record model="ir.ui.view" id="stock_inventory_hierarchical_tree_view"> |
355 | + <field name="name">hierarchical.inventory.tree</field> |
356 | + <field name="model">stock.inventory</field> |
357 | + <field name="inherit_id" ref="stock.view_inventory_tree" /> |
358 | + <field name="field_parent">inventory_ids</field> |
359 | + <field name="arch" type="xml"> |
360 | + <xpath expr="//field[@name='name']" position="replace"> |
361 | + <field name="complete_name" string="Reference"/> |
362 | + </xpath> |
363 | + <xpath expr="//field[@name='state']" position="after"> |
364 | + <field name="progress_rate" widget="progressbar" /> |
365 | + </xpath> |
366 | + </field> |
367 | + </record> |
368 | + |
369 | + <!-- Add the parent_id filter to search view --> |
370 | + <record model="ir.ui.view" id="view_inventory_subinventories_filter"> |
371 | + <field name="name">hierarchical.inventory.filter</field> |
372 | + <field name="model">stock.inventory</field> |
373 | + <field name="inherit_id" ref="stock.view_inventory_filter" /> |
374 | + <field name="arch" type="xml"> |
375 | + <xpath expr="//field[@name='name']" position="before"> |
376 | + <filter icon="terp-check" name="main_inventories" string="Main inventories" domain="[('parent_id', '=', False)]" help="Only select inventories that have no parents." /> |
377 | + <separator orientation="vertical"/> |
378 | + </xpath> |
379 | + <xpath expr="//field[@name='date']" position="after"> |
380 | + <field name="parent_id" /> |
381 | + </xpath> |
382 | + </field> |
383 | + </record> |
384 | + <!-- Show main inventories by default --> |
385 | + <record id="stock.action_inventory_form" model="ir.actions.act_window"> |
386 | + <field name="context">{'full':'1', 'search_default_main_inventories':1}</field> |
387 | + </record> |
388 | + |
389 | + <record model="ir.ui.view" id="stock_inventory_hierarchical_form_view"> |
390 | + <field name="name">hierarchical.inventory.form</field> |
391 | + <field name="model">stock.inventory</field> |
392 | + <field name="inherit_id" ref="stock.view_inventory_form" /> |
393 | + <field name="arch" type="xml"> |
394 | + <xpath expr="/form//div[@class='oe_right oe_button_box']" position="inside"> |
395 | + <button name="%(action_view_sub_inventory)d" string="View Sub-inventories" type="action" /> |
396 | + </xpath> |
397 | + <xpath expr="/form//field[@name='name']" position="after"> |
398 | + <field name="parent_id"/> |
399 | + </xpath> |
400 | + <xpath expr="/form//field[@name='date']" position="attributes"> |
401 | + <attribute name="attrs">{'readonly':[('parent_id', '!=', False)]}</attribute> |
402 | + </xpath> |
403 | + <xpath expr="/form//field[@name='date']" position="after"> |
404 | + <field name="progress_rate" widget="progressbar" /> |
405 | + </xpath> |
406 | + <xpath |
407 | + expr="//page[@string='General Information']" |
408 | + position="after"> |
409 | + <page string="Sub-inventories"> |
410 | + <field name="inventory_ids" nolabel="1" context="{'default_parent_id': active_id}"> |
411 | + <tree> |
412 | + <field name="name" /> |
413 | + <field name="state" /> |
414 | + <field name="progress_rate" widget="progressbar" /> |
415 | + </tree> |
416 | + </field> |
417 | + </page> |
418 | + </xpath> |
419 | + </field> |
420 | + </record> |
421 | + |
422 | + <!-- Open the children of the current Inventory in a distinct list |
423 | + to let users work in a normal window instead of a popup --> |
424 | + <act_window id="action_view_sub_inventory" |
425 | + name="View Sub-inventories" |
426 | + res_model="stock.inventory" |
427 | + src_model="stock.inventory" |
428 | + view_mode="tree,form" |
429 | + view_type="form" |
430 | + domain="[('parent_id', 'child_of', active_id),('id', '!=', active_id)]" |
431 | + context="{'full':1, 'search_default_main_inventories':0}"/> |
432 | + </data> |
433 | +</openerp> |
434 | |
435 | === added directory 'stock_inventory_hierarchical/i18n' |
436 | === added file 'stock_inventory_hierarchical/i18n/fr.po' |
437 | --- stock_inventory_hierarchical/i18n/fr.po 1970-01-01 00:00:00 +0000 |
438 | +++ stock_inventory_hierarchical/i18n/fr.po 2014-07-01 11:47:18 +0000 |
439 | @@ -0,0 +1,116 @@ |
440 | +# Translation of OpenERP Server. |
441 | +# This file contains the translation of the following modules: |
442 | +# * stock_inventory_hierarchical |
443 | +# |
444 | +msgid "" |
445 | +msgstr "" |
446 | +"Project-Id-Version: OpenERP Server 7.0\n" |
447 | +"Report-Msgid-Bugs-To: \n" |
448 | +"POT-Creation-Date: 2014-07-01 11:15+0000\n" |
449 | +"PO-Revision-Date: 2014-07-01 11:15+0000\n" |
450 | +"Last-Translator: <>\n" |
451 | +"Language-Team: \n" |
452 | +"MIME-Version: 1.0\n" |
453 | +"Content-Type: text/plain; charset=UTF-8\n" |
454 | +"Content-Transfer-Encoding: \n" |
455 | +"Plural-Forms: \n" |
456 | + |
457 | +#. module: stock_inventory_hierarchical |
458 | +#: field:stock.inventory,complete_name:0 |
459 | +msgid "Complete reference" |
460 | +msgstr "Réference complète" |
461 | + |
462 | +#. module: stock_inventory_hierarchical |
463 | +#: constraint:stock.inventory:0 |
464 | +msgid "Error: You can not create recursive inventories." |
465 | +msgstr "Erreur : Vous ne pouvez pas créer d'inventaire récursifs." |
466 | + |
467 | +#. module: stock_inventory_hierarchical |
468 | +#: code:_description:0 |
469 | +#: model:ir.model,name:stock_inventory_hierarchical.model_stock_inventory |
470 | +#, python-format |
471 | +msgid "Inventory" |
472 | +msgstr "Inventaire" |
473 | + |
474 | +#. module: stock_inventory_hierarchical |
475 | +#: field:stock.inventory,inventory_ids:0 |
476 | +msgid "List of Sub-inventories" |
477 | +msgstr "Liste des sous-inventaires" |
478 | + |
479 | +#. module: stock_inventory_hierarchical |
480 | +#: view:stock.inventory:0 |
481 | +msgid "Main inventories" |
482 | +msgstr "Inventaires principaux" |
483 | + |
484 | +#. module: stock_inventory_hierarchical |
485 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:174 |
486 | +#, python-format |
487 | +msgid "One of the parent Inventories is not canceled." |
488 | +msgstr "Un des inventaires pères n'est pas annulé." |
489 | + |
490 | +#. module: stock_inventory_hierarchical |
491 | +#: view:stock.inventory:0 |
492 | +msgid "Only select inventories that have no parents." |
493 | +msgstr "Sélectionne uniquement les inventaires qui n'ont pas de père." |
494 | + |
495 | +#. module: stock_inventory_hierarchical |
496 | +#: field:stock.inventory,parent_id:0 |
497 | +msgid "Parent Inventory" |
498 | +msgstr "Inventaire père" |
499 | + |
500 | +#. module: stock_inventory_hierarchical |
501 | +#: field:stock.inventory,parent_left:0 |
502 | +msgid "Parent Left" |
503 | +msgstr "Parent gauche" |
504 | + |
505 | +#. module: stock_inventory_hierarchical |
506 | +#: field:stock.inventory,parent_right:0 |
507 | +msgid "Parent Right" |
508 | +msgstr "Parent droit" |
509 | + |
510 | +#. module: stock_inventory_hierarchical |
511 | +#: field:stock.inventory,progress_rate:0 |
512 | +msgid "Progress" |
513 | +msgstr "Avancement" |
514 | + |
515 | +#. module: stock_inventory_hierarchical |
516 | +#: view:stock.inventory:0 |
517 | +msgid "Reference" |
518 | +msgstr "Référence" |
519 | + |
520 | +#. module: stock_inventory_hierarchical |
521 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:188 |
522 | +#, python-format |
523 | +msgid "Some Sub-inventories are not confirmed." |
524 | +msgstr "Certains sous-inventaires ne sont pas confirmés." |
525 | + |
526 | +#. module: stock_inventory_hierarchical |
527 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:200 |
528 | +#, python-format |
529 | +msgid "Some Sub-inventories are not validated." |
530 | +msgstr "Certains sous-inventaires ne sont pas terminés." |
531 | + |
532 | +#. module: stock_inventory_hierarchical |
533 | +#: view:stock.inventory:0 |
534 | +msgid "Sub-inventories" |
535 | +msgstr "Sous-inventaires" |
536 | + |
537 | +#. module: stock_inventory_hierarchical |
538 | +#: model:ir.actions.act_window,name:stock_inventory_hierarchical.action_view_sub_inventory |
539 | +#: view:stock.inventory:0 |
540 | +msgid "View Sub-inventories" |
541 | +msgstr "Voir les sous-inventaires" |
542 | + |
543 | +#. module: stock_inventory_hierarchical |
544 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:173 |
545 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:187 |
546 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:199 |
547 | +#, python-format |
548 | +msgid "Warning" |
549 | +msgstr "Attention" |
550 | + |
551 | +#. module: stock_inventory_hierarchical |
552 | +#: view:stock.inventory:0 |
553 | +msgid "{'readonly':[('parent_id', '!=', False)]}" |
554 | +msgstr "{'readonly':[('parent_id', '!=', False)]}" |
555 | + |
556 | |
557 | === added file 'stock_inventory_hierarchical/i18n/stock_inventory_hierarchical.pot' |
558 | --- stock_inventory_hierarchical/i18n/stock_inventory_hierarchical.pot 1970-01-01 00:00:00 +0000 |
559 | +++ stock_inventory_hierarchical/i18n/stock_inventory_hierarchical.pot 2014-07-01 11:47:18 +0000 |
560 | @@ -0,0 +1,116 @@ |
561 | +# Translation of OpenERP Server. |
562 | +# This file contains the translation of the following modules: |
563 | +# * stock_inventory_hierarchical |
564 | +# |
565 | +msgid "" |
566 | +msgstr "" |
567 | +"Project-Id-Version: OpenERP Server 7.0\n" |
568 | +"Report-Msgid-Bugs-To: \n" |
569 | +"POT-Creation-Date: 2014-07-01 11:26+0000\n" |
570 | +"PO-Revision-Date: 2014-07-01 11:26+0000\n" |
571 | +"Last-Translator: <>\n" |
572 | +"Language-Team: \n" |
573 | +"MIME-Version: 1.0\n" |
574 | +"Content-Type: text/plain; charset=UTF-8\n" |
575 | +"Content-Transfer-Encoding: \n" |
576 | +"Plural-Forms: \n" |
577 | + |
578 | +#. module: stock_inventory_hierarchical |
579 | +#: field:stock.inventory,complete_name:0 |
580 | +msgid "Complete reference" |
581 | +msgstr "" |
582 | + |
583 | +#. module: stock_inventory_hierarchical |
584 | +#: constraint:stock.inventory:0 |
585 | +msgid "Error: You can not create recursive inventories." |
586 | +msgstr "" |
587 | + |
588 | +#. module: stock_inventory_hierarchical |
589 | +#: code:_description:0 |
590 | +#: model:ir.model,name:stock_inventory_hierarchical.model_stock_inventory |
591 | +#, python-format |
592 | +msgid "Inventory" |
593 | +msgstr "" |
594 | + |
595 | +#. module: stock_inventory_hierarchical |
596 | +#: field:stock.inventory,inventory_ids:0 |
597 | +msgid "List of Sub-inventories" |
598 | +msgstr "" |
599 | + |
600 | +#. module: stock_inventory_hierarchical |
601 | +#: view:stock.inventory:0 |
602 | +msgid "Main inventories" |
603 | +msgstr "" |
604 | + |
605 | +#. module: stock_inventory_hierarchical |
606 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:174 |
607 | +#, python-format |
608 | +msgid "One of the parent Inventories is not canceled." |
609 | +msgstr "" |
610 | + |
611 | +#. module: stock_inventory_hierarchical |
612 | +#: view:stock.inventory:0 |
613 | +msgid "Only select inventories that have no parents." |
614 | +msgstr "" |
615 | + |
616 | +#. module: stock_inventory_hierarchical |
617 | +#: field:stock.inventory,parent_id:0 |
618 | +msgid "Parent Inventory" |
619 | +msgstr "" |
620 | + |
621 | +#. module: stock_inventory_hierarchical |
622 | +#: field:stock.inventory,parent_left:0 |
623 | +msgid "Parent Left" |
624 | +msgstr "" |
625 | + |
626 | +#. module: stock_inventory_hierarchical |
627 | +#: field:stock.inventory,parent_right:0 |
628 | +msgid "Parent Right" |
629 | +msgstr "" |
630 | + |
631 | +#. module: stock_inventory_hierarchical |
632 | +#: field:stock.inventory,progress_rate:0 |
633 | +msgid "Progress" |
634 | +msgstr "" |
635 | + |
636 | +#. module: stock_inventory_hierarchical |
637 | +#: view:stock.inventory:0 |
638 | +msgid "Reference" |
639 | +msgstr "" |
640 | + |
641 | +#. module: stock_inventory_hierarchical |
642 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:188 |
643 | +#, python-format |
644 | +msgid "Some Sub-inventories are not confirmed." |
645 | +msgstr "" |
646 | + |
647 | +#. module: stock_inventory_hierarchical |
648 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:200 |
649 | +#, python-format |
650 | +msgid "Some Sub-inventories are not validated." |
651 | +msgstr "" |
652 | + |
653 | +#. module: stock_inventory_hierarchical |
654 | +#: view:stock.inventory:0 |
655 | +msgid "Sub-inventories" |
656 | +msgstr "" |
657 | + |
658 | +#. module: stock_inventory_hierarchical |
659 | +#: model:ir.actions.act_window,name:stock_inventory_hierarchical.action_view_sub_inventory |
660 | +#: view:stock.inventory:0 |
661 | +msgid "View Sub-inventories" |
662 | +msgstr "" |
663 | + |
664 | +#. module: stock_inventory_hierarchical |
665 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:173 |
666 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:187 |
667 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:199 |
668 | +#, python-format |
669 | +msgid "Warning" |
670 | +msgstr "" |
671 | + |
672 | +#. module: stock_inventory_hierarchical |
673 | +#: view:stock.inventory:0 |
674 | +msgid "{'readonly':[('parent_id', '!=', False)]}" |
675 | +msgstr "" |
676 | + |
677 | |
678 | === added directory 'stock_inventory_hierarchical/images' |
679 | === added file 'stock_inventory_hierarchical/images/inventory_form.png' |
680 | Binary files stock_inventory_hierarchical/images/inventory_form.png 1970-01-01 00:00:00 +0000 and stock_inventory_hierarchical/images/inventory_form.png 2014-07-01 11:47:18 +0000 differ |
681 | === added file 'stock_inventory_hierarchical/images/inventory_form_actions.png' |
682 | Binary files stock_inventory_hierarchical/images/inventory_form_actions.png 1970-01-01 00:00:00 +0000 and stock_inventory_hierarchical/images/inventory_form_actions.png 2014-07-01 11:47:18 +0000 differ |
683 | === added directory 'stock_inventory_hierarchical/static' |
684 | === added directory 'stock_inventory_hierarchical/static/src' |
685 | === added directory 'stock_inventory_hierarchical/static/src/img' |
686 | === added file 'stock_inventory_hierarchical/static/src/img/icon.png' |
687 | Binary files stock_inventory_hierarchical/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and stock_inventory_hierarchical/static/src/img/icon.png 2014-07-01 11:47:18 +0000 differ |
688 | === added directory 'stock_inventory_hierarchical/test' |
689 | === added file 'stock_inventory_hierarchical/test/hierarchical_inventory_test.yml' |
690 | --- stock_inventory_hierarchical/test/hierarchical_inventory_test.yml 1970-01-01 00:00:00 +0000 |
691 | +++ stock_inventory_hierarchical/test/hierarchical_inventory_test.yml 2014-07-01 11:47:18 +0000 |
692 | @@ -0,0 +1,96 @@ |
693 | +- |
694 | + In this file, i check rules about hierarchical inventories. |
695 | + Children date must be the same of parent date for each state, |
696 | + the state of parent and children can change only if conditions are correct. |
697 | +- |
698 | + Check if date of children are the same as the parent's. |
699 | +- |
700 | + !python {model: stock.inventory}: | |
701 | + parent_date = self.read( |
702 | + cr, uid, [ref('stock_inventory_parent0')], ['date'])[0]['date'] |
703 | + child_1_date = self.read( |
704 | + cr, uid, [ref('child_1_id')], ['date'])[0]['date'] |
705 | + assert child_1_date == parent_date, "Date are different: %s - %s" % (parent_date, child_1_date) |
706 | + |
707 | + child_2_date = self.read( |
708 | + cr, uid, [ref('child_2_id')], ['date'])[0]['date'] |
709 | + assert child_2_date == parent_date, "Date are different: %s - %s" % (parent_date, child_2_date) |
710 | + |
711 | +- |
712 | + Check if children cannot be canceled if the parent was not canceled. |
713 | + I'll try to cancel both children inventory while parent inventory having "draft" state. |
714 | + After, i'll verify the state of each inventory. |
715 | +- |
716 | + !python {model: stock.inventory}: | |
717 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
718 | + try: |
719 | + self.action_cancel_inventory(cr, uid, [ref('child_1_id')]) |
720 | + except HierarchicalInventoryException as e: |
721 | + log("Good ! The Inventory could not be canceled: %s" % e) |
722 | + try: |
723 | + self.action_cancel_inventory(cr, uid, [ref('child_2_id')]) |
724 | + except HierarchicalInventoryException as e: |
725 | + log("Good ! The Inventory could not be canceled: %s" % e) |
726 | + child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state'] |
727 | + assert child_1_state == 'draft', "Child inventory 1 have '%s' state. It should be 'draft'" % child_1_state |
728 | + child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state'] |
729 | + assert child_2_state == 'draft', "Child inventory 2 have '%s' state. It should be 'draft'" % child_2_state |
730 | + |
731 | +- |
732 | + Check if children inventory have confirm state before confirm parent inventory. |
733 | + To check this, i'll try to confirm parent inventory when children inventory having "draft" state, |
734 | + and i'll check if state is still 'draft'. |
735 | +- |
736 | + !python {model: stock.inventory}: | |
737 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
738 | + try: |
739 | + self.action_confirm(cr, uid, [ref('stock_inventory_parent0')]) |
740 | + except HierarchicalInventoryException as e: |
741 | + log("Good, the inventory could not be confirmed: %s", e) |
742 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
743 | + assert parent_state == 'draft', "Parent inventory have '%s' state. It should be 'draft'" % parent_state |
744 | + |
745 | +- |
746 | + In order, i'll confirm the children inventories, and the parent inventory after. |
747 | +- |
748 | + !python {model: stock.inventory}: | |
749 | + self.action_confirm(cr, uid, [ref('child_1_id')]) |
750 | + child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state'] |
751 | + assert child_1_state == 'confirm', "Child inventory 1 have '%s' state. It should be 'confirm'" % child_1_state |
752 | + |
753 | + self.action_confirm(cr, uid, [ref('child_2_id')]) |
754 | + child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state'] |
755 | + assert child_2_state == 'confirm', "Child inventory 2 have '%s' state. It should be 'confirm'" % child_2_state |
756 | + |
757 | + self.action_confirm(cr, uid, [ref('stock_inventory_parent0')]) |
758 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
759 | + assert parent_state == 'confirm', "Parent inventory have '%s' state. It should be 'confirm'" % parent_state |
760 | + |
761 | +- |
762 | + Check if children inventory have done state before validate parent inventory. |
763 | + I'll try to validate parent inventory before children. |
764 | +- |
765 | + !python {model: stock.inventory}: | |
766 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
767 | + try: |
768 | + self.action_done(cr, uid, [ref('stock_inventory_parent0')]) |
769 | + except HierarchicalInventoryException as e: |
770 | + log("Good, the inventory could not be validated: %s", e) |
771 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
772 | + assert parent_state == 'confirm', "Parent inventory have '%s' state. It should be 'confirm'" % parent_state |
773 | + |
774 | +- |
775 | + Now, i'll validate all children inventory before validate the parent. |
776 | +- |
777 | + !python {model: stock.inventory}: | |
778 | + self.action_done(cr, uid, [ref('child_1_id')]) |
779 | + child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state'] |
780 | + assert child_1_state == 'done', "Child inventory 1 have '%s' state. It should be 'done'" % child_1_state |
781 | + |
782 | + self.action_done(cr, uid, [ref('child_2_id')]) |
783 | + child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state'] |
784 | + assert child_2_state == 'done', "Child inventory 2 have '%s' state. It should be 'done'" % child_2_state |
785 | + |
786 | + self.action_done(cr, uid, [ref('stock_inventory_parent0')]) |
787 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
788 | + assert parent_state == 'done', "Parent inventory have '%s' state. It should be 'done'" % parent_state |
789 | |
790 | === added directory 'stock_inventory_hierarchical_location' |
791 | === added file 'stock_inventory_hierarchical_location/__init__.py' |
792 | --- stock_inventory_hierarchical_location/__init__.py 1970-01-01 00:00:00 +0000 |
793 | +++ stock_inventory_hierarchical_location/__init__.py 2014-07-01 11:47:18 +0000 |
794 | @@ -0,0 +1,22 @@ |
795 | +# -*- coding: utf-8 -*- |
796 | +############################################################################## |
797 | +# |
798 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
799 | +# |
800 | +# This program is free software: you can redistribute it and/or modify |
801 | +# it under the terms of the GNU General Public License as published by |
802 | +# the Free Software Foundation, either version 3 of the License, or |
803 | +# (at your option) any later version. |
804 | +# |
805 | +# This program is distributed in the hope that it will be useful, |
806 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
807 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
808 | +# GNU General Public License for more details. |
809 | +# |
810 | +# You should have received a copy of the GNU General Public License |
811 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
812 | +# |
813 | +############################################################################## |
814 | + |
815 | +from . import inventory_hierarchical_location |
816 | +from . import wizard |
817 | |
818 | === added file 'stock_inventory_hierarchical_location/__openerp__.py' |
819 | --- stock_inventory_hierarchical_location/__openerp__.py 1970-01-01 00:00:00 +0000 |
820 | +++ stock_inventory_hierarchical_location/__openerp__.py 2014-07-01 11:47:18 +0000 |
821 | @@ -0,0 +1,49 @@ |
822 | +# -*- coding: utf-8 -*- |
823 | +############################################################################## |
824 | +# |
825 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
826 | +# |
827 | +# This program is free software: you can redistribute it and/or modify |
828 | +# it under the terms of the GNU General Public License as published by |
829 | +# the Free Software Foundation, either version 3 of the License, or |
830 | +# (at your option) any later version. |
831 | +# |
832 | +# This program is distributed in the hope that it will be useful, |
833 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
834 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
835 | +# GNU General Public License for more details. |
836 | +# |
837 | +# You should have received a copy of the GNU General Public License |
838 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
839 | +# |
840 | +############################################################################## |
841 | + |
842 | +{ |
843 | + "name": "Exhaustive and hierarchical Stock Inventories", |
844 | + "version": "1.1", |
845 | + "depends": ["stock_inventory_hierarchical", "stock_inventory_location"], |
846 | + "auto_install": True, |
847 | + "author": u"Numérigraphe", |
848 | + "category": "Hidden", |
849 | + "description": """ |
850 | +Make exhaustive Inventories aware of their Sub-Inventories. |
851 | +=========================================================== |
852 | + |
853 | +This module allows an inventory to contain a general Location, |
854 | +and it's sub-inventories to contain some of it's sub-Locations. |
855 | +It will prevent you from setting the Inventories and sub-Inventories |
856 | +in inconsistent status. |
857 | + |
858 | +This module will be installed automatically if the modules |
859 | +"stock_inventory_location" and "stock_inventory_hierarchical" are both |
860 | +installed. |
861 | +You must keep this module installed to ensure proper functioning. |
862 | + |
863 | + """, |
864 | + "data": [ |
865 | + "inventory_hierarchical_location_view.xml", |
866 | + "wizard/generate_inventory_view.xml", |
867 | + ], |
868 | + "test": ["tests/inventory_hierarchical_location_test.yml"], |
869 | + "demo": ["inventory_hierarchical_location_demo.xml"], |
870 | +} |
871 | |
872 | === added directory 'stock_inventory_hierarchical_location/i18n' |
873 | === added file 'stock_inventory_hierarchical_location/i18n/fr.po' |
874 | --- stock_inventory_hierarchical_location/i18n/fr.po 1970-01-01 00:00:00 +0000 |
875 | +++ stock_inventory_hierarchical_location/i18n/fr.po 2014-07-01 11:47:18 +0000 |
876 | @@ -0,0 +1,164 @@ |
877 | +# Translation of OpenERP Server. |
878 | +# This file contains the translation of the following modules: |
879 | +# * stock_inventory_hierarchical_location |
880 | +# |
881 | +msgid "" |
882 | +msgstr "" |
883 | +"Project-Id-Version: OpenERP Server 7.0\n" |
884 | +"Report-Msgid-Bugs-To: \n" |
885 | +"POT-Creation-Date: 2014-07-01 11:35+0000\n" |
886 | +"PO-Revision-Date: 2014-07-01 11:35+0000\n" |
887 | +"Last-Translator: <>\n" |
888 | +"Language-Team: \n" |
889 | +"MIME-Version: 1.0\n" |
890 | +"Content-Type: text/plain; charset=UTF-8\n" |
891 | +"Content-Transfer-Encoding: \n" |
892 | +"Plural-Forms: \n" |
893 | + |
894 | +#. module: stock_inventory_hierarchical_location |
895 | +#: view:stock.generate.inventory:0 |
896 | +msgid "Cancel" |
897 | +msgstr "Cancel" |
898 | + |
899 | +#. module: stock_inventory_hierarchical_location |
900 | +#: code:_description:0 |
901 | +#: model:ir.actions.act_window,name:stock_inventory_hierarchical_location.action_view_stock_generate_inventory |
902 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_generate_inventory |
903 | +#: model:ir.ui.menu,name:stock_inventory_hierarchical_location.menu_action_stock_generate_inventory_form |
904 | +#: view:stock.generate.inventory:0 |
905 | +#, python-format |
906 | +msgid "Generate Inventory" |
907 | +msgstr "Générer l'inventaire" |
908 | + |
909 | +#. module: stock_inventory_hierarchical_location |
910 | +#: help:stock.generate.inventory,only_view:0 |
911 | +msgid "If set, only inventory on view location can be created" |
912 | +msgstr "Si coché, seuls les inventaires des emplacements vues seront créés." |
913 | + |
914 | +#. module: stock_inventory_hierarchical_location |
915 | +#: code:_description:0 |
916 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_fill_inventory |
917 | +#, python-format |
918 | +msgid "Import Inventory" |
919 | +msgstr "Importer un inventaire" |
920 | + |
921 | +#. module: stock_inventory_hierarchical_location |
922 | +#: code:_description:0 |
923 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_inventory |
924 | +#, python-format |
925 | +msgid "Inventory" |
926 | +msgstr "Inventaire" |
927 | + |
928 | +#. module: stock_inventory_hierarchical_location |
929 | +#: code:addons/stock_inventory_hierarchical_location/wizard/generate_inventory.py:124 |
930 | +#, python-format |
931 | +msgid "Inventory generated" |
932 | +msgstr "Inventaire généré" |
933 | + |
934 | +#. module: stock_inventory_hierarchical_location |
935 | +#: field:stock.generate.inventory,prefix_inv_name:0 |
936 | +msgid "Inventory prefix" |
937 | +msgstr "Préfixe de l'inventaire" |
938 | + |
939 | +#. module: stock_inventory_hierarchical_location |
940 | +#: field:stock.generate.inventory,level:0 |
941 | +msgid "Level" |
942 | +msgstr "Profondeur" |
943 | + |
944 | +#. module: stock_inventory_hierarchical_location |
945 | +#: sql_constraint:stock.generate.inventory:0 |
946 | +msgid "Level must be positive!" |
947 | +msgstr "La profondeur doit être positive!" |
948 | + |
949 | +#. module: stock_inventory_hierarchical_location |
950 | +#: field:stock.generate.inventory,location_id:0 |
951 | +msgid "Location" |
952 | +msgstr "Emplacement" |
953 | + |
954 | +#. module: stock_inventory_hierarchical_location |
955 | +#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:78 |
956 | +#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84 |
957 | +#, python-format |
958 | +msgid "No product in this location. Please select a location in the product form." |
959 | +msgstr "" |
960 | +"Aucun article dans cet emplacement. Veuillez choisir un emplacement dans le " |
961 | +"formulaire produit." |
962 | + |
963 | +#. module: stock_inventory_hierarchical_location |
964 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:43 |
965 | +#, python-format |
966 | +msgid "One of the parent inventories is not open." |
967 | +msgstr "Un des inventaires pères n'est pas ouvert." |
968 | + |
969 | +#. module: stock_inventory_hierarchical_location |
970 | +#: field:stock.generate.inventory,only_view:0 |
971 | +msgid "Only view" |
972 | +msgstr "Vues seulement" |
973 | + |
974 | +#. module: stock_inventory_hierarchical_location |
975 | +#: help:stock.generate.inventory,prefix_inv_name:0 |
976 | +msgid "Optional prefix for all created inventory" |
977 | +msgstr "Préfixe facultatif ajouté devant les noms des inventaires créés" |
978 | + |
979 | +#. module: stock_inventory_hierarchical_location |
980 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:65 |
981 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:79 |
982 | +#, python-format |
983 | +msgid "Some Sub-inventories are not confirmed." |
984 | +msgstr "Au moins un sous-inventaire n'est pas confirmé." |
985 | + |
986 | +#. module: stock_inventory_hierarchical_location |
987 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:84 |
988 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:98 |
989 | +#, python-format |
990 | +msgid "This location is not declared on the parent inventory\n" |
991 | +"It cannot be added." |
992 | +msgstr "Cet emplacement n'est pas déclaré dans l'inventaire parent\n" |
993 | +"Vous ne pouvez pas l'ajouter." |
994 | + |
995 | +#. module: stock_inventory_hierarchical_location |
996 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:42 |
997 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:64 |
998 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:78 |
999 | +#, python-format |
1000 | +msgid "Warning" |
1001 | +msgstr "Attention" |
1002 | + |
1003 | +#. module: stock_inventory_hierarchical_location |
1004 | +#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84 |
1005 | +#, python-format |
1006 | +msgid "Warning!" |
1007 | +msgstr "Attention!" |
1008 | + |
1009 | +#. module: stock_inventory_hierarchical_location |
1010 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:83 |
1011 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:97 |
1012 | +#, python-format |
1013 | +msgid "Warning: Wrong location" |
1014 | +msgstr "Attention: emplacement incorrect" |
1015 | + |
1016 | +#. module: stock_inventory_hierarchical_location |
1017 | +#: help:stock.generate.inventory,level:0 |
1018 | +msgid "Maximum number of intermediate sub-inventories between the main inventory and the smallest sub-inventory." |
1019 | +msgstr "Nombre maximum de niveaux entre l'inventaire principal et le plus petit sous-inventaire." |
1020 | + |
1021 | +#. module: stock_inventory_hierarchical_location |
1022 | +#: view:stock.inventory:0 |
1023 | +msgid "onchange_location_id(location_id)" |
1024 | +msgstr "onchange_location_id(location_id)" |
1025 | + |
1026 | +#. module: stock_inventory_hierarchical_location |
1027 | +#: view:stock.generate.inventory:0 |
1028 | +msgid "or" |
1029 | +msgstr "ou" |
1030 | + |
1031 | +#. module: stock_inventory_hierarchical_location |
1032 | +#: view:stock.inventory:0 |
1033 | +msgid "{'default_parent_id': active_id, 'default_exhaustive': exhaustive}" |
1034 | +msgstr "{'default_parent_id': active_id, 'default_exhaustive': exhaustive}" |
1035 | + |
1036 | +#. module: stock_inventory_hierarchical_location |
1037 | +#: view:stock.inventory:0 |
1038 | +msgid "{'readonly':[('parent_id', '!=', False)]}" |
1039 | +msgstr "{'readonly':[('parent_id', '!=', False)]}" |
1040 | + |
1041 | |
1042 | === added file 'stock_inventory_hierarchical_location/i18n/stock_inventory_hierarchical_location.pot' |
1043 | --- stock_inventory_hierarchical_location/i18n/stock_inventory_hierarchical_location.pot 1970-01-01 00:00:00 +0000 |
1044 | +++ stock_inventory_hierarchical_location/i18n/stock_inventory_hierarchical_location.pot 2014-07-01 11:47:18 +0000 |
1045 | @@ -0,0 +1,166 @@ |
1046 | +# Translation of OpenERP Server. |
1047 | +# This file contains the translation of the following modules: |
1048 | +# * stock_inventory_hierarchical_location |
1049 | +# |
1050 | +msgid "" |
1051 | +msgstr "" |
1052 | +"Project-Id-Version: OpenERP Server 7.0\n" |
1053 | +"Report-Msgid-Bugs-To: \n" |
1054 | +"POT-Creation-Date: 2014-07-01 11:32+0000\n" |
1055 | +"PO-Revision-Date: 2014-07-01 11:32+0000\n" |
1056 | +"Last-Translator: <>\n" |
1057 | +"Language-Team: \n" |
1058 | +"MIME-Version: 1.0\n" |
1059 | +"Content-Type: text/plain; charset=UTF-8\n" |
1060 | +"Content-Transfer-Encoding: \n" |
1061 | +"Plural-Forms: \n" |
1062 | + |
1063 | +#. module: stock_inventory_hierarchical_location |
1064 | +#: view:stock.generate.inventory:0 |
1065 | +msgid "Cancel" |
1066 | +msgstr "" |
1067 | + |
1068 | +#. module: stock_inventory_hierarchical_location |
1069 | +#: code:_description:0 |
1070 | +#: model:ir.actions.act_window,name:stock_inventory_hierarchical_location.action_view_stock_generate_inventory |
1071 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_generate_inventory |
1072 | +#: model:ir.ui.menu,name:stock_inventory_hierarchical_location.menu_action_stock_generate_inventory_form |
1073 | +#: view:stock.generate.inventory:0 |
1074 | +#, python-format |
1075 | +msgid "Generate Inventory" |
1076 | +msgstr "" |
1077 | + |
1078 | +#. module: stock_inventory_hierarchical_location |
1079 | +#: view:stock.generate.inventory:0 |
1080 | +msgid "Generate inventory" |
1081 | +msgstr "" |
1082 | + |
1083 | +#. module: stock_inventory_hierarchical_location |
1084 | +#: help:stock.generate.inventory,only_view:0 |
1085 | +msgid "If set, only inventory on view location can be created" |
1086 | +msgstr "" |
1087 | + |
1088 | +#. module: stock_inventory_hierarchical_location |
1089 | +#: code:_description:0 |
1090 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_fill_inventory |
1091 | +#, python-format |
1092 | +msgid "Import Inventory" |
1093 | +msgstr "" |
1094 | + |
1095 | +#. module: stock_inventory_hierarchical_location |
1096 | +#: code:_description:0 |
1097 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_inventory |
1098 | +#, python-format |
1099 | +msgid "Inventory" |
1100 | +msgstr "" |
1101 | + |
1102 | +#. module: stock_inventory_hierarchical_location |
1103 | +#: code:addons/stock_inventory_hierarchical_location/wizard/generate_inventory.py:124 |
1104 | +#, python-format |
1105 | +msgid "Inventory generated" |
1106 | +msgstr "" |
1107 | + |
1108 | +#. module: stock_inventory_hierarchical_location |
1109 | +#: field:stock.generate.inventory,prefix_inv_name:0 |
1110 | +msgid "Inventory prefix" |
1111 | +msgstr "" |
1112 | + |
1113 | +#. module: stock_inventory_hierarchical_location |
1114 | +#: field:stock.generate.inventory,level:0 |
1115 | +msgid "Level" |
1116 | +msgstr "" |
1117 | + |
1118 | +#. module: stock_inventory_hierarchical_location |
1119 | +#: sql_constraint:stock.generate.inventory:0 |
1120 | +msgid "Level must be positive!" |
1121 | +msgstr "" |
1122 | + |
1123 | +#. module: stock_inventory_hierarchical_location |
1124 | +#: field:stock.generate.inventory,location_id:0 |
1125 | +msgid "Location" |
1126 | +msgstr "" |
1127 | + |
1128 | +#. module: stock_inventory_hierarchical_location |
1129 | +#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:78 |
1130 | +#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84 |
1131 | +#, python-format |
1132 | +msgid "No product in this location. Please select a location in the product form." |
1133 | +msgstr "" |
1134 | + |
1135 | +#. module: stock_inventory_hierarchical_location |
1136 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:43 |
1137 | +#, python-format |
1138 | +msgid "One of the parent inventories is not open." |
1139 | +msgstr "" |
1140 | + |
1141 | +#. module: stock_inventory_hierarchical_location |
1142 | +#: field:stock.generate.inventory,only_view:0 |
1143 | +msgid "Only view" |
1144 | +msgstr "" |
1145 | + |
1146 | +#. module: stock_inventory_hierarchical_location |
1147 | +#: help:stock.generate.inventory,prefix_inv_name:0 |
1148 | +msgid "Optional prefix for all created inventory" |
1149 | +msgstr "" |
1150 | + |
1151 | +#. module: stock_inventory_hierarchical_location |
1152 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:65 |
1153 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:79 |
1154 | +#, python-format |
1155 | +msgid "Some Sub-inventories are not confirmed." |
1156 | +msgstr "" |
1157 | + |
1158 | +#. module: stock_inventory_hierarchical_location |
1159 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:84 |
1160 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:98 |
1161 | +#, python-format |
1162 | +msgid "This location is not declared on the parent inventory\n" |
1163 | +"It cannot be added." |
1164 | +msgstr "" |
1165 | + |
1166 | +#. module: stock_inventory_hierarchical_location |
1167 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:42 |
1168 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:64 |
1169 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:78 |
1170 | +#, python-format |
1171 | +msgid "Warning" |
1172 | +msgstr "" |
1173 | + |
1174 | +#. module: stock_inventory_hierarchical_location |
1175 | +#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84 |
1176 | +#, python-format |
1177 | +msgid "Warning!" |
1178 | +msgstr "" |
1179 | + |
1180 | +#. module: stock_inventory_hierarchical_location |
1181 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:83 |
1182 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:97 |
1183 | +#, python-format |
1184 | +msgid "Warning: Wrong location" |
1185 | +msgstr "" |
1186 | + |
1187 | +#. module: stock_inventory_hierarchical_location |
1188 | +#: help:stock.generate.inventory,level:0 |
1189 | +msgid "Maximum number of intermediate sub-inventories between the main inventory and the smallest sub-inventory." |
1190 | +msgstr "" |
1191 | + |
1192 | +#. module: stock_inventory_hierarchical_location |
1193 | +#: view:stock.inventory:0 |
1194 | +msgid "onchange_location_id(location_id)" |
1195 | +msgstr "" |
1196 | + |
1197 | +#. module: stock_inventory_hierarchical_location |
1198 | +#: view:stock.generate.inventory:0 |
1199 | +msgid "or" |
1200 | +msgstr "" |
1201 | + |
1202 | +#. module: stock_inventory_hierarchical_location |
1203 | +#: view:stock.inventory:0 |
1204 | +msgid "{'default_parent_id': active_id, 'default_exhaustive': exhaustive}" |
1205 | +msgstr "" |
1206 | + |
1207 | +#. module: stock_inventory_hierarchical_location |
1208 | +#: view:stock.inventory:0 |
1209 | +msgid "{'readonly':[('parent_id', '!=', False)]}" |
1210 | +msgstr "" |
1211 | + |
1212 | |
1213 | === added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location.py' |
1214 | --- stock_inventory_hierarchical_location/inventory_hierarchical_location.py 1970-01-01 00:00:00 +0000 |
1215 | +++ stock_inventory_hierarchical_location/inventory_hierarchical_location.py 2014-07-01 11:47:18 +0000 |
1216 | @@ -0,0 +1,102 @@ |
1217 | +# -*- coding: utf-8 -*- |
1218 | +############################################################################## |
1219 | +# |
1220 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
1221 | +# |
1222 | +# This program is free software: you can redistribute it and/or modify |
1223 | +# it under the terms of the GNU General Public License as published by |
1224 | +# the Free Software Foundation, either version 3 of the License, or |
1225 | +# (at your option) any later version. |
1226 | +# |
1227 | +# This program is distributed in the hope that it will be useful, |
1228 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1229 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1230 | +# GNU General Public License for more details. |
1231 | +# |
1232 | +# You should have received a copy of the GNU General Public License |
1233 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1234 | +# |
1235 | +############################################################################## |
1236 | + |
1237 | +from openerp.osv import orm |
1238 | +from openerp.tools.translate import _ |
1239 | + |
1240 | +from stock_inventory_hierarchical import HierarchicalInventoryException |
1241 | + |
1242 | +# Add the date to the list of fields we must propagate to children inventories |
1243 | +from stock_inventory_hierarchical import PARENT_VALUES |
1244 | +PARENT_VALUES.append('exhaustive') |
1245 | + |
1246 | + |
1247 | +class HierarchicalExhInventory(orm.Model): |
1248 | + """Add hierarchical structure features to exhaustive Inventories""" |
1249 | + _inherit = 'stock.inventory' |
1250 | + |
1251 | + def action_open(self, cr, uid, ids, context=None): |
1252 | + """Open only if all the parents are Open.""" |
1253 | + for inventory in self.browse(cr, uid, ids, context=context): |
1254 | + while inventory.parent_id: |
1255 | + inventory = inventory.parent_id |
1256 | + if inventory.state != 'open': |
1257 | + raise HierarchicalInventoryException( |
1258 | + _('Warning'), |
1259 | + _('One of the parent inventories is not open.')) |
1260 | + return super(HierarchicalExhInventory, self).action_open( |
1261 | + cr, uid, ids, context=context) |
1262 | + |
1263 | + def get_missing_locations(self, cr, uid, ids, context=None): |
1264 | + """Extend the list of inventories with their children""" |
1265 | + ids = self.search( |
1266 | + cr, uid, [('parent_id', 'child_of', ids)], context=context) |
1267 | + missing_ids = super(HierarchicalExhInventory, |
1268 | + self).get_missing_locations( |
1269 | + cr, uid, ids, context=context) |
1270 | + # Find the locations already included in sub-inventories |
1271 | + inventories = self.browse(cr, uid, ids, context=context) |
1272 | + subinv_location_ids = [sub.location_id.id |
1273 | + for i in inventories |
1274 | + for sub in i.inventory_ids] |
1275 | + if not subinv_location_ids: |
1276 | + return missing_ids |
1277 | + # Extend to the children locations |
1278 | + subinv_location_ids = set(self.pool['stock.location'].search( |
1279 | + cr, uid, [ |
1280 | + ('location_id', 'child_of', subinv_location_ids), |
1281 | + ('usage', '=', 'internal')], context=context)) |
1282 | + return list(set(missing_ids) - subinv_location_ids) |
1283 | + |
1284 | + # TODO v8: probably only keep the state "done" |
1285 | + def confirm_missing_locations(self, cr, uid, ids, context=None): |
1286 | + """Do something only if children state are confirm or done.""" |
1287 | + children_count = self.search( |
1288 | + cr, uid, [('parent_id', 'child_of', ids), |
1289 | + ('id', 'not in', ids), |
1290 | + ('state', 'not in', ['confirm', 'done'])], |
1291 | + context=context, count=True) |
1292 | + if children_count > 0: |
1293 | + raise HierarchicalInventoryException( |
1294 | + _('Warning'), |
1295 | + _('Some Sub-inventories are not confirmed.')) |
1296 | + return super(HierarchicalExhInventory, |
1297 | + self).confirm_missing_locations( |
1298 | + cr, uid, ids, context=context) |
1299 | + |
1300 | + def onchange_location_id(self, cr, uid, ids, location_id, context=None): |
1301 | + """Check if location is a child of parent inventory location""" |
1302 | + loc_obj = self.pool['stock.location'] |
1303 | + for inventory in self.browse(cr, uid, ids, context=context): |
1304 | + if inventory.parent_id: |
1305 | + allowed_location_ids = loc_obj.search( |
1306 | + cr, uid, [('location_id', 'child_of', |
1307 | + inventory.parent_id.location_id.id)], |
1308 | + context=context) |
1309 | + if location_id not in allowed_location_ids: |
1310 | + return { |
1311 | + 'location_id': False, |
1312 | + 'warning': { |
1313 | + 'title': _('Warning: Wrong location'), |
1314 | + 'message': _("This location is not declared on " |
1315 | + "the parent inventory\n" |
1316 | + "It cannot be added.")} |
1317 | + } |
1318 | + return {} |
1319 | |
1320 | === added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml' |
1321 | --- stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml 1970-01-01 00:00:00 +0000 |
1322 | +++ stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml 2014-07-01 11:47:18 +0000 |
1323 | @@ -0,0 +1,28 @@ |
1324 | +<?xml version="1.0" encoding="utf-8"?> |
1325 | +<openerp> |
1326 | + <data noupdate="0"> |
1327 | + |
1328 | + <!-- Record inventories we can use in the tests. --> |
1329 | + <!-- We need them in the demo data because test data is rolled back |
1330 | + whenever an exception is raised. --> |
1331 | + |
1332 | + <!-- Record a hierarchical exhaustive inventory --> |
1333 | + <record id="parent_inventory" model="stock.inventory"> |
1334 | + <field name="name">Hierarchical exhaustive inventory</field> |
1335 | + <field name="state">draft</field> |
1336 | + <field name="date">2020-04-15 00:00:00</field> |
1337 | + <field name="exhaustive">True</field> |
1338 | + <field name="location_id" model="stock.location" ref="stock.stock_location_stock"/> |
1339 | + </record> |
1340 | + <record id="child_1_id" model="stock.inventory"> |
1341 | + <field name="name">Team A</field> |
1342 | + <field name="parent_id" ref="parent_inventory"/> |
1343 | + <field name="location_id" model="stock.location" ref="stock.stock_location_14"/> |
1344 | + </record> |
1345 | + <record id="child_2_id" model="stock.inventory"> |
1346 | + <field name="name">Team B</field> |
1347 | + <field name="parent_id" ref="parent_inventory"/> |
1348 | + <field name="location_id" model="stock.location" ref="stock.stock_location_components"/> |
1349 | + </record> |
1350 | + </data> |
1351 | +</openerp> |
1352 | |
1353 | === added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml' |
1354 | --- stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 1970-01-01 00:00:00 +0000 |
1355 | +++ stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 2014-07-01 11:47:18 +0000 |
1356 | @@ -0,0 +1,37 @@ |
1357 | +<?xml version="1.0" encoding="utf-8"?> |
1358 | +<openerp> |
1359 | + <data> |
1360 | + <record model="ir.ui.view" id="stock_inventory_hierarchical_location_form_view"> |
1361 | + <field name="name">hierarchical.inventory.location.form</field> |
1362 | + <field name="model">stock.inventory</field> |
1363 | + <field name="inherit_id" ref="stock.view_inventory_form" /> |
1364 | + <field name="arch" type="xml"> |
1365 | + |
1366 | + <xpath expr="/form//field[@name='exhaustive']" position="attributes"> |
1367 | + <attribute name="attrs">{'readonly':[('parent_id', '!=', False)]}</attribute> |
1368 | + </xpath> |
1369 | + |
1370 | + <xpath expr="/form//field[@name='location_id']" position="attributes"> |
1371 | + <attribute name="on_change">onchange_location_id(location_id)</attribute> |
1372 | + </xpath> |
1373 | + |
1374 | + </field> |
1375 | + </record> |
1376 | + |
1377 | + <record model="ir.ui.view" id="stock_ihl_exhautive_form_view"> |
1378 | + <field name="name">hierarchical.inventory.location.exhautive.form</field> |
1379 | + <field name="model">stock.inventory</field> |
1380 | + <field name="inherit_id" ref="stock_inventory_hierarchical.stock_inventory_hierarchical_form_view" /> |
1381 | + <field name="arch" type="xml"> |
1382 | + <xpath expr="//field[@name='inventory_ids']" position="attributes"> |
1383 | + <attribute name="context">{'default_parent_id': active_id, 'default_exhaustive': exhaustive}</attribute> |
1384 | + </xpath> |
1385 | + </field> |
1386 | + </record> |
1387 | + |
1388 | + <!-- Show hierarchical exhaustive inventories by default --> |
1389 | + <record id="stock.action_inventory_form" model="ir.actions.act_window"> |
1390 | + <field name="context">{'full':'1', 'search_default_exhaustive':1, 'search_default_main_inventories':1}</field> |
1391 | + </record> |
1392 | + </data> |
1393 | +</openerp> |
1394 | |
1395 | === added directory 'stock_inventory_hierarchical_location/static' |
1396 | === added directory 'stock_inventory_hierarchical_location/static/src' |
1397 | === added directory 'stock_inventory_hierarchical_location/static/src/img' |
1398 | === added file 'stock_inventory_hierarchical_location/static/src/img/icon.png' |
1399 | Binary files stock_inventory_hierarchical_location/static/src/img/icon.png 1970-01-01 00:00:00 +0000 and stock_inventory_hierarchical_location/static/src/img/icon.png 2014-07-01 11:47:18 +0000 differ |
1400 | === added directory 'stock_inventory_hierarchical_location/tests' |
1401 | === added file 'stock_inventory_hierarchical_location/tests/__init__.py' |
1402 | --- stock_inventory_hierarchical_location/tests/__init__.py 1970-01-01 00:00:00 +0000 |
1403 | +++ stock_inventory_hierarchical_location/tests/__init__.py 2014-07-01 11:47:18 +0000 |
1404 | @@ -0,0 +1,39 @@ |
1405 | +# -*- coding: utf-8 -*- |
1406 | +# |
1407 | +# |
1408 | +# Authors: Laetitia Gangloff |
1409 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1410 | +# All Rights Reserved |
1411 | +# |
1412 | +# WARNING: This program as such is intended to be used by professional |
1413 | +# programmers who take the whole responsibility of assessing all potential |
1414 | +# consequences resulting from its eventual inadequacies and bugs. |
1415 | +# End users who are looking for a ready-to-use solution with commercial |
1416 | +# guarantees and support are strongly advised to contact a Free Software |
1417 | +# Service Company. |
1418 | +# |
1419 | +# This program is free software: you can redistribute it and/or modify |
1420 | +# it under the terms of the GNU Affero General Public License as |
1421 | +# published by the Free Software Foundation, either version 3 of the |
1422 | +# License, or (at your option) any later version. |
1423 | +# |
1424 | +# This program is distributed in the hope that it will be useful, |
1425 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1426 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1427 | +# GNU Affero General Public License for more details. |
1428 | +# |
1429 | +# You should have received a copy of the GNU Affero General Public License |
1430 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1431 | +# |
1432 | +# |
1433 | + |
1434 | +import fill_inventory_test |
1435 | + |
1436 | +fast_suite = [ |
1437 | +] |
1438 | + |
1439 | +checks = [ |
1440 | + fill_inventory_test, |
1441 | +] |
1442 | + |
1443 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1444 | |
1445 | === added file 'stock_inventory_hierarchical_location/tests/fill_inventory_test.py' |
1446 | --- stock_inventory_hierarchical_location/tests/fill_inventory_test.py 1970-01-01 00:00:00 +0000 |
1447 | +++ stock_inventory_hierarchical_location/tests/fill_inventory_test.py 2014-07-01 11:47:18 +0000 |
1448 | @@ -0,0 +1,118 @@ |
1449 | +# -*- coding: utf-8 -*- |
1450 | +# |
1451 | +# |
1452 | +# Authors: Laetitia Gangloff |
1453 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1454 | +# All Rights Reserved |
1455 | +# |
1456 | +# WARNING: This program as such is intended to be used by professional |
1457 | +# programmers who take the whole responsibility of assessing all potential |
1458 | +# consequences resulting from its eventual inadequacies and bugs. |
1459 | +# End users who are looking for a ready-to-use solution with commercial |
1460 | +# guarantees and support are strongly advised to contact a Free Software |
1461 | +# Service Company. |
1462 | +# |
1463 | +# This program is free software: you can redistribute it and/or modify |
1464 | +# it under the terms of the GNU Affero General Public License as |
1465 | +# published by the Free Software Foundation, either version 3 of the |
1466 | +# License, or (at your option) any later version. |
1467 | +# |
1468 | +# This program is distributed in the hope that it will be useful, |
1469 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1470 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1471 | +# GNU Affero General Public License for more details. |
1472 | +# |
1473 | +# You should have received a copy of the GNU Affero General Public License |
1474 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1475 | +# |
1476 | +# |
1477 | + |
1478 | +import openerp.tests.common as common |
1479 | + |
1480 | +DB = common.DB |
1481 | +ADMIN_USER_ID = common.ADMIN_USER_ID |
1482 | + |
1483 | + |
1484 | +class fill_inventory_test(common.TransactionCase): |
1485 | + |
1486 | + def setUp(self): |
1487 | + super(fill_inventory_test, self).setUp() |
1488 | + |
1489 | + def test_missing_location(self): |
1490 | + """ |
1491 | + Test that when confirm a parent inventory, the child location are not in the confirmation result |
1492 | + """ |
1493 | + parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory') |
1494 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id]) |
1495 | + # confirm shelf 1 inventory |
1496 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id') |
1497 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1498 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1499 | + self.assertEqual(len(missing_location), 1, "1 missing location should be find, because the inventory is empty") |
1500 | + wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]}) |
1501 | + self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]}) |
1502 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1503 | + self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is confirmed") |
1504 | + # confirm shelf 2 inventory |
1505 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id') |
1506 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1507 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1508 | + self.assertEqual(len(missing_location), 1, "1 missing location should be fine, because the inventory is empty") |
1509 | + self.registry('stock.inventory.line').create(self.cr, self.uid, {'product_id': self.ref('product.product_product_7'), |
1510 | + 'product_uom': self.ref('product.product_uom_unit'), |
1511 | + 'company_id': self.ref('base.main_company'), |
1512 | + 'inventory_id': inventory_id, |
1513 | + 'product_qty': 18.0, |
1514 | + 'location_id': self.ref('stock.stock_location_14')}) |
1515 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1516 | + self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is filled") |
1517 | + wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]}) |
1518 | + wizard = self.registry('stock.inventory.uninventoried.locations').browse(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]}) |
1519 | + self.assertEqual(len(wizard.location_ids), 0, "The wizard should not contain any lines but contains %s." % wizard.location_ids) |
1520 | + self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]}) |
1521 | + # confirm parent inventory |
1522 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [parent_inventory_id]) |
1523 | + self.assertEqual(len(missing_location), 1, "Only 1 missing location should be find, because there is some location in child inventory") |
1524 | + |
1525 | + def test_fill_inventory(self): |
1526 | + """ |
1527 | + Test that when fill a parent inventory, the child location are not in the result |
1528 | + """ |
1529 | + parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory') |
1530 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id]) |
1531 | + # confirm shelf 1 inventory |
1532 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id') |
1533 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1534 | + wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_components'), |
1535 | + 'recursive': True, |
1536 | + 'exhaustive': True, |
1537 | + 'set_stock_zero': True}, context={'active_ids': [inventory_id]}) |
1538 | + self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]}) |
1539 | + inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)]) |
1540 | + self.assertEqual(len(inventory_line_ids), 12, "12 inventory line is fount after filling inventory") |
1541 | + # confirm shelf 2 inventory |
1542 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id') |
1543 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1544 | + wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_14'), |
1545 | + 'recursive': True, |
1546 | + 'exhaustive': True, |
1547 | + 'set_stock_zero': True}, context={'active_ids': [inventory_id]}) |
1548 | + self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]}) |
1549 | + inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)]) |
1550 | + self.assertEqual(len(inventory_line_ids), 4, "1 inventory line is fount after filling inventory") |
1551 | + # confirm parent inventory |
1552 | + wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_stock'), |
1553 | + 'recursive': True, |
1554 | + 'exhaustive': True, |
1555 | + 'set_stock_zero': True}, context={'active_ids': [parent_inventory_id]}) |
1556 | + try: |
1557 | + self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [parent_inventory_id]}) |
1558 | + except Exception, e: |
1559 | + self.assertEqual(e.value, 'No product in this location. Please select a location in the product form.', "The message should be ''No product in this location. Please select a location in the product form.''") |
1560 | + exception_happened = True |
1561 | + pass |
1562 | + self.assertTrue(exception_happened) |
1563 | + inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', parent_inventory_id)]) |
1564 | + self.assertEqual(len(inventory_line_ids), 0, "No inventory line is fount after filling inventory") |
1565 | + |
1566 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1567 | |
1568 | === added file 'stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml' |
1569 | --- stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml 1970-01-01 00:00:00 +0000 |
1570 | +++ stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml 2014-07-01 11:47:18 +0000 |
1571 | @@ -0,0 +1,56 @@ |
1572 | +- |
1573 | + Check that the exhaustive field of parent inventory has been propagated to children. |
1574 | +- |
1575 | + !python {model: stock.inventory}: | |
1576 | + exhaustive = self.read(cr, uid, [ref("child_1_id")], ['exhaustive'])[0]['exhaustive'] |
1577 | + assert exhaustive, "Exhaustive field not propagated to child inventory" |
1578 | + |
1579 | +- |
1580 | + Check that I can't open child inventory while parent inventory is open. |
1581 | +- |
1582 | + !python {model: stock.inventory}: | |
1583 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
1584 | + parent_state = self.read(cr, uid, [ref("parent_inventory")], ['state'])[0]['state'] |
1585 | + assert parent_state == 'draft', "Parent inventory in state '%s'. It should be 'draft'" % parent_state |
1586 | + try: |
1587 | + self.action_open(cr, uid, [ref("child_1_id")]) |
1588 | + except HierarchicalInventoryException as e: |
1589 | + log("Good ! The Inventory could not be opened: %s" % e) |
1590 | + child_1_state = self.read(cr, uid, [ref("child_1_id")], ['state'])[0]['state'] |
1591 | + assert child_1_state == 'draft', "Child inventory 1 have '%s' state. It should be 'draft'" % child_1_state |
1592 | + |
1593 | +- |
1594 | + I will check that the function get_missing_locations return some locations. |
1595 | +- |
1596 | + !python {model: stock.inventory}: | |
1597 | + missing_loc_ids = self.get_missing_locations(cr, uid, [ref('parent_inventory')], context=context) |
1598 | + assert len(missing_loc_ids)==3, "get_missing_locations did not return any ID." |
1599 | + |
1600 | +- |
1601 | + I will fill the inventory and check that the function get_missing_locations return no locations. |
1602 | + Adding 17” LCD Monitor. |
1603 | +- |
1604 | + !record {model: stock.inventory.line, id: lines_inventory_location_pc1}: |
1605 | + product_id: product.product_product_7 |
1606 | + product_uom: product.product_uom_unit |
1607 | + company_id: base.main_company |
1608 | + inventory_id: child_1_id |
1609 | + product_qty: 18.0 |
1610 | + location_id: stock.stock_location_14 |
1611 | + |
1612 | +- |
1613 | + Adding USB Keyboard, QWERTY. |
1614 | +- |
1615 | + !record {model: stock.inventory.line, id: lines_inventory_location_pc3}: |
1616 | + product_id: product.product_product_8 |
1617 | + product_uom: product.product_uom_unit |
1618 | + company_id: base.main_company |
1619 | + inventory_id: child_2_id |
1620 | + product_qty: 5.0 |
1621 | + location_id: stock.stock_location_components |
1622 | + |
1623 | +- |
1624 | + !python {model: stock.inventory}: | |
1625 | + |
1626 | + missing_loc_ids = self.get_missing_locations(cr, uid, [ref('parent_inventory')], context=context) |
1627 | + assert set(missing_loc_ids)==set([ref('stock.stock_location_stock')]), "get_missing_locations should return only %s but returned %s" % ([ref('stock.stock_location_stock')], missing_loc_ids) |
1628 | |
1629 | === added directory 'stock_inventory_hierarchical_location/wizard' |
1630 | === added file 'stock_inventory_hierarchical_location/wizard/__init__.py' |
1631 | --- stock_inventory_hierarchical_location/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
1632 | +++ stock_inventory_hierarchical_location/wizard/__init__.py 2014-07-01 11:47:18 +0000 |
1633 | @@ -0,0 +1,22 @@ |
1634 | +# -*- coding: utf-8 -*- |
1635 | +############################################################################## |
1636 | +# |
1637 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
1638 | +# |
1639 | +# This program is free software: you can redistribute it and/or modify |
1640 | +# it under the terms of the GNU General Public License as published by |
1641 | +# the Free Software Foundation, either version 3 of the License, or |
1642 | +# (at your option) any later version. |
1643 | +# |
1644 | +# This program is distributed in the hope that it will be useful, |
1645 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1646 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1647 | +# GNU General Public License for more details. |
1648 | +# |
1649 | +# You should have received a copy of the GNU General Public License |
1650 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1651 | +# |
1652 | +############################################################################## |
1653 | + |
1654 | +from . import stock_fill_location_inventory |
1655 | +from . import generate_inventory |
1656 | |
1657 | === added file 'stock_inventory_hierarchical_location/wizard/generate_inventory.py' |
1658 | --- stock_inventory_hierarchical_location/wizard/generate_inventory.py 1970-01-01 00:00:00 +0000 |
1659 | +++ stock_inventory_hierarchical_location/wizard/generate_inventory.py 2014-07-01 11:47:18 +0000 |
1660 | @@ -0,0 +1,134 @@ |
1661 | +# -*- coding: utf-8 -*- |
1662 | +# |
1663 | +# |
1664 | +# Authors: Laetitia Gangloff |
1665 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1666 | +# All Rights Reserved |
1667 | +# |
1668 | +# WARNING: This program as such is intended to be used by professional |
1669 | +# programmers who take the whole responsibility of assessing all potential |
1670 | +# consequences resulting from its eventual inadequacies and bugs. |
1671 | +# End users who are looking for a ready-to-use solution with commercial |
1672 | +# guarantees and support are strongly advised to contact a Free Software |
1673 | +# Service Company. |
1674 | +# |
1675 | +# This program is free software: you can redistribute it and/or modify |
1676 | +# it under the terms of the GNU Affero General Public License as |
1677 | +# published by the Free Software Foundation, either version 3 of the |
1678 | +# License, or (at your option) any later version. |
1679 | +# |
1680 | +# This program is distributed in the hope that it will be useful, |
1681 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1682 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1683 | +# GNU Affero General Public License for more details. |
1684 | +# |
1685 | +# You should have received a copy of the GNU Affero General Public License |
1686 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1687 | +# |
1688 | +# |
1689 | + |
1690 | +from openerp.osv import fields, orm |
1691 | +from openerp.tools.translate import _ |
1692 | + |
1693 | + |
1694 | +class GenerateInventoryWizard(orm.TransientModel): |
1695 | + """ This wizard generate an inventory and all related sub-inventories for the specified location and level |
1696 | + Example: location = Stock / level = 1 => 1 inventory on Stock (similar to create) |
1697 | + location = Stock / level = 2 => 1 inventory on Stock, 1 sub-inventory on Shelf1, 1 sub-inventory on Shelf2 |
1698 | + """ |
1699 | + |
1700 | + _name = "stock.generate.inventory" |
1701 | + _description = "Generate Inventory" |
1702 | + |
1703 | + _columns = { |
1704 | + 'prefix_inv_name': fields.char('Inventory prefix', help="Optional prefix for all created inventory"), |
1705 | + 'location_id': fields.many2one('stock.location', 'Location', required=True), |
1706 | + 'level': fields.integer("Level", help="Maximum number of intermediate sub-inventories between the main inventory and the smallest sub-inventory."), |
1707 | + 'only_view': fields.boolean('Only view', help="If set, only inventory on view location can be created"), |
1708 | + } |
1709 | + |
1710 | + def _default_location(self, cr, uid, ids, context=None): |
1711 | + """Default stock location |
1712 | + |
1713 | + @return: id of the stock location of the first warehouse of the |
1714 | + default company""" |
1715 | + location_id = False |
1716 | + company_id = self.pool['res.company']._company_default_get( |
1717 | + cr, uid, 'stock.warehouse', context=context) |
1718 | + warehouse_id = self.pool['stock.warehouse'].search( |
1719 | + cr, uid, [('company_id', '=', company_id)], limit=1) |
1720 | + if warehouse_id: |
1721 | + location_id = self.pool['stock.warehouse'].read( |
1722 | + cr, uid, warehouse_id[0], ['lot_stock_id'])['lot_stock_id'][0] |
1723 | + return location_id |
1724 | + |
1725 | + _defaults = { |
1726 | + 'location_id': _default_location, |
1727 | + 'level': 1, |
1728 | + 'only_view': True, |
1729 | + } |
1730 | + |
1731 | + _sql_constraints = [ |
1732 | + ('level', 'CHECK (level>0)', 'Level must be positive!'), |
1733 | + ] |
1734 | + |
1735 | + def _create_subinventory(self, cr, uid, inventory_ids, prefix_inv_name, only_view, context): |
1736 | + new_inventory_ids = [] |
1737 | + for inventory_id in inventory_ids: |
1738 | + location_id = self.pool['stock.inventory'].read(cr, uid, inventory_id, ['location_id'], context=context)['location_id'][0] |
1739 | + domain = [('location_id', '=', location_id)] |
1740 | + if only_view: |
1741 | + domain.append(('usage', '=', 'view')) |
1742 | + location_ids = self.pool['stock.location'].search(cr, uid, domain, context=context) |
1743 | + for location_id in location_ids: |
1744 | + location_name = self.pool['stock.location'].read(cr, uid, location_id, ['name'], context=context)['name'] |
1745 | + new_inventory_ids.append(self.pool['stock.inventory'].create(cr, uid, {'name': prefix_inv_name + location_name, |
1746 | + 'exhaustive': True, |
1747 | + 'location_id': location_id, |
1748 | + 'parent_id': inventory_id}, context=context)) |
1749 | + return new_inventory_ids |
1750 | + |
1751 | + def generate_inventory(self, cr, uid, ids, context=None): |
1752 | + """ Generate inventory and sub-inventories for specified location and level |
1753 | + |
1754 | + @param self: The object pointer. |
1755 | + @param cr: A database cursor |
1756 | + @param uid: ID of the user currently logged in |
1757 | + @param ids: the ID or list of IDs if we want more than one |
1758 | + @param context: A standard dictionary |
1759 | + @return: |
1760 | + """ |
1761 | + if context is None: |
1762 | + context = {} |
1763 | + |
1764 | + if ids and len(ids): |
1765 | + ids = ids[0] |
1766 | + else: |
1767 | + return {'type': 'ir.actions.act_window_close'} |
1768 | + generate_inventory = self.browse(cr, uid, ids, context=context) |
1769 | + # create first level inventory |
1770 | + prefix_inv_name = generate_inventory.prefix_inv_name or '' |
1771 | + location_id = generate_inventory.location_id.id |
1772 | + only_view = generate_inventory.only_view |
1773 | + parent_inventory_id = self.pool['stock.inventory'].create(cr, uid, {'name': prefix_inv_name + generate_inventory.location_id.name, |
1774 | + 'exhaustive': True, |
1775 | + 'location_id': location_id}, context=context) |
1776 | + |
1777 | + inventory_ids = [parent_inventory_id] |
1778 | + for i in range(1, generate_inventory.level): |
1779 | + inventory_ids = self._create_subinventory(cr, uid, inventory_ids, prefix_inv_name, only_view, context) |
1780 | + |
1781 | + mod_obj = self.pool['ir.model.data'] |
1782 | + result = mod_obj.get_object_reference(cr, uid, 'stock', 'view_inventory_form') |
1783 | + view_id = result and result[1] or False |
1784 | + return {'name': _('Inventory generated'), |
1785 | + 'view_mode': 'form', |
1786 | + 'view_type': 'form', |
1787 | + 'res_model': 'stock.inventory', |
1788 | + 'type': 'ir.actions.act_window', |
1789 | + 'view_id': view_id, |
1790 | + 'res_id': int(parent_inventory_id), |
1791 | + } |
1792 | + |
1793 | + |
1794 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1795 | |
1796 | === added file 'stock_inventory_hierarchical_location/wizard/generate_inventory_view.xml' |
1797 | --- stock_inventory_hierarchical_location/wizard/generate_inventory_view.xml 1970-01-01 00:00:00 +0000 |
1798 | +++ stock_inventory_hierarchical_location/wizard/generate_inventory_view.xml 2014-07-01 11:47:18 +0000 |
1799 | @@ -0,0 +1,42 @@ |
1800 | +<?xml version="1.0" encoding="utf-8"?> |
1801 | +<openerp> |
1802 | + <data> |
1803 | + <record id="view_stock_generate_inventory" model="ir.ui.view"> |
1804 | + <field name="name">Generate Inventory</field> |
1805 | + <field name="model">stock.generate.inventory</field> |
1806 | + <field name="arch" type="xml"> |
1807 | + <form string="Generate Inventory" version="7.0"> |
1808 | + <separator string="Generate Inventory"/> |
1809 | + <group> |
1810 | + <field name="prefix_inv_name"/> |
1811 | + <field name="location_id"/> |
1812 | + <field name="only_view"/> |
1813 | + <field name="level"/> |
1814 | + </group> |
1815 | + <footer> |
1816 | + <button name="generate_inventory" string="Generate Inventory" type="object" class="oe_highlight"/> |
1817 | + or |
1818 | + <button string="Cancel" class="oe_link" special="cancel" /> |
1819 | + </footer> |
1820 | + </form> |
1821 | + </field> |
1822 | + </record> |
1823 | + |
1824 | + <record id="action_view_stock_generate_inventory" model="ir.actions.act_window"> |
1825 | + <field name="name">Generate Inventory</field> |
1826 | + <field name="type">ir.actions.act_window</field> |
1827 | + <field name="res_model">stock.generate.inventory</field> |
1828 | + <field name="view_type">form</field> |
1829 | + <field name="view_mode">form</field> |
1830 | + <field name="view_id" ref="view_stock_generate_inventory"/> |
1831 | + <field name="target">new</field> |
1832 | + </record> |
1833 | + |
1834 | + <menuitem action="action_view_stock_generate_inventory" |
1835 | + id="menu_action_stock_generate_inventory_form" |
1836 | + parent="stock.menu_stock_inventory_control" |
1837 | + sequence="20" |
1838 | + groups="stock.group_locations"/> |
1839 | + |
1840 | + </data> |
1841 | +</openerp> |
1842 | |
1843 | === added file 'stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py' |
1844 | --- stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 1970-01-01 00:00:00 +0000 |
1845 | +++ stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 2014-07-01 11:47:18 +0000 |
1846 | @@ -0,0 +1,89 @@ |
1847 | +# -*- coding: utf-8 -*- |
1848 | +# |
1849 | +# |
1850 | +# Authors: Laetitia Gangloff |
1851 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1852 | +# All Rights Reserved |
1853 | +# |
1854 | +# WARNING: This program as such is intended to be used by professional |
1855 | +# programmers who take the whole responsibility of assessing all potential |
1856 | +# consequences resulting from its eventual inadequacies and bugs. |
1857 | +# End users who are looking for a ready-to-use solution with commercial |
1858 | +# guarantees and support are strongly advised to contact a Free Software |
1859 | +# Service Company. |
1860 | +# |
1861 | +# This program is free software: you can redistribute it and/or modify |
1862 | +# it under the terms of the GNU Affero General Public License as |
1863 | +# published by the Free Software Foundation, either version 3 of the |
1864 | +# License, or (at your option) any later version. |
1865 | +# |
1866 | +# This program is distributed in the hope that it will be useful, |
1867 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1868 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1869 | +# GNU Affero General Public License for more details. |
1870 | +# |
1871 | +# You should have received a copy of the GNU Affero General Public License |
1872 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1873 | +# |
1874 | +# |
1875 | + |
1876 | +from openerp.osv import orm, osv |
1877 | +from openerp.tools.translate import _ |
1878 | + |
1879 | + |
1880 | +class FillInventoryWizard(orm.TransientModel): |
1881 | + """If inventory as sub inventories, do not fill with sub inventories location""" |
1882 | + _inherit = 'stock.fill.inventory' |
1883 | + |
1884 | + def fill_inventory(self, cr, uid, ids, context=None): |
1885 | + """ To Import stock inventory according to products available in the location and not already in a sub inventory |
1886 | + |
1887 | + We split fill_inventory on many fill_inventory (one for each location) |
1888 | + @param self: The object pointer. |
1889 | + @param cr: A database cursor |
1890 | + @param uid: ID of the user currently logged in |
1891 | + @param ids: the ID or list of IDs if we want more than one |
1892 | + @param context: A standard dictionary |
1893 | + @return: |
1894 | + """ |
1895 | + if context is None: |
1896 | + context = {} |
1897 | + |
1898 | + if ids and len(ids): |
1899 | + ids = ids[0] |
1900 | + else: |
1901 | + return {'type': 'ir.actions.act_window_close'} |
1902 | + fill_inventory = self.browse(cr, uid, ids, context=context) |
1903 | + if fill_inventory.recursive and fill_inventory.exhaustive: |
1904 | + exclude_location_ids = [] |
1905 | + for i in self.pool['stock.inventory'].browse(cr, uid, context['active_ids']): |
1906 | + for sub_inventory in i.inventory_ids: |
1907 | + # exclude these location |
1908 | + exclude_location_ids.append(sub_inventory.location_id.id) |
1909 | + domain = [('location_id', 'child_of', [fill_inventory.location_id.id])] |
1910 | + if exclude_location_ids: |
1911 | + domain.append('!') |
1912 | + domain.append(('location_id', 'child_of', exclude_location_ids)) |
1913 | + location_ids = self.pool['stock.location'].search(cr, uid, domain, |
1914 | + order="id", |
1915 | + context=context) |
1916 | + all_in_exception = 0 |
1917 | + for location_id in location_ids: |
1918 | + try: |
1919 | + super(FillInventoryWizard, self).fill_inventory(cr, uid, |
1920 | + [self.copy(cr, uid, ids, {'location_id': location_id, |
1921 | + 'recursive': False, }, context=context)], |
1922 | + context=context) |
1923 | + except osv.except_osv, e: |
1924 | + if e.value == _('No product in this location. Please select a location in the product form.'): |
1925 | + all_in_exception = all_in_exception + 1 |
1926 | + pass |
1927 | + else: |
1928 | + raise e |
1929 | + if all_in_exception == len(location_ids): |
1930 | + raise osv.except_osv(_('Warning!'), _('No product in this location. Please select a location in the product form.')) |
1931 | + return {'type': 'ir.actions.act_window_close'} |
1932 | + else: |
1933 | + return super(FillInventoryWizard, self).fill_inventory(cr, uid, [ids], context=context) |
1934 | + |
1935 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
Loic and I are improving this proposal WRT the 7.0 coding style and latest v8 updates.