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: | Superseded |
---|---|
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: |
1547 lines (+1371/-6) 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 (+78/-0) stock_inventory_hierarchical/i18n/fr.po (+112/-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 (+48/-0) stock_inventory_hierarchical_location/i18n/fr.po (+127/-0) stock_inventory_hierarchical_location/inventory_hierarchical_location.py (+88/-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 (+21/-0) stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py (+89/-0) stock_inventory_location/__openerp__.py (+3/-3) stock_inventory_location/stock_inventory_location.py (+4/-3) stock_inventory_location/tests/__init__.py (+39/-0) stock_inventory_location/tests/stock_inventory_location_test.py (+47/-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 |
---|---|---|---|
Lionel Sausin - Initiatives/Numérigraphe (community) | test pending | Needs Resubmitting | |
Stock and Logistic Core Editors | Pending | ||
Review via email: mp+210631@code.launchpad.net |
This proposal has been superseded by a proposal from 2014-06-20.
Commit message
Description of the change
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
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : | # |
- 37. By Numérigraphe
-
[MERGE] code & views cleanup and fixes
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : | # |
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.
- 38. By Loïc Bellier - Numérigraphe
-
[FIX]: Extract xpath inventory_ids from stock.inventory
_view_form - 39. By Loïc Bellier - Numérigraphe
-
[MERGE]: From dev branch
- 40. By Loïc Bellier - Numérigraphe
-
[MERGE]: merge from dev branch
- 41. By Loïc Bellier - Numérigraphe
-
[MERGE]: Fix some bugs. Add Merge Proposal of Laetitia Gangloff from ASCONE and thanks to her.
- 42. By Loïc Bellier - Numérigraphe
-
[MERGE]: Exception fault fixed by ACSONE.
- 43. By Numérigraphe
-
[MERGE] fixes from 7.0-inventory-
location - 44. By Numérigraphe
-
[MERGE] take subinventories into account when validating an exhaustive structured inventory
- 45. By Numérigraphe
-
[MERGE] no-change commit to close acsone's MP
- 46. By Laetitia Gangloff (Acsone)
-
[MERGE] raise the same exception as the standard so the other parts of the code can catch it properly
- 47. By Numérigraphe
-
[IMP] add button to open subinventories and progresbar on inventory header.
- 48. By Numérigraphe
-
[IMP] French translation
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-06-16 10:01:17 +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-06-16 10:01:17 +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-06-16 10:01:17 +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-06-16 10:01:17 +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', 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-06-16 10:01:17 +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-06-16 10:01:17 +0000 |
349 | @@ -0,0 +1,78 @@ |
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//field[@name='name']" position="after"> |
395 | + <field name="parent_id"/> |
396 | + </xpath> |
397 | + <xpath expr="/form//field[@name='date']" position="attributes"> |
398 | + <attribute name="attrs">{'readonly':[('parent_id', '!=', False)]}</attribute> |
399 | + </xpath> |
400 | + <xpath |
401 | + expr="//page[@string='General Information']" |
402 | + position="after"> |
403 | + <page string="Sub-inventories"> |
404 | + <field name="inventory_ids" nolabel="1" context="{'default_parent_id': active_id}"> |
405 | + <tree> |
406 | + <field name="name" /> |
407 | + <field name="state" /> |
408 | + <field name="progress_rate" widget="progressbar" /> |
409 | + </tree> |
410 | + </field> |
411 | + </page> |
412 | + </xpath> |
413 | + </field> |
414 | + </record> |
415 | + |
416 | + <!-- Open the children of the current Inventory in a distinct list |
417 | + to let users work in a normal window instead of a popup --> |
418 | + <act_window id="action_view_sub_inventory" |
419 | + name="View Sub-inventories" |
420 | + res_model="stock.inventory" |
421 | + src_model="stock.inventory" |
422 | + view_mode="tree,form" |
423 | + view_type="form" |
424 | + domain="[('parent_id', 'child_of', active_id),('id', '!=', active_id)]" |
425 | + context="{'full':1, 'search_default_main_inventories':0}"/> |
426 | + </data> |
427 | +</openerp> |
428 | |
429 | === added directory 'stock_inventory_hierarchical/i18n' |
430 | === added file 'stock_inventory_hierarchical/i18n/fr.po' |
431 | --- stock_inventory_hierarchical/i18n/fr.po 1970-01-01 00:00:00 +0000 |
432 | +++ stock_inventory_hierarchical/i18n/fr.po 2014-06-16 10:01:17 +0000 |
433 | @@ -0,0 +1,112 @@ |
434 | +# Translation of OpenERP Server. |
435 | +# This file contains the translation of the following modules: |
436 | +# * stock_inventory_hierarchical |
437 | +# |
438 | +msgid "" |
439 | +msgstr "" |
440 | +"Project-Id-Version: OpenERP Server 6.0.4\n" |
441 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
442 | +"POT-Creation-Date: 2013-09-25 13:43+0000\n" |
443 | +"PO-Revision-Date: 2013-09-25 13:43+0000\n" |
444 | +"Last-Translator: <>\n" |
445 | +"Language-Team: \n" |
446 | +"MIME-Version: 1.0\n" |
447 | +"Content-Type: text/plain; charset=UTF-8\n" |
448 | +"Content-Transfer-Encoding: \n" |
449 | +"Plural-Forms: \n" |
450 | + |
451 | +#. module: stock_inventory_hierarchical |
452 | +#: field:stock.inventory,complete_name:0 |
453 | +msgid "Complete reference" |
454 | +msgstr "Réference complète" |
455 | + |
456 | +#. module: stock_inventory_hierarchical |
457 | +#: field:stock.inventory,progress_rate:0 |
458 | +msgid "Done" |
459 | +msgstr "Terminé" |
460 | + |
461 | +#. module: stock_inventory_hierarchical |
462 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:108 |
463 | +#: constraint:stock.inventory:0 |
464 | +#, python-format |
465 | +msgid "Error: You can not create recursive inventories." |
466 | +msgstr "Erreur : Vous ne pouvez pas créer d'inventaire récursifs." |
467 | + |
468 | +#. module: stock_inventory_hierarchical |
469 | +#: model:ir.model,name:stock_inventory_hierarchical.model_stock_inventory |
470 | +msgid "Gestion des stocks" |
471 | +msgstr "Gestion des stocks" |
472 | + |
473 | +#. module: stock_inventory_hierarchical |
474 | +#: field:stock.inventory,inventory_ids:0 |
475 | +msgid "List of Sub-inventories" |
476 | +msgstr "Liste des sous-inventaires" |
477 | + |
478 | +#. module: stock_inventory_hierarchical |
479 | +#: view:stock.inventory:0 |
480 | +msgid "Main inventories" |
481 | +msgstr "Inventaires principaux" |
482 | + |
483 | +#. module: stock_inventory_hierarchical |
484 | +#: view:stock.inventory:0 |
485 | +msgid "Number of Sub-inventories" |
486 | +msgstr "Nombre de sous-inventaires" |
487 | + |
488 | +#. module: stock_inventory_hierarchical |
489 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:180 |
490 | +#, python-format |
491 | +msgid "One of the parent Inventories is not canceled." |
492 | +msgstr "Un des inventaires pères n'est pas annulé." |
493 | + |
494 | +#. module: stock_inventory_hierarchical |
495 | +#: constraint:stock.inventory:0 |
496 | +msgid "Other Physical inventories are being conducted using the same Locations." |
497 | +msgstr "Certains emplacements sont déjà dans un autre inventaire." |
498 | + |
499 | +#. module: stock_inventory_hierarchical |
500 | +#: field:stock.inventory,parent_id:0 |
501 | +msgid "Parent" |
502 | +msgstr "Parent" |
503 | + |
504 | +#. module: stock_inventory_hierarchical |
505 | +#: field:stock.inventory,parent_left:0 |
506 | +msgid "Parent Left" |
507 | +msgstr "Parent gauche" |
508 | + |
509 | +#. module: stock_inventory_hierarchical |
510 | +#: field:stock.inventory,parent_right:0 |
511 | +msgid "Parent Right" |
512 | +msgstr "Parent droit" |
513 | + |
514 | +#. module: stock_inventory_hierarchical |
515 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:188 |
516 | +#, python-format |
517 | +msgid "Some Sub-inventories are not confirmed." |
518 | +msgstr "Certains sous-inventaires ne sont pas confirmés." |
519 | + |
520 | +#. module: stock_inventory_hierarchical |
521 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:196 |
522 | +#, python-format |
523 | +msgid "Some Sub-inventories are not validated." |
524 | +msgstr "Certains sous-inventaires ne sont pas terminés." |
525 | + |
526 | +#. module: stock_inventory_hierarchical |
527 | +#: model:ir.actions.act_window,name:stock_inventory_hierarchical.action_view_sub_inventory |
528 | +#: view:stock.inventory:0 |
529 | +msgid "View Sub-inventories" |
530 | +msgstr "Voir les sous-inventaires" |
531 | + |
532 | +#. module: stock_inventory_hierarchical |
533 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:130 |
534 | +#, python-format |
535 | +msgid "Sub-inventory: %s" |
536 | +msgstr "Sous-inventaire : %s" |
537 | + |
538 | +#. module: stock_inventory_hierarchical |
539 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:180 |
540 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:188 |
541 | +#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:196 |
542 | +#, python-format |
543 | +msgid "Warning" |
544 | +msgstr "Attention" |
545 | + |
546 | |
547 | === added directory 'stock_inventory_hierarchical/images' |
548 | === added file 'stock_inventory_hierarchical/images/inventory_form.png' |
549 | 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-06-16 10:01:17 +0000 differ |
550 | === added file 'stock_inventory_hierarchical/images/inventory_form_actions.png' |
551 | 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-06-16 10:01:17 +0000 differ |
552 | === added directory 'stock_inventory_hierarchical/static' |
553 | === added directory 'stock_inventory_hierarchical/static/src' |
554 | === added directory 'stock_inventory_hierarchical/static/src/img' |
555 | === added file 'stock_inventory_hierarchical/static/src/img/icon.png' |
556 | 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-06-16 10:01:17 +0000 differ |
557 | === added directory 'stock_inventory_hierarchical/test' |
558 | === added file 'stock_inventory_hierarchical/test/hierarchical_inventory_test.yml' |
559 | --- stock_inventory_hierarchical/test/hierarchical_inventory_test.yml 1970-01-01 00:00:00 +0000 |
560 | +++ stock_inventory_hierarchical/test/hierarchical_inventory_test.yml 2014-06-16 10:01:17 +0000 |
561 | @@ -0,0 +1,96 @@ |
562 | +- |
563 | + In this file, i check rules about hierarchical inventories. |
564 | + Children date must be the same of parent date for each state, |
565 | + the state of parent and children can change only if conditions are correct. |
566 | +- |
567 | + Check if date of children are the same as the parent's. |
568 | +- |
569 | + !python {model: stock.inventory}: | |
570 | + parent_date = self.read( |
571 | + cr, uid, [ref('stock_inventory_parent0')], ['date'])[0]['date'] |
572 | + child_1_date = self.read( |
573 | + cr, uid, [ref('child_1_id')], ['date'])[0]['date'] |
574 | + assert child_1_date == parent_date, "Date are different: %s - %s" % (parent_date, child_1_date) |
575 | + |
576 | + child_2_date = self.read( |
577 | + cr, uid, [ref('child_2_id')], ['date'])[0]['date'] |
578 | + assert child_2_date == parent_date, "Date are different: %s - %s" % (parent_date, child_2_date) |
579 | + |
580 | +- |
581 | + Check if children cannot be canceled if the parent was not canceled. |
582 | + I'll try to cancel both children inventory while parent inventory having "draft" state. |
583 | + After, i'll verify the state of each inventory. |
584 | +- |
585 | + !python {model: stock.inventory}: | |
586 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
587 | + try: |
588 | + self.action_cancel_inventory(cr, uid, [ref('child_1_id')]) |
589 | + except HierarchicalInventoryException as e: |
590 | + log("Good ! The Inventory could not be canceled: %s" % e) |
591 | + try: |
592 | + self.action_cancel_inventory(cr, uid, [ref('child_2_id')]) |
593 | + except HierarchicalInventoryException as e: |
594 | + log("Good ! The Inventory could not be canceled: %s" % e) |
595 | + child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state'] |
596 | + assert child_1_state == 'draft', "Child inventory 1 have '%s' state. It should be 'draft'" % child_1_state |
597 | + child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state'] |
598 | + assert child_2_state == 'draft', "Child inventory 2 have '%s' state. It should be 'draft'" % child_2_state |
599 | + |
600 | +- |
601 | + Check if children inventory have confirm state before confirm parent inventory. |
602 | + To check this, i'll try to confirm parent inventory when children inventory having "draft" state, |
603 | + and i'll check if state is still 'draft'. |
604 | +- |
605 | + !python {model: stock.inventory}: | |
606 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
607 | + try: |
608 | + self.action_confirm(cr, uid, [ref('stock_inventory_parent0')]) |
609 | + except HierarchicalInventoryException as e: |
610 | + log("Good, the inventory could not be confirmed: %s", e) |
611 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
612 | + assert parent_state == 'draft', "Parent inventory have '%s' state. It should be 'draft'" % parent_state |
613 | + |
614 | +- |
615 | + In order, i'll confirm the children inventories, and the parent inventory after. |
616 | +- |
617 | + !python {model: stock.inventory}: | |
618 | + self.action_confirm(cr, uid, [ref('child_1_id')]) |
619 | + child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state'] |
620 | + assert child_1_state == 'confirm', "Child inventory 1 have '%s' state. It should be 'confirm'" % child_1_state |
621 | + |
622 | + self.action_confirm(cr, uid, [ref('child_2_id')]) |
623 | + child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state'] |
624 | + assert child_2_state == 'confirm', "Child inventory 2 have '%s' state. It should be 'confirm'" % child_2_state |
625 | + |
626 | + self.action_confirm(cr, uid, [ref('stock_inventory_parent0')]) |
627 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
628 | + assert parent_state == 'confirm', "Parent inventory have '%s' state. It should be 'confirm'" % parent_state |
629 | + |
630 | +- |
631 | + Check if children inventory have done state before validate parent inventory. |
632 | + I'll try to validate parent inventory before children. |
633 | +- |
634 | + !python {model: stock.inventory}: | |
635 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
636 | + try: |
637 | + self.action_done(cr, uid, [ref('stock_inventory_parent0')]) |
638 | + except HierarchicalInventoryException as e: |
639 | + log("Good, the inventory could not be validated: %s", e) |
640 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
641 | + assert parent_state == 'confirm', "Parent inventory have '%s' state. It should be 'confirm'" % parent_state |
642 | + |
643 | +- |
644 | + Now, i'll validate all children inventory before validate the parent. |
645 | +- |
646 | + !python {model: stock.inventory}: | |
647 | + self.action_done(cr, uid, [ref('child_1_id')]) |
648 | + child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state'] |
649 | + assert child_1_state == 'done', "Child inventory 1 have '%s' state. It should be 'done'" % child_1_state |
650 | + |
651 | + self.action_done(cr, uid, [ref('child_2_id')]) |
652 | + child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state'] |
653 | + assert child_2_state == 'done', "Child inventory 2 have '%s' state. It should be 'done'" % child_2_state |
654 | + |
655 | + self.action_done(cr, uid, [ref('stock_inventory_parent0')]) |
656 | + parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state'] |
657 | + assert parent_state == 'done', "Parent inventory have '%s' state. It should be 'done'" % parent_state |
658 | |
659 | === added directory 'stock_inventory_hierarchical_location' |
660 | === added file 'stock_inventory_hierarchical_location/__init__.py' |
661 | --- stock_inventory_hierarchical_location/__init__.py 1970-01-01 00:00:00 +0000 |
662 | +++ stock_inventory_hierarchical_location/__init__.py 2014-06-16 10:01:17 +0000 |
663 | @@ -0,0 +1,22 @@ |
664 | +# -*- coding: utf-8 -*- |
665 | +############################################################################## |
666 | +# |
667 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
668 | +# |
669 | +# This program is free software: you can redistribute it and/or modify |
670 | +# it under the terms of the GNU General Public License as published by |
671 | +# the Free Software Foundation, either version 3 of the License, or |
672 | +# (at your option) any later version. |
673 | +# |
674 | +# This program is distributed in the hope that it will be useful, |
675 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
676 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
677 | +# GNU General Public License for more details. |
678 | +# |
679 | +# You should have received a copy of the GNU General Public License |
680 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
681 | +# |
682 | +############################################################################## |
683 | + |
684 | +from . import inventory_hierarchical_location |
685 | +from . import wizard |
686 | |
687 | === added file 'stock_inventory_hierarchical_location/__openerp__.py' |
688 | --- stock_inventory_hierarchical_location/__openerp__.py 1970-01-01 00:00:00 +0000 |
689 | +++ stock_inventory_hierarchical_location/__openerp__.py 2014-06-16 10:01:17 +0000 |
690 | @@ -0,0 +1,48 @@ |
691 | +# -*- coding: utf-8 -*- |
692 | +############################################################################## |
693 | +# |
694 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
695 | +# |
696 | +# This program is free software: you can redistribute it and/or modify |
697 | +# it under the terms of the GNU General Public License as published by |
698 | +# the Free Software Foundation, either version 3 of the License, or |
699 | +# (at your option) any later version. |
700 | +# |
701 | +# This program is distributed in the hope that it will be useful, |
702 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
703 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
704 | +# GNU General Public License for more details. |
705 | +# |
706 | +# You should have received a copy of the GNU General Public License |
707 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
708 | +# |
709 | +############################################################################## |
710 | + |
711 | +{ |
712 | + "name": "Exhaustive and hierarchical Stock Inventories", |
713 | + "version": "1.1", |
714 | + "depends": ["stock_inventory_hierarchical", "stock_inventory_location"], |
715 | + "auto_install": True, |
716 | + "author": u"Numérigraphe", |
717 | + "category": "Hidden", |
718 | + "description": """ |
719 | +Make exhaustive Inventories aware of their Sub-Inventories. |
720 | +=========================================================== |
721 | + |
722 | +This module allows an inventory to contain a general Location, |
723 | +and it's sub-inventories to contain some of it's sub-Locations. |
724 | +It will prevent you from setting the Inventories and sub-Inventories |
725 | +in inconsistent status. |
726 | + |
727 | +This module will be installed automatically if the modules |
728 | +"stock_inventory_location" and "stock_inventory_hierarchical" are both |
729 | +installed. |
730 | +You must keep this module installed to ensure proper functioning. |
731 | + |
732 | + """, |
733 | + "data": [ |
734 | + "inventory_hierarchical_location_view.xml", |
735 | + ], |
736 | + "test": ["tests/inventory_hierarchical_location_test.yml"], |
737 | + "demo": ["inventory_hierarchical_location_demo.xml"], |
738 | +} |
739 | |
740 | === added directory 'stock_inventory_hierarchical_location/i18n' |
741 | === added file 'stock_inventory_hierarchical_location/i18n/fr.po' |
742 | --- stock_inventory_hierarchical_location/i18n/fr.po 1970-01-01 00:00:00 +0000 |
743 | +++ stock_inventory_hierarchical_location/i18n/fr.po 2014-06-16 10:01:17 +0000 |
744 | @@ -0,0 +1,127 @@ |
745 | +# Translation of OpenERP Server. |
746 | +# This file contains the translation of the following modules: |
747 | +# * stock_inventory_hierarchical_location |
748 | +# |
749 | +msgid "" |
750 | +msgstr "" |
751 | +"Project-Id-Version: OpenERP Server 6.0.4\n" |
752 | +"Report-Msgid-Bugs-To: support@openerp.com\n" |
753 | +"POT-Creation-Date: 2013-09-25 13:55+0000\n" |
754 | +"PO-Revision-Date: 2013-09-25 13:55+0000\n" |
755 | +"Last-Translator: <>\n" |
756 | +"Language-Team: \n" |
757 | +"MIME-Version: 1.0\n" |
758 | +"Content-Type: text/plain; charset=UTF-8\n" |
759 | +"Content-Transfer-Encoding: \n" |
760 | +"Plural-Forms: \n" |
761 | + |
762 | +#. module: stock_inventory_hierarchical_location |
763 | +#: model:ir.actions.act_window,name:stock_inventory_hierarchical_location.action_view_stock_inventory_missing_location |
764 | +msgid "Confirm missing location" |
765 | +msgstr "Confirmer les emplacements manquants" |
766 | + |
767 | +#. module: stock_inventory_hierarchical_location |
768 | +#: view:stock.inventory.missing.location:0 |
769 | +msgid "Confirm missing locations" |
770 | +msgstr "Confirmer les emplacements manquants" |
771 | + |
772 | +#. module: stock_inventory_hierarchical_location |
773 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_inventory_uninventoried_locations |
774 | +msgid "Confirm the uninventoried Locations." |
775 | +msgstr "Confirmer les emplacements non inventoriés." |
776 | + |
777 | +#. module: stock_inventory_hierarchical_location |
778 | +#: view:stock.inventory.missing.location:0 |
779 | +msgid "Do you want to continue ?" |
780 | +msgstr "Voulez-vous continuer ?" |
781 | + |
782 | +#. module: stock_inventory_hierarchical_location |
783 | +#: constraint:stock.inventory:0 |
784 | +msgid "Error! You can not create recursive inventories." |
785 | +msgstr "Erreur! Vous ne pouvez pas créer un inventaire récursif." |
786 | + |
787 | +#. module: stock_inventory_hierarchical_location |
788 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_inventory |
789 | +msgid "Gestion des stocks" |
790 | +msgstr "Gestion des stocks" |
791 | + |
792 | +#. module: stock_inventory_hierarchical_location |
793 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:70 |
794 | +#, python-format |
795 | +msgid "Location missing for inventory \"%s\"." |
796 | +msgstr "Emplacement manquants dans l'inventaire \"%s\"." |
797 | + |
798 | +#. module: stock_inventory_hierarchical_location |
799 | +#: view:stock.inventory:0 |
800 | +msgid "Locations" |
801 | +msgstr "Emplacements" |
802 | + |
803 | +#. module: stock_inventory_hierarchical_location |
804 | +#: field:stock.inventory.missing.location,location_ids:0 |
805 | +msgid "Missing location" |
806 | +msgstr "Emplacements manquants" |
807 | + |
808 | +#. module: stock_inventory_hierarchical_location |
809 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:41 |
810 | +#, python-format |
811 | +msgid "One of the parent inventories is not open." |
812 | +msgstr "Un des inventaire parent n'est pas ouvert." |
813 | + |
814 | +#. module: stock_inventory_hierarchical_location |
815 | +#: view:stock.inventory:0 |
816 | +msgid "Open Inventory" |
817 | +msgstr "Ouvrir l'inventaire" |
818 | + |
819 | +#. module: stock_inventory_hierarchical_location |
820 | +#: constraint:stock.inventory:0 |
821 | +msgid "Other Physical inventories are being conducted using the same Locations." |
822 | +msgstr "Erreur: certains emplacements sont déjà dans un autre inventaire." |
823 | + |
824 | +#. module: stock_inventory_hierarchical_location |
825 | +#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_inventory_missing_location |
826 | +msgid "Search on inventory tree for missing declared locations." |
827 | +msgstr "Recherche dans les inventaires les emplacements absents." |
828 | + |
829 | +#. module: stock_inventory_hierarchical_location |
830 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:122 |
831 | +#, python-format |
832 | +msgid "Some Sub-inventories are not confirmed." |
833 | +msgstr "Au moins un sous-inventaire n'est pas confirmé." |
834 | + |
835 | +#. module: stock_inventory_hierarchical_location |
836 | +#: view:stock.inventory.missing.location:0 |
837 | +msgid "This is the list of missing locations." |
838 | +msgstr "Voici la liste des emplacements manquants." |
839 | + |
840 | +#. module: stock_inventory_hierarchical_location |
841 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:58 |
842 | +#, python-format |
843 | +msgid "This location is not declared on the parent inventory\n" |
844 | +"It cannot be added." |
845 | +msgstr "Cet emplacement n'est pas déclaré dans l'inventaire parent\n" |
846 | +"Vous ne pouvez pas l'ajouter." |
847 | + |
848 | +#. module: stock_inventory_hierarchical_location |
849 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:41 |
850 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:70 |
851 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:122 |
852 | +#, python-format |
853 | +msgid "Warning !" |
854 | +msgstr "Attention !" |
855 | + |
856 | +#. module: stock_inventory_hierarchical_location |
857 | +#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:57 |
858 | +#, python-format |
859 | +msgid "Warning: Wrong location" |
860 | +msgstr "Attention: mauvais emplacement" |
861 | + |
862 | +#. module: stock_inventory_hierarchical_location |
863 | +#: view:stock.inventory.missing.location:0 |
864 | +msgid "_Cancel" |
865 | +msgstr "_Annuler" |
866 | + |
867 | +#. module: stock_inventory_hierarchical_location |
868 | +#: view:stock.inventory.missing.location:0 |
869 | +msgid "_Confirm missing locations" |
870 | +msgstr "_Confirmer les emplacements manquants" |
871 | + |
872 | |
873 | === added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location.py' |
874 | --- stock_inventory_hierarchical_location/inventory_hierarchical_location.py 1970-01-01 00:00:00 +0000 |
875 | +++ stock_inventory_hierarchical_location/inventory_hierarchical_location.py 2014-06-16 10:01:17 +0000 |
876 | @@ -0,0 +1,88 @@ |
877 | +# -*- coding: utf-8 -*- |
878 | +############################################################################## |
879 | +# |
880 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
881 | +# |
882 | +# This program is free software: you can redistribute it and/or modify |
883 | +# it under the terms of the GNU General Public License as published by |
884 | +# the Free Software Foundation, either version 3 of the License, or |
885 | +# (at your option) any later version. |
886 | +# |
887 | +# This program is distributed in the hope that it will be useful, |
888 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
889 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
890 | +# GNU General Public License for more details. |
891 | +# |
892 | +# You should have received a copy of the GNU General Public License |
893 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
894 | +# |
895 | +############################################################################## |
896 | + |
897 | +from openerp.osv import orm |
898 | +from openerp.tools.translate import _ |
899 | + |
900 | +from stock_inventory_hierarchical import HierarchicalInventoryException |
901 | + |
902 | +# Add the date to the list of fields we must propagate to children inventories |
903 | +from stock_inventory_hierarchical import PARENT_VALUES |
904 | +PARENT_VALUES.append('exhaustive') |
905 | + |
906 | + |
907 | +class HierarchicalExhInventory(orm.Model): |
908 | + """Add hierarchical structure features to exhaustive Inventories""" |
909 | + _inherit = 'stock.inventory' |
910 | + |
911 | + def action_open(self, cr, uid, ids, context=None): |
912 | + """Open only if all the parents are Open.""" |
913 | + for inventory in self.browse(cr, uid, ids, context=context): |
914 | + while inventory.parent_id: |
915 | + inventory = inventory.parent_id |
916 | + if inventory.state != 'open': |
917 | + raise HierarchicalInventoryException( |
918 | + _('Warning'), |
919 | + _('One of the parent inventories is not open.')) |
920 | + return super(HierarchicalExhInventory, self).action_open( |
921 | + cr, uid, ids, context=context) |
922 | + |
923 | + def get_missing_locations(self, cr, uid, ids, context=None): |
924 | + """Extend the list of inventories with their children""" |
925 | + ids = self.search( |
926 | + cr, uid, [('parent_id', 'child_of', ids)], context=context) |
927 | + return super(HierarchicalExhInventory, self).get_missing_locations( |
928 | + cr, uid, ids, context=context) |
929 | + |
930 | + # TODO v8: probably only keep the state "done" |
931 | + def confirm_missing_locations(self, cr, uid, ids, context=None): |
932 | + """Do something only if children state are confirm or done.""" |
933 | + children_count = self.search( |
934 | + cr, uid, [('parent_id', 'child_of', ids), |
935 | + ('id', 'not in', ids), |
936 | + ('state', 'not in', ['confirm', 'done'])], |
937 | + context=context, count=True) |
938 | + if children_count > 0: |
939 | + raise HierarchicalInventoryException( |
940 | + _('Warning'), |
941 | + _('Some Sub-inventories are not confirmed.')) |
942 | + return super(HierarchicalExhInventory, |
943 | + self).confirm_missing_locations( |
944 | + cr, uid, ids, context=context) |
945 | + |
946 | + def onchange_location_id(self, cr, uid, ids, location_id, context=None): |
947 | + """Check if location is a child of parent inventory location""" |
948 | + loc_obj = self.pool['stock.location'] |
949 | + for inventory in self.browse(cr, uid, ids, context=context): |
950 | + if inventory.parent_id: |
951 | + allowed_location_ids = loc_obj.search( |
952 | + cr, uid, [('location_id', 'child_of', |
953 | + inventory.parent_id.location_id.id)], |
954 | + context=context) |
955 | + if location_id not in allowed_location_ids: |
956 | + return { |
957 | + 'location_id': False, |
958 | + 'warning': { |
959 | + 'title': _('Warning: Wrong location'), |
960 | + 'message': _("This location is not declared on " |
961 | + "the parent inventory\n" |
962 | + "It cannot be added.")} |
963 | + } |
964 | + return {} |
965 | |
966 | === added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml' |
967 | --- stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml 1970-01-01 00:00:00 +0000 |
968 | +++ stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml 2014-06-16 10:01:17 +0000 |
969 | @@ -0,0 +1,28 @@ |
970 | +<?xml version="1.0" encoding="utf-8"?> |
971 | +<openerp> |
972 | + <data noupdate="0"> |
973 | + |
974 | + <!-- Record inventories we can use in the tests. --> |
975 | + <!-- We need them in the demo data because test data is rolled back |
976 | + whenever an exception is raised. --> |
977 | + |
978 | + <!-- Record a hierarchical exhaustive inventory --> |
979 | + <record id="parent_inventory" model="stock.inventory"> |
980 | + <field name="name">Hierarchical exhaustive inventory</field> |
981 | + <field name="state">draft</field> |
982 | + <field name="date">2020-04-15 00:00:00</field> |
983 | + <field name="exhaustive">True</field> |
984 | + <field name="location_id" model="stock.location" ref="stock.stock_location_stock"/> |
985 | + </record> |
986 | + <record id="child_1_id" model="stock.inventory"> |
987 | + <field name="name">Team A</field> |
988 | + <field name="parent_id" ref="parent_inventory"/> |
989 | + <field name="location_id" model="stock.location" ref="stock.stock_location_14"/> |
990 | + </record> |
991 | + <record id="child_2_id" model="stock.inventory"> |
992 | + <field name="name">Team B</field> |
993 | + <field name="parent_id" ref="parent_inventory"/> |
994 | + <field name="location_id" model="stock.location" ref="stock.stock_location_components"/> |
995 | + </record> |
996 | + </data> |
997 | +</openerp> |
998 | |
999 | === added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml' |
1000 | --- stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 1970-01-01 00:00:00 +0000 |
1001 | +++ stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 2014-06-16 10:01:17 +0000 |
1002 | @@ -0,0 +1,37 @@ |
1003 | +<?xml version="1.0" encoding="utf-8"?> |
1004 | +<openerp> |
1005 | + <data> |
1006 | + <record model="ir.ui.view" id="stock_inventory_hierarchical_location_form_view"> |
1007 | + <field name="name">hierarchical.inventory.location.form</field> |
1008 | + <field name="model">stock.inventory</field> |
1009 | + <field name="inherit_id" ref="stock.view_inventory_form" /> |
1010 | + <field name="arch" type="xml"> |
1011 | + |
1012 | + <xpath expr="/form//field[@name='exhaustive']" position="attributes"> |
1013 | + <attribute name="attrs">{'readonly':[('parent_id', '!=', False)]}</attribute> |
1014 | + </xpath> |
1015 | + |
1016 | + <xpath expr="/form//field[@name='location_id']" position="attributes"> |
1017 | + <attribute name="on_change">onchange_location_id(location_id)</attribute> |
1018 | + </xpath> |
1019 | + |
1020 | + </field> |
1021 | + </record> |
1022 | + |
1023 | + <record model="ir.ui.view" id="stock_ihl_exhautive_form_view"> |
1024 | + <field name="name">hierarchical.inventory.location.exhautive.form</field> |
1025 | + <field name="model">stock.inventory</field> |
1026 | + <field name="inherit_id" ref="stock_inventory_hierarchical.stock_inventory_hierarchical_form_view" /> |
1027 | + <field name="arch" type="xml"> |
1028 | + <xpath expr="//field[@name='inventory_ids']" position="attributes"> |
1029 | + <attribute name="context">{'default_parent_id': active_id, 'default_exhaustive': exhaustive}</attribute> |
1030 | + </xpath> |
1031 | + </field> |
1032 | + </record> |
1033 | + |
1034 | + <!-- Show hierarchical exhaustive inventories by default --> |
1035 | + <record id="stock.action_inventory_form" model="ir.actions.act_window"> |
1036 | + <field name="context">{'full':'1', 'search_default_exhaustive':1, 'search_default_main_inventories':1}</field> |
1037 | + </record> |
1038 | + </data> |
1039 | +</openerp> |
1040 | |
1041 | === added directory 'stock_inventory_hierarchical_location/static' |
1042 | === added directory 'stock_inventory_hierarchical_location/static/src' |
1043 | === added directory 'stock_inventory_hierarchical_location/static/src/img' |
1044 | === added file 'stock_inventory_hierarchical_location/static/src/img/icon.png' |
1045 | 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-06-16 10:01:17 +0000 differ |
1046 | === added directory 'stock_inventory_hierarchical_location/tests' |
1047 | === added file 'stock_inventory_hierarchical_location/tests/__init__.py' |
1048 | --- stock_inventory_hierarchical_location/tests/__init__.py 1970-01-01 00:00:00 +0000 |
1049 | +++ stock_inventory_hierarchical_location/tests/__init__.py 2014-06-16 10:01:17 +0000 |
1050 | @@ -0,0 +1,39 @@ |
1051 | +# -*- coding: utf-8 -*- |
1052 | +# |
1053 | +# |
1054 | +# Authors: Laetitia Gangloff |
1055 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1056 | +# All Rights Reserved |
1057 | +# |
1058 | +# WARNING: This program as such is intended to be used by professional |
1059 | +# programmers who take the whole responsibility of assessing all potential |
1060 | +# consequences resulting from its eventual inadequacies and bugs. |
1061 | +# End users who are looking for a ready-to-use solution with commercial |
1062 | +# guarantees and support are strongly advised to contact a Free Software |
1063 | +# Service Company. |
1064 | +# |
1065 | +# This program is free software: you can redistribute it and/or modify |
1066 | +# it under the terms of the GNU Affero General Public License as |
1067 | +# published by the Free Software Foundation, either version 3 of the |
1068 | +# License, or (at your option) any later version. |
1069 | +# |
1070 | +# This program is distributed in the hope that it will be useful, |
1071 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1072 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1073 | +# GNU Affero General Public License for more details. |
1074 | +# |
1075 | +# You should have received a copy of the GNU Affero General Public License |
1076 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1077 | +# |
1078 | +# |
1079 | + |
1080 | +import fill_inventory_test |
1081 | + |
1082 | +fast_suite = [ |
1083 | +] |
1084 | + |
1085 | +checks = [ |
1086 | + fill_inventory_test, |
1087 | +] |
1088 | + |
1089 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1090 | |
1091 | === added file 'stock_inventory_hierarchical_location/tests/fill_inventory_test.py' |
1092 | --- stock_inventory_hierarchical_location/tests/fill_inventory_test.py 1970-01-01 00:00:00 +0000 |
1093 | +++ stock_inventory_hierarchical_location/tests/fill_inventory_test.py 2014-06-16 10:01:17 +0000 |
1094 | @@ -0,0 +1,118 @@ |
1095 | +# -*- coding: utf-8 -*- |
1096 | +# |
1097 | +# |
1098 | +# Authors: Laetitia Gangloff |
1099 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1100 | +# All Rights Reserved |
1101 | +# |
1102 | +# WARNING: This program as such is intended to be used by professional |
1103 | +# programmers who take the whole responsibility of assessing all potential |
1104 | +# consequences resulting from its eventual inadequacies and bugs. |
1105 | +# End users who are looking for a ready-to-use solution with commercial |
1106 | +# guarantees and support are strongly advised to contact a Free Software |
1107 | +# Service Company. |
1108 | +# |
1109 | +# This program is free software: you can redistribute it and/or modify |
1110 | +# it under the terms of the GNU Affero General Public License as |
1111 | +# published by the Free Software Foundation, either version 3 of the |
1112 | +# License, or (at your option) any later version. |
1113 | +# |
1114 | +# This program is distributed in the hope that it will be useful, |
1115 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1116 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1117 | +# GNU Affero General Public License for more details. |
1118 | +# |
1119 | +# You should have received a copy of the GNU Affero General Public License |
1120 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1121 | +# |
1122 | +# |
1123 | + |
1124 | +import openerp.tests.common as common |
1125 | + |
1126 | +DB = common.DB |
1127 | +ADMIN_USER_ID = common.ADMIN_USER_ID |
1128 | + |
1129 | + |
1130 | +class fill_inventory_test(common.TransactionCase): |
1131 | + |
1132 | + def setUp(self): |
1133 | + super(fill_inventory_test, self).setUp() |
1134 | + |
1135 | + def test_missing_location(self): |
1136 | + """ |
1137 | + Test that when confirm a parent inventory, the child location are not in the confirmation result |
1138 | + """ |
1139 | + parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory') |
1140 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id]) |
1141 | + # confirm shelf 1 inventory |
1142 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id') |
1143 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1144 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1145 | + self.assertEqual(len(missing_location), 1, "1 missing location should be find, because the inventory is empty") |
1146 | + wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]}) |
1147 | + self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]}) |
1148 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1149 | + self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is confirmed") |
1150 | + # confirm shelf 2 inventory |
1151 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id') |
1152 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1153 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1154 | + self.assertEqual(len(missing_location), 1, "1 missing location should be fine, because the inventory is empty") |
1155 | + self.registry('stock.inventory.line').create(self.cr, self.uid, {'product_id': self.ref('product.product_product_7'), |
1156 | + 'product_uom': self.ref('product.product_uom_unit'), |
1157 | + 'company_id': self.ref('base.main_company'), |
1158 | + 'inventory_id': inventory_id, |
1159 | + 'product_qty': 18.0, |
1160 | + 'location_id': self.ref('stock.stock_location_14')}) |
1161 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id]) |
1162 | + self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is filled") |
1163 | + wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]}) |
1164 | + wizard = self.registry('stock.inventory.uninventoried.locations').browse(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]}) |
1165 | + self.assertEqual(len(wizard.location_ids), 0, "The wizard should not contain any lines but contains %s." % wizard.location_ids) |
1166 | + self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]}) |
1167 | + # confirm parent inventory |
1168 | + missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [parent_inventory_id]) |
1169 | + self.assertEqual(len(missing_location), 1, "Only 1 missing location should be find, because there is some location in child inventory") |
1170 | + |
1171 | + def test_fill_inventory(self): |
1172 | + """ |
1173 | + Test that when fill a parent inventory, the child location are not in the result |
1174 | + """ |
1175 | + parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory') |
1176 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id]) |
1177 | + # confirm shelf 1 inventory |
1178 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id') |
1179 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1180 | + wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_components'), |
1181 | + 'recursive': True, |
1182 | + 'exhaustive': True, |
1183 | + 'set_stock_zero': True}, context={'active_ids': [inventory_id]}) |
1184 | + self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]}) |
1185 | + inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)]) |
1186 | + self.assertEqual(len(inventory_line_ids), 12, "12 inventory line is fount after filling inventory") |
1187 | + # confirm shelf 2 inventory |
1188 | + inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id') |
1189 | + self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id]) |
1190 | + wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_14'), |
1191 | + 'recursive': True, |
1192 | + 'exhaustive': True, |
1193 | + 'set_stock_zero': True}, context={'active_ids': [inventory_id]}) |
1194 | + self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]}) |
1195 | + inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)]) |
1196 | + self.assertEqual(len(inventory_line_ids), 4, "1 inventory line is fount after filling inventory") |
1197 | + # confirm parent inventory |
1198 | + wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_stock'), |
1199 | + 'recursive': True, |
1200 | + 'exhaustive': True, |
1201 | + 'set_stock_zero': True}, context={'active_ids': [parent_inventory_id]}) |
1202 | + try: |
1203 | + self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [parent_inventory_id]}) |
1204 | + except Exception, e: |
1205 | + 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.''") |
1206 | + exception_happened = True |
1207 | + pass |
1208 | + self.assertTrue(exception_happened) |
1209 | + inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', parent_inventory_id)]) |
1210 | + self.assertEqual(len(inventory_line_ids), 0, "No inventory line is fount after filling inventory") |
1211 | + |
1212 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1213 | |
1214 | === added file 'stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml' |
1215 | --- stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml 1970-01-01 00:00:00 +0000 |
1216 | +++ stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml 2014-06-16 10:01:17 +0000 |
1217 | @@ -0,0 +1,56 @@ |
1218 | +- |
1219 | + Check that the exhaustive field of parent inventory has been propagated to children. |
1220 | +- |
1221 | + !python {model: stock.inventory}: | |
1222 | + exhaustive = self.read(cr, uid, [ref("child_1_id")], ['exhaustive'])[0]['exhaustive'] |
1223 | + assert exhaustive, "Exhaustive field not propagated to child inventory" |
1224 | + |
1225 | +- |
1226 | + Check that I can't open child inventory while parent inventory is open. |
1227 | +- |
1228 | + !python {model: stock.inventory}: | |
1229 | + from stock_inventory_hierarchical import HierarchicalInventoryException |
1230 | + parent_state = self.read(cr, uid, [ref("parent_inventory")], ['state'])[0]['state'] |
1231 | + assert parent_state == 'draft', "Parent inventory in state '%s'. It should be 'draft'" % parent_state |
1232 | + try: |
1233 | + self.action_open(cr, uid, [ref("child_1_id")]) |
1234 | + except HierarchicalInventoryException as e: |
1235 | + log("Good ! The Inventory could not be opened: %s" % e) |
1236 | + child_1_state = self.read(cr, uid, [ref("child_1_id")], ['state'])[0]['state'] |
1237 | + assert child_1_state == 'draft', "Child inventory 1 have '%s' state. It should be 'draft'" % child_1_state |
1238 | + |
1239 | +- |
1240 | + I will check that the function get_missing_locations return some locations. |
1241 | +- |
1242 | + !python {model: stock.inventory}: | |
1243 | + missing_loc_ids = self.get_missing_locations(cr, uid, [ref('parent_inventory')], context=context) |
1244 | + assert len(missing_loc_ids)==3, "get_missing_locations did not return any ID." |
1245 | + |
1246 | +- |
1247 | + I will fill the inventory and check that the function get_missing_locations return no locations. |
1248 | + Adding 17” LCD Monitor. |
1249 | +- |
1250 | + !record {model: stock.inventory.line, id: lines_inventory_location_pc1}: |
1251 | + product_id: product.product_product_7 |
1252 | + product_uom: product.product_uom_unit |
1253 | + company_id: base.main_company |
1254 | + inventory_id: child_1_id |
1255 | + product_qty: 18.0 |
1256 | + location_id: stock.stock_location_14 |
1257 | + |
1258 | +- |
1259 | + Adding USB Keyboard, QWERTY. |
1260 | +- |
1261 | + !record {model: stock.inventory.line, id: lines_inventory_location_pc3}: |
1262 | + product_id: product.product_product_8 |
1263 | + product_uom: product.product_uom_unit |
1264 | + company_id: base.main_company |
1265 | + inventory_id: child_2_id |
1266 | + product_qty: 5.0 |
1267 | + location_id: stock.stock_location_components |
1268 | + |
1269 | +- |
1270 | + !python {model: stock.inventory}: | |
1271 | + |
1272 | + missing_loc_ids = self.get_missing_locations(cr, uid, [ref('parent_inventory')], context=context) |
1273 | + 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) |
1274 | |
1275 | === added directory 'stock_inventory_hierarchical_location/wizard' |
1276 | === added file 'stock_inventory_hierarchical_location/wizard/__init__.py' |
1277 | --- stock_inventory_hierarchical_location/wizard/__init__.py 1970-01-01 00:00:00 +0000 |
1278 | +++ stock_inventory_hierarchical_location/wizard/__init__.py 2014-06-16 10:01:17 +0000 |
1279 | @@ -0,0 +1,21 @@ |
1280 | +# -*- coding: utf-8 -*- |
1281 | +############################################################################## |
1282 | +# |
1283 | +# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved. |
1284 | +# |
1285 | +# This program is free software: you can redistribute it and/or modify |
1286 | +# it under the terms of the GNU General Public License as published by |
1287 | +# the Free Software Foundation, either version 3 of the License, or |
1288 | +# (at your option) any later version. |
1289 | +# |
1290 | +# This program is distributed in the hope that it will be useful, |
1291 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1292 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1293 | +# GNU General Public License for more details. |
1294 | +# |
1295 | +# You should have received a copy of the GNU General Public License |
1296 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1297 | +# |
1298 | +############################################################################## |
1299 | + |
1300 | +from . import stock_fill_location_inventory |
1301 | |
1302 | === added file 'stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py' |
1303 | --- stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 1970-01-01 00:00:00 +0000 |
1304 | +++ stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 2014-06-16 10:01:17 +0000 |
1305 | @@ -0,0 +1,89 @@ |
1306 | +# -*- coding: utf-8 -*- |
1307 | +# |
1308 | +# |
1309 | +# Authors: Laetitia Gangloff |
1310 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1311 | +# All Rights Reserved |
1312 | +# |
1313 | +# WARNING: This program as such is intended to be used by professional |
1314 | +# programmers who take the whole responsibility of assessing all potential |
1315 | +# consequences resulting from its eventual inadequacies and bugs. |
1316 | +# End users who are looking for a ready-to-use solution with commercial |
1317 | +# guarantees and support are strongly advised to contact a Free Software |
1318 | +# Service Company. |
1319 | +# |
1320 | +# This program is free software: you can redistribute it and/or modify |
1321 | +# it under the terms of the GNU Affero General Public License as |
1322 | +# published by the Free Software Foundation, either version 3 of the |
1323 | +# License, or (at your option) any later version. |
1324 | +# |
1325 | +# This program is distributed in the hope that it will be useful, |
1326 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1327 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1328 | +# GNU Affero General Public License for more details. |
1329 | +# |
1330 | +# You should have received a copy of the GNU Affero General Public License |
1331 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1332 | +# |
1333 | +# |
1334 | + |
1335 | +from openerp.osv import orm |
1336 | +from openerp.tools.translate import _ |
1337 | + |
1338 | + |
1339 | +class FillInventoryWizard(orm.TransientModel): |
1340 | + """If inventory as sub inventories, do not fill with sub inventories location""" |
1341 | + _inherit = 'stock.fill.inventory' |
1342 | + |
1343 | + def fill_inventory(self, cr, uid, ids, context=None): |
1344 | + """ To Import stock inventory according to products available in the location and not already in a sub inventory |
1345 | + |
1346 | + We split fill_inventory on many fill_inventory (one for each location) |
1347 | + @param self: The object pointer. |
1348 | + @param cr: A database cursor |
1349 | + @param uid: ID of the user currently logged in |
1350 | + @param ids: the ID or list of IDs if we want more than one |
1351 | + @param context: A standard dictionary |
1352 | + @return: |
1353 | + """ |
1354 | + if context is None: |
1355 | + context = {} |
1356 | + |
1357 | + if ids and len(ids): |
1358 | + ids = ids[0] |
1359 | + else: |
1360 | + return {'type': 'ir.actions.act_window_close'} |
1361 | + fill_inventory = self.browse(cr, uid, ids, context=context) |
1362 | + if fill_inventory.recursive and fill_inventory.exhaustive: |
1363 | + exclude_location_ids = [] |
1364 | + for i in self.pool['stock.inventory'].browse(cr, uid, context['active_ids']): |
1365 | + for sub_inventory in i.inventory_ids: |
1366 | + # exclude these location |
1367 | + exclude_location_ids.append(sub_inventory.location_id.id) |
1368 | + domain = [('location_id', 'child_of', [fill_inventory.location_id.id])] |
1369 | + if exclude_location_ids: |
1370 | + domain.append('!') |
1371 | + domain.append(('location_id', 'child_of', exclude_location_ids)) |
1372 | + location_ids = self.pool['stock.location'].search(cr, uid, domain, |
1373 | + order="id", |
1374 | + context=context) |
1375 | + all_in_exception = 0 |
1376 | + for location_id in location_ids: |
1377 | + try: |
1378 | + super(FillInventoryWizard, self).fill_inventory(cr, uid, |
1379 | + [self.copy(cr, uid, ids, {'location_id': location_id, |
1380 | + 'recursive': False, }, context=context)], |
1381 | + context=context) |
1382 | + except Exception, e: |
1383 | + if e.value == _('No product in this location. Please select a location in the product form.'): |
1384 | + all_in_exception = all_in_exception + 1 |
1385 | + pass |
1386 | + else: |
1387 | + raise e |
1388 | + if all_in_exception == len(location_ids): |
1389 | + raise orm.except_orm(_('Warning!'), _('No product in this location. Please select a location in the product form.')) |
1390 | + return {'type': 'ir.actions.act_window_close'} |
1391 | + else: |
1392 | + return super(FillInventoryWizard, self).fill_inventory(cr, uid, [ids], context=context) |
1393 | + |
1394 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1395 | |
1396 | === modified file 'stock_inventory_location/__openerp__.py' |
1397 | --- stock_inventory_location/__openerp__.py 2014-06-16 10:01:17 +0000 |
1398 | +++ stock_inventory_location/__openerp__.py 2014-06-16 10:01:17 +0000 |
1399 | @@ -62,9 +62,9 @@ |
1400 | "wizard/stock_fill_location_inventory_view.xml", |
1401 | ], |
1402 | "test": [ |
1403 | - "test/inventory_standard_test.yml", |
1404 | - "test/inventory_exhaustive_test.yml", |
1405 | - "test/inventory_future_test.yml", |
1406 | + "tests/inventory_standard_test.yml", |
1407 | + "tests/inventory_exhaustive_test.yml", |
1408 | + "tests/inventory_future_test.yml", |
1409 | ], |
1410 | "images": [ |
1411 | "images/inventory_form.png", |
1412 | |
1413 | === modified file 'stock_inventory_location/stock_inventory_location.py' |
1414 | --- stock_inventory_location/stock_inventory_location.py 2014-06-16 10:01:17 +0000 |
1415 | +++ stock_inventory_location/stock_inventory_location.py 2014-06-16 10:01:17 +0000 |
1416 | @@ -27,6 +27,7 @@ |
1417 | # TODOv8! remove, feature is included upstream |
1418 | from openerp.osv import osv |
1419 | from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT |
1420 | +from openerp import SUPERUSER_ID |
1421 | |
1422 | from .exceptions import ExhaustiveInventoryException |
1423 | |
1424 | @@ -270,7 +271,7 @@ |
1425 | """Error if an exhaustive Inventory is being conducted here""" |
1426 | inv_obj = self.pool['stock.inventory'] |
1427 | location_inventory_open_ids = inv_obj._get_locations_open_inventories( |
1428 | - cr, uid, context=context) |
1429 | + cr, SUPERUSER_ID, context=context) |
1430 | if not isinstance(ids, Iterable): |
1431 | ids = [ids] |
1432 | for inv_id in ids: |
1433 | @@ -286,7 +287,7 @@ |
1434 | self._check_inventory(cr, uid, ids, context=context) |
1435 | if not isinstance(ids, Iterable): |
1436 | ids = [ids] |
1437 | - ids_to_check = ids |
1438 | + ids_to_check = list(ids) |
1439 | # If changing the parent, no inventory must conducted there either |
1440 | if vals.get('location_id'): |
1441 | ids_to_check.append(vals['location_id']) |
1442 | @@ -326,7 +327,7 @@ |
1443 | message = "" |
1444 | inv_obj = self.pool['stock.inventory'] |
1445 | locked_location_ids = inv_obj._get_locations_open_inventories( |
1446 | - cr, uid, context=context) |
1447 | + cr, SUPERUSER_ID, context=context) |
1448 | if not locked_location_ids: |
1449 | # Nothing to verify |
1450 | return True |
1451 | |
1452 | === renamed directory 'stock_inventory_location/test' => 'stock_inventory_location/tests' |
1453 | === added file 'stock_inventory_location/tests/__init__.py' |
1454 | --- stock_inventory_location/tests/__init__.py 1970-01-01 00:00:00 +0000 |
1455 | +++ stock_inventory_location/tests/__init__.py 2014-06-16 10:01:17 +0000 |
1456 | @@ -0,0 +1,39 @@ |
1457 | +# -*- coding: utf-8 -*- |
1458 | +# |
1459 | +# |
1460 | +# Authors: Laetitia Gangloff |
1461 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1462 | +# All Rights Reserved |
1463 | +# |
1464 | +# WARNING: This program as such is intended to be used by professional |
1465 | +# programmers who take the whole responsibility of assessing all potential |
1466 | +# consequences resulting from its eventual inadequacies and bugs. |
1467 | +# End users who are looking for a ready-to-use solution with commercial |
1468 | +# guarantees and support are strongly advised to contact a Free Software |
1469 | +# Service Company. |
1470 | +# |
1471 | +# This program is free software: you can redistribute it and/or modify |
1472 | +# it under the terms of the GNU Affero General Public License as |
1473 | +# published by the Free Software Foundation, either version 3 of the |
1474 | +# License, or (at your option) any later version. |
1475 | +# |
1476 | +# This program is distributed in the hope that it will be useful, |
1477 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1478 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1479 | +# GNU Affero General Public License for more details. |
1480 | +# |
1481 | +# You should have received a copy of the GNU Affero General Public License |
1482 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1483 | +# |
1484 | +# |
1485 | + |
1486 | +import stock_inventory_location_test |
1487 | + |
1488 | +fast_suite = [ |
1489 | +] |
1490 | + |
1491 | +checks = [ |
1492 | + stock_inventory_location_test, |
1493 | +] |
1494 | + |
1495 | +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1496 | |
1497 | === added file 'stock_inventory_location/tests/stock_inventory_location_test.py' |
1498 | --- stock_inventory_location/tests/stock_inventory_location_test.py 1970-01-01 00:00:00 +0000 |
1499 | +++ stock_inventory_location/tests/stock_inventory_location_test.py 2014-06-16 10:01:17 +0000 |
1500 | @@ -0,0 +1,47 @@ |
1501 | +# -*- coding: utf-8 -*- |
1502 | +# |
1503 | +# |
1504 | +# Authors: Laetitia Gangloff |
1505 | +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) |
1506 | +# All Rights Reserved |
1507 | +# |
1508 | +# WARNING: This program as such is intended to be used by professional |
1509 | +# programmers who take the whole responsibility of assessing all potential |
1510 | +# consequences resulting from its eventual inadequacies and bugs. |
1511 | +# End users who are looking for a ready-to-use solution with commercial |
1512 | +# guarantees and support are strongly advised to contact a Free Software |
1513 | +# Service Company. |
1514 | +# |
1515 | +# This program is free software: you can redistribute it and/or modify |
1516 | +# it under the terms of the GNU Affero General Public License as |
1517 | +# published by the Free Software Foundation, either version 3 of the |
1518 | +# License, or (at your option) any later version. |
1519 | +# |
1520 | +# This program is distributed in the hope that it will be useful, |
1521 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
1522 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1523 | +# GNU Affero General Public License for more details. |
1524 | +# |
1525 | +# You should have received a copy of the GNU Affero General Public License |
1526 | +# along with this program. If not, see <http://www.gnu.org/licenses/>. |
1527 | +# |
1528 | +# |
1529 | + |
1530 | +import openerp.tests.common as common |
1531 | + |
1532 | +DB = common.DB |
1533 | +ADMIN_USER_ID = common.ADMIN_USER_ID |
1534 | + |
1535 | + |
1536 | +class stock_inventory_location_test(common.TransactionCase): |
1537 | + |
1538 | + def setUp(self): |
1539 | + super(stock_inventory_location_test, self).setUp() |
1540 | + |
1541 | + def test_update_parent_location(self): |
1542 | + """ |
1543 | + Test the update of the parent of a location (no inventory in progress |
1544 | + """ |
1545 | + self.registry('stock.location').write(self.cr, self.uid, self.ref('stock.stock_location_5'), {'location_id': self.ref('stock.stock_location_4')}) |
1546 | + |
1547 | +# 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.