Merge lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-hierarchical into lp:stock-logistic-warehouse

Proposed by Loïc Bellier - Numérigraphe
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
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.

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_hierarchical_location depends of stock_inventory_hierarchical and
stock_inventory_location (lp:~numerigraphe-team/stock-logistic-warehouse/7.0-inventory-location).

Thanks to Laetitia GANGLOFF from Ascone for her contribution.

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

Loic and I are improving this proposal WRT the 7.0 coding style and latest v8 updates.

Revision history for this message
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.

review: Needs Resubmitting (test pending)
Revision history for this message
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) :
review: Abstain (i'm a contributor)
Revision history for this message
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.

review: Needs Fixing (functionnal bug)
Revision history for this message
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote :
review: Abstain (co-author)
47. By Numérigraphe

[IMP] add button to open subinventories and progresbar on inventory header.

48. By Numérigraphe

[IMP] French translation

Revision history for this message
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote :

The source code management for this project has been moved to https://github.com/OCA/stock-logistics-warehouse

Could you resubmit this MP on the new site?

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

I've finally resubmitted this as part of the pull request at https://github.com/OCA/stock-logistics-warehouse/pull/17.
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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory 'stock_inventory_hierarchical'
=== added file 'stock_inventory_hierarchical/__init__.py'
--- stock_inventory_hierarchical/__init__.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/__init__.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,28 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21# This package-wide list keeps the names of the field that must be
22# propagated from root inventories to their children.
23# Add field names in the Model's definition.
24PARENT_VALUES = []
25
26import hierarchical_inventory
27# Bring the main exception into the package's scope for easier reuse
28from .exceptions import HierarchicalInventoryException
029
=== added file 'stock_inventory_hierarchical/__openerp__.py'
--- stock_inventory_hierarchical/__openerp__.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/__openerp__.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,46 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21{
22 "name": "Hierarchical Physical Inventory",
23 "version": "1.1",
24 "depends": ["stock"],
25 "author": "Numérigraphe",
26 "category": "Warehouse Management",
27 "description": """
28Hierarchical structure for Physical Inventories and sub-Inventories
29===================================================================
30
31This module adds a parent-child relationship between Physical Inventories, to
32help users manage complex inventories.
33Using several inventories, you can distribute the counting to several persons
34and still keep a clear overview of global Inventory's status.
35
36OpenERP will make sure the status of the Inventory and it's Sub-Inventories are
37consistent.
38""",
39 "data": ["hierarchical_inventory_view.xml"],
40 "test": ["test/hierarchical_inventory_test.yml"],
41 "demo": ["hierarchical_inventory_demo.xml"],
42 "images": [
43 "inventory_form.png",
44 "inventory_form_actions.png",
45 ],
46}
047
=== added file 'stock_inventory_hierarchical/exceptions.py'
--- stock_inventory_hierarchical/exceptions.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/exceptions.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,26 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21from openerp.osv import orm
22
23
24class HierarchicalInventoryException(orm.except_orm):
25 """The operation is not possible for a hierarchical inventory"""
26 pass
027
=== added file 'stock_inventory_hierarchical/hierarchical_inventory.py'
--- stock_inventory_hierarchical/hierarchical_inventory.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/hierarchical_inventory.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,202 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21from openerp.osv import orm, fields
22from openerp.tools.translate import _
23
24from .exceptions import HierarchicalInventoryException
25
26# Add the date to the list of fields we must propagate to children inventories
27from . import PARENT_VALUES
28PARENT_VALUES.append('date')
29
30
31class HierarchicalInventory(orm.Model):
32 _inherit = 'stock.inventory'
33
34 _parent_store = True
35 _parent_order = 'date, name'
36 _order = 'parent_left'
37
38 def name_get(self, cr, uid, ids, context=None):
39 """Show the parent inventory's name in the name of the children
40
41 :param dict context: the ``inventory_display`` key can be
42 used to select the short version of the
43 inventory name (without the direct parent),
44 when set to ``'short'``. The default is
45 the long version."""
46 if context is None:
47 context = {}
48 if context.get('inventory_display') == 'short':
49 # Short name context: just do the usual stuff
50 return super(HierarchicalInventory, self).name_get(
51 cr, uid, ids, context=context)
52 if isinstance(ids, (list, tuple)) and not len(ids):
53 return []
54 if isinstance(ids, (long, int)):
55 ids = [ids]
56 reads = self.read(cr, uid, ids, ['name', 'parent_id'], context=context)
57 res = []
58 for record in reads:
59 name = record['name']
60 if record['parent_id']:
61 name = record['parent_id'][1] + ' / ' + name
62 res.append((record['id'], name))
63 return res
64
65 def name_search(self, cr, uid, name='', args=None, operator='ilike',
66 context=None, limit=100):
67 """Enable search on value returned by name_get ("parent / child")"""
68 if not args:
69 args = []
70 if not context:
71 context = {}
72 if name:
73 # Make sure name_search is symmetric to name_get
74 name = name.split(' / ')[-1]
75 ids = self.search(cr, uid, [('name', operator, name)] + args,
76 limit=limit, context=context)
77 else:
78 ids = self.search(cr, uid, args, limit=limit, context=context)
79 return self.name_get(cr, uid, ids, context=context)
80
81 def _complete_name(self, cr, uid, ids, field_name, arg, context=None):
82 """Function-field wrapper to get the complete name from name_get"""
83 res = self.name_get(cr, uid, ids, context=context)
84 return dict(res)
85
86 def _progress_rate(self, cr, uid, ids, field_name, arg, context=None):
87 """Rate of (sub)inventories done/total"""
88 rates = {}
89 for current_id in ids:
90 nb = self.search(
91 cr, uid, [('parent_id', 'child_of', current_id)],
92 context=context, count=True)
93 if not nb:
94 # No inventory, consider it's 0% done
95 rates[current_id] = 0
96 continue
97 nb_done = self.search(
98 cr, uid, [('parent_id', 'child_of', current_id),
99 ('state', '=', 'done')],
100 context=context, count=True)
101 rates[current_id] = 100 * nb_done / nb
102 return rates
103
104 _columns = {
105 # name_get() only changes the default name of the record, not the
106 # content of the field "name" so we add another field for that
107 'complete_name': fields.function(
108 _complete_name, type="char",
109 string='Complete reference'),
110 'parent_id': fields.many2one(
111 'stock.inventory', 'Parent Inventory', ondelete='cascade', readonly=True,
112 states={'draft': [('readonly', False)]}),
113 'inventory_ids': fields.one2many(
114 'stock.inventory', 'parent_id', 'List of Sub-inventories',
115 readonly=True, states={'draft': [('readonly', False)]}),
116 'parent_left': fields.integer('Parent Left', select=1),
117 'parent_right': fields.integer('Parent Right', select=1),
118 'progress_rate': fields.function(
119 _progress_rate, string='Progress', type='float'),
120 }
121
122 _constraints = [
123 (orm.Model._check_recursion,
124 'Error: You can not create recursive inventories.',
125 ['parent_id']),
126 ]
127
128 def create(self, cr, uid, vals, context=None):
129 """Copy selected values from parent to child"""
130 if vals and vals.get('parent_id'):
131 existing_fields = self.fields_get_keys(cr, uid, context=context)
132 parent_values = self.read(cr, uid, [vals['parent_id']],
133 PARENT_VALUES, context=context)
134 vals = vals.copy()
135 vals.update({field: parent_values[0][field]
136 for field in PARENT_VALUES
137 if field in existing_fields})
138 return super(HierarchicalInventory, self).create(
139 cr, uid, vals, context=context)
140
141 def write(self, cr, uid, ids, vals, context=None):
142 """Copy selected values from parent to children"""
143 if context is None:
144 context = {}
145
146 values = super(HierarchicalInventory, self).write(
147 cr, uid, ids, vals, context=context)
148 if not vals or context.get('norecurse', False):
149 return values
150
151 # filter the fields we want to propagate
152 children_values = {
153 field: vals[field] for field in PARENT_VALUES if field in vals
154 }
155 if not children_values:
156 return values
157
158 if not isinstance(ids, list):
159 ids = [ids]
160 # The context disables recursion - children are already included
161 return self.write(
162 cr, uid, self.search(cr, uid, [('parent_id', 'child_of', ids)]),
163 children_values, context=dict(context, norecurse=True))
164
165 def action_cancel_inventory(self, cr, uid, ids, context=None):
166 """Cancel inventory only if all the parents are canceled"""
167 inventories = self.browse(cr, uid, ids, context=context)
168 for inventory in inventories:
169 while inventory.parent_id:
170 inventory = inventory.parent_id
171 if inventory.state != 'cancel':
172 raise HierarchicalInventoryException(
173 _('Warning'),
174 _('One of the parent Inventories is not canceled.'))
175 return super(HierarchicalInventory,
176 self).action_cancel_inventory(cr, uid, ids,
177 context=context)
178
179 def action_confirm(self, cr, uid, ids, context=None):
180 """Confirm inventory only if all the children are confirmed"""
181 children_count = self.search(
182 cr, uid, [('parent_id', 'child_of', ids),
183 ('state', 'not in', ['confirm', 'done'])],
184 context=context, count=True)
185 if children_count > 1:
186 raise HierarchicalInventoryException(
187 _('Warning'),
188 _('Some Sub-inventories are not confirmed.'))
189 return super(HierarchicalInventory, self).action_confirm(
190 cr, uid, ids, context=context)
191
192 def action_done(self, cr, uid, ids, context=None):
193 """Perform validation only if all the children states are 'done'."""
194 children_count = self.search(cr, uid, [('parent_id', 'child_of', ids),
195 ('state', '!=', 'done')],
196 context=context, count=True)
197 if children_count > 1:
198 raise HierarchicalInventoryException(
199 _('Warning'),
200 _('Some Sub-inventories are not validated.'))
201 return super(HierarchicalInventory, self).action_done(
202 cr, uid, ids, context=context)
0203
=== added file 'stock_inventory_hierarchical/hierarchical_inventory_demo.xml'
--- stock_inventory_hierarchical/hierarchical_inventory_demo.xml 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/hierarchical_inventory_demo.xml 2014-07-01 11:47:18 +0000
@@ -0,0 +1,17 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data noupdate="0">
4 <!-- Example Inventory with Sub-Inventories. -->
5 <record id="stock_inventory_parent0" model="stock.inventory">
6 <field name="name">Main Inventory</field>
7 </record>
8 <record id="child_1_id" model="stock.inventory">
9 <field name="name">Sub-Inventory 1</field>
10 <field name="parent_id" ref="stock_inventory_parent0" />
11 </record>
12 <record id="child_2_id" model="stock.inventory">
13 <field name="name">Sub-Inventory 2</field>
14 <field name="parent_id" ref="stock_inventory_parent0" />
15 </record>
16 </data>
17</openerp>
018
=== added file 'stock_inventory_hierarchical/hierarchical_inventory_view.xml'
--- stock_inventory_hierarchical/hierarchical_inventory_view.xml 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/hierarchical_inventory_view.xml 2014-07-01 11:47:18 +0000
@@ -0,0 +1,84 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <!-- Add parent_id and number of Sub-inventories to form view -->
5 <record model="ir.ui.view" id="stock_inventory_hierarchical_tree_view">
6 <field name="name">hierarchical.inventory.tree</field>
7 <field name="model">stock.inventory</field>
8 <field name="inherit_id" ref="stock.view_inventory_tree" />
9 <field name="field_parent">inventory_ids</field>
10 <field name="arch" type="xml">
11 <xpath expr="//field[@name='name']" position="replace">
12 <field name="complete_name" string="Reference"/>
13 </xpath>
14 <xpath expr="//field[@name='state']" position="after">
15 <field name="progress_rate" widget="progressbar" />
16 </xpath>
17 </field>
18 </record>
19
20 <!-- Add the parent_id filter to search view -->
21 <record model="ir.ui.view" id="view_inventory_subinventories_filter">
22 <field name="name">hierarchical.inventory.filter</field>
23 <field name="model">stock.inventory</field>
24 <field name="inherit_id" ref="stock.view_inventory_filter" />
25 <field name="arch" type="xml">
26 <xpath expr="//field[@name='name']" position="before">
27 <filter icon="terp-check" name="main_inventories" string="Main inventories" domain="[('parent_id', '=', False)]" help="Only select inventories that have no parents." />
28 <separator orientation="vertical"/>
29 </xpath>
30 <xpath expr="//field[@name='date']" position="after">
31 <field name="parent_id" />
32 </xpath>
33 </field>
34 </record>
35 <!-- Show main inventories by default -->
36 <record id="stock.action_inventory_form" model="ir.actions.act_window">
37 <field name="context">{'full':'1', 'search_default_main_inventories':1}</field>
38 </record>
39
40 <record model="ir.ui.view" id="stock_inventory_hierarchical_form_view">
41 <field name="name">hierarchical.inventory.form</field>
42 <field name="model">stock.inventory</field>
43 <field name="inherit_id" ref="stock.view_inventory_form" />
44 <field name="arch" type="xml">
45 <xpath expr="/form//div[@class='oe_right oe_button_box']" position="inside">
46 <button name="%(action_view_sub_inventory)d" string="View Sub-inventories" type="action" />
47 </xpath>
48 <xpath expr="/form//field[@name='name']" position="after">
49 <field name="parent_id"/>
50 </xpath>
51 <xpath expr="/form//field[@name='date']" position="attributes">
52 <attribute name="attrs">{'readonly':[('parent_id', '!=', False)]}</attribute>
53 </xpath>
54 <xpath expr="/form//field[@name='date']" position="after">
55 <field name="progress_rate" widget="progressbar" />
56 </xpath>
57 <xpath
58 expr="//page[@string='General Information']"
59 position="after">
60 <page string="Sub-inventories">
61 <field name="inventory_ids" nolabel="1" context="{'default_parent_id': active_id}">
62 <tree>
63 <field name="name" />
64 <field name="state" />
65 <field name="progress_rate" widget="progressbar" />
66 </tree>
67 </field>
68 </page>
69 </xpath>
70 </field>
71 </record>
72
73 <!-- Open the children of the current Inventory in a distinct list
74 to let users work in a normal window instead of a popup -->
75 <act_window id="action_view_sub_inventory"
76 name="View Sub-inventories"
77 res_model="stock.inventory"
78 src_model="stock.inventory"
79 view_mode="tree,form"
80 view_type="form"
81 domain="[('parent_id', 'child_of', active_id),('id', '!=', active_id)]"
82 context="{'full':1, 'search_default_main_inventories':0}"/>
83 </data>
84</openerp>
085
=== added directory 'stock_inventory_hierarchical/i18n'
=== added file 'stock_inventory_hierarchical/i18n/fr.po'
--- stock_inventory_hierarchical/i18n/fr.po 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/i18n/fr.po 2014-07-01 11:47:18 +0000
@@ -0,0 +1,116 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * stock_inventory_hierarchical
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-07-01 11:15+0000\n"
10"PO-Revision-Date: 2014-07-01 11:15+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: stock_inventory_hierarchical
19#: field:stock.inventory,complete_name:0
20msgid "Complete reference"
21msgstr "Réference complète"
22
23#. module: stock_inventory_hierarchical
24#: constraint:stock.inventory:0
25msgid "Error: You can not create recursive inventories."
26msgstr "Erreur : Vous ne pouvez pas créer d'inventaire récursifs."
27
28#. module: stock_inventory_hierarchical
29#: code:_description:0
30#: model:ir.model,name:stock_inventory_hierarchical.model_stock_inventory
31#, python-format
32msgid "Inventory"
33msgstr "Inventaire"
34
35#. module: stock_inventory_hierarchical
36#: field:stock.inventory,inventory_ids:0
37msgid "List of Sub-inventories"
38msgstr "Liste des sous-inventaires"
39
40#. module: stock_inventory_hierarchical
41#: view:stock.inventory:0
42msgid "Main inventories"
43msgstr "Inventaires principaux"
44
45#. module: stock_inventory_hierarchical
46#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:174
47#, python-format
48msgid "One of the parent Inventories is not canceled."
49msgstr "Un des inventaires pères n'est pas annulé."
50
51#. module: stock_inventory_hierarchical
52#: view:stock.inventory:0
53msgid "Only select inventories that have no parents."
54msgstr "Sélectionne uniquement les inventaires qui n'ont pas de père."
55
56#. module: stock_inventory_hierarchical
57#: field:stock.inventory,parent_id:0
58msgid "Parent Inventory"
59msgstr "Inventaire père"
60
61#. module: stock_inventory_hierarchical
62#: field:stock.inventory,parent_left:0
63msgid "Parent Left"
64msgstr "Parent gauche"
65
66#. module: stock_inventory_hierarchical
67#: field:stock.inventory,parent_right:0
68msgid "Parent Right"
69msgstr "Parent droit"
70
71#. module: stock_inventory_hierarchical
72#: field:stock.inventory,progress_rate:0
73msgid "Progress"
74msgstr "Avancement"
75
76#. module: stock_inventory_hierarchical
77#: view:stock.inventory:0
78msgid "Reference"
79msgstr "Référence"
80
81#. module: stock_inventory_hierarchical
82#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:188
83#, python-format
84msgid "Some Sub-inventories are not confirmed."
85msgstr "Certains sous-inventaires ne sont pas confirmés."
86
87#. module: stock_inventory_hierarchical
88#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:200
89#, python-format
90msgid "Some Sub-inventories are not validated."
91msgstr "Certains sous-inventaires ne sont pas terminés."
92
93#. module: stock_inventory_hierarchical
94#: view:stock.inventory:0
95msgid "Sub-inventories"
96msgstr "Sous-inventaires"
97
98#. module: stock_inventory_hierarchical
99#: model:ir.actions.act_window,name:stock_inventory_hierarchical.action_view_sub_inventory
100#: view:stock.inventory:0
101msgid "View Sub-inventories"
102msgstr "Voir les sous-inventaires"
103
104#. module: stock_inventory_hierarchical
105#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:173
106#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:187
107#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:199
108#, python-format
109msgid "Warning"
110msgstr "Attention"
111
112#. module: stock_inventory_hierarchical
113#: view:stock.inventory:0
114msgid "{'readonly':[('parent_id', '!=', False)]}"
115msgstr "{'readonly':[('parent_id', '!=', False)]}"
116
0117
=== added file 'stock_inventory_hierarchical/i18n/stock_inventory_hierarchical.pot'
--- stock_inventory_hierarchical/i18n/stock_inventory_hierarchical.pot 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/i18n/stock_inventory_hierarchical.pot 2014-07-01 11:47:18 +0000
@@ -0,0 +1,116 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * stock_inventory_hierarchical
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-07-01 11:26+0000\n"
10"PO-Revision-Date: 2014-07-01 11:26+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: stock_inventory_hierarchical
19#: field:stock.inventory,complete_name:0
20msgid "Complete reference"
21msgstr ""
22
23#. module: stock_inventory_hierarchical
24#: constraint:stock.inventory:0
25msgid "Error: You can not create recursive inventories."
26msgstr ""
27
28#. module: stock_inventory_hierarchical
29#: code:_description:0
30#: model:ir.model,name:stock_inventory_hierarchical.model_stock_inventory
31#, python-format
32msgid "Inventory"
33msgstr ""
34
35#. module: stock_inventory_hierarchical
36#: field:stock.inventory,inventory_ids:0
37msgid "List of Sub-inventories"
38msgstr ""
39
40#. module: stock_inventory_hierarchical
41#: view:stock.inventory:0
42msgid "Main inventories"
43msgstr ""
44
45#. module: stock_inventory_hierarchical
46#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:174
47#, python-format
48msgid "One of the parent Inventories is not canceled."
49msgstr ""
50
51#. module: stock_inventory_hierarchical
52#: view:stock.inventory:0
53msgid "Only select inventories that have no parents."
54msgstr ""
55
56#. module: stock_inventory_hierarchical
57#: field:stock.inventory,parent_id:0
58msgid "Parent Inventory"
59msgstr ""
60
61#. module: stock_inventory_hierarchical
62#: field:stock.inventory,parent_left:0
63msgid "Parent Left"
64msgstr ""
65
66#. module: stock_inventory_hierarchical
67#: field:stock.inventory,parent_right:0
68msgid "Parent Right"
69msgstr ""
70
71#. module: stock_inventory_hierarchical
72#: field:stock.inventory,progress_rate:0
73msgid "Progress"
74msgstr ""
75
76#. module: stock_inventory_hierarchical
77#: view:stock.inventory:0
78msgid "Reference"
79msgstr ""
80
81#. module: stock_inventory_hierarchical
82#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:188
83#, python-format
84msgid "Some Sub-inventories are not confirmed."
85msgstr ""
86
87#. module: stock_inventory_hierarchical
88#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:200
89#, python-format
90msgid "Some Sub-inventories are not validated."
91msgstr ""
92
93#. module: stock_inventory_hierarchical
94#: view:stock.inventory:0
95msgid "Sub-inventories"
96msgstr ""
97
98#. module: stock_inventory_hierarchical
99#: model:ir.actions.act_window,name:stock_inventory_hierarchical.action_view_sub_inventory
100#: view:stock.inventory:0
101msgid "View Sub-inventories"
102msgstr ""
103
104#. module: stock_inventory_hierarchical
105#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:173
106#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:187
107#: code:addons/stock_inventory_hierarchical/hierarchical_inventory.py:199
108#, python-format
109msgid "Warning"
110msgstr ""
111
112#. module: stock_inventory_hierarchical
113#: view:stock.inventory:0
114msgid "{'readonly':[('parent_id', '!=', False)]}"
115msgstr ""
116
0117
=== added directory 'stock_inventory_hierarchical/images'
=== added file 'stock_inventory_hierarchical/images/inventory_form.png'
1Binary 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 differ118Binary 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
=== added file 'stock_inventory_hierarchical/images/inventory_form_actions.png'
2Binary 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 differ119Binary 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
=== added directory 'stock_inventory_hierarchical/static'
=== added directory 'stock_inventory_hierarchical/static/src'
=== added directory 'stock_inventory_hierarchical/static/src/img'
=== added file 'stock_inventory_hierarchical/static/src/img/icon.png'
3Binary 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 differ120Binary 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
=== added directory 'stock_inventory_hierarchical/test'
=== added file 'stock_inventory_hierarchical/test/hierarchical_inventory_test.yml'
--- stock_inventory_hierarchical/test/hierarchical_inventory_test.yml 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical/test/hierarchical_inventory_test.yml 2014-07-01 11:47:18 +0000
@@ -0,0 +1,96 @@
1-
2 In this file, i check rules about hierarchical inventories.
3 Children date must be the same of parent date for each state,
4 the state of parent and children can change only if conditions are correct.
5-
6 Check if date of children are the same as the parent's.
7-
8 !python {model: stock.inventory}: |
9 parent_date = self.read(
10 cr, uid, [ref('stock_inventory_parent0')], ['date'])[0]['date']
11 child_1_date = self.read(
12 cr, uid, [ref('child_1_id')], ['date'])[0]['date']
13 assert child_1_date == parent_date, "Date are different: %s - %s" % (parent_date, child_1_date)
14
15 child_2_date = self.read(
16 cr, uid, [ref('child_2_id')], ['date'])[0]['date']
17 assert child_2_date == parent_date, "Date are different: %s - %s" % (parent_date, child_2_date)
18
19-
20 Check if children cannot be canceled if the parent was not canceled.
21 I'll try to cancel both children inventory while parent inventory having "draft" state.
22 After, i'll verify the state of each inventory.
23-
24 !python {model: stock.inventory}: |
25 from stock_inventory_hierarchical import HierarchicalInventoryException
26 try:
27 self.action_cancel_inventory(cr, uid, [ref('child_1_id')])
28 except HierarchicalInventoryException as e:
29 log("Good ! The Inventory could not be canceled: %s" % e)
30 try:
31 self.action_cancel_inventory(cr, uid, [ref('child_2_id')])
32 except HierarchicalInventoryException as e:
33 log("Good ! The Inventory could not be canceled: %s" % e)
34 child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state']
35 assert child_1_state == 'draft', "Child inventory 1 have '%s' state. It should be 'draft'" % child_1_state
36 child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state']
37 assert child_2_state == 'draft', "Child inventory 2 have '%s' state. It should be 'draft'" % child_2_state
38
39-
40 Check if children inventory have confirm state before confirm parent inventory.
41 To check this, i'll try to confirm parent inventory when children inventory having "draft" state,
42 and i'll check if state is still 'draft'.
43-
44 !python {model: stock.inventory}: |
45 from stock_inventory_hierarchical import HierarchicalInventoryException
46 try:
47 self.action_confirm(cr, uid, [ref('stock_inventory_parent0')])
48 except HierarchicalInventoryException as e:
49 log("Good, the inventory could not be confirmed: %s", e)
50 parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state']
51 assert parent_state == 'draft', "Parent inventory have '%s' state. It should be 'draft'" % parent_state
52
53-
54 In order, i'll confirm the children inventories, and the parent inventory after.
55-
56 !python {model: stock.inventory}: |
57 self.action_confirm(cr, uid, [ref('child_1_id')])
58 child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state']
59 assert child_1_state == 'confirm', "Child inventory 1 have '%s' state. It should be 'confirm'" % child_1_state
60
61 self.action_confirm(cr, uid, [ref('child_2_id')])
62 child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state']
63 assert child_2_state == 'confirm', "Child inventory 2 have '%s' state. It should be 'confirm'" % child_2_state
64
65 self.action_confirm(cr, uid, [ref('stock_inventory_parent0')])
66 parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state']
67 assert parent_state == 'confirm', "Parent inventory have '%s' state. It should be 'confirm'" % parent_state
68
69-
70 Check if children inventory have done state before validate parent inventory.
71 I'll try to validate parent inventory before children.
72-
73 !python {model: stock.inventory}: |
74 from stock_inventory_hierarchical import HierarchicalInventoryException
75 try:
76 self.action_done(cr, uid, [ref('stock_inventory_parent0')])
77 except HierarchicalInventoryException as e:
78 log("Good, the inventory could not be validated: %s", e)
79 parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state']
80 assert parent_state == 'confirm', "Parent inventory have '%s' state. It should be 'confirm'" % parent_state
81
82-
83 Now, i'll validate all children inventory before validate the parent.
84-
85 !python {model: stock.inventory}: |
86 self.action_done(cr, uid, [ref('child_1_id')])
87 child_1_state = self.read(cr, uid, [ref('child_1_id')], ['state'])[0]['state']
88 assert child_1_state == 'done', "Child inventory 1 have '%s' state. It should be 'done'" % child_1_state
89
90 self.action_done(cr, uid, [ref('child_2_id')])
91 child_2_state = self.read(cr, uid, [ref('child_2_id')], ['state'])[0]['state']
92 assert child_2_state == 'done', "Child inventory 2 have '%s' state. It should be 'done'" % child_2_state
93
94 self.action_done(cr, uid, [ref('stock_inventory_parent0')])
95 parent_state = self.read(cr, uid, [ref('stock_inventory_parent0')], ['state'])[0]['state']
96 assert parent_state == 'done', "Parent inventory have '%s' state. It should be 'done'" % parent_state
097
=== added directory 'stock_inventory_hierarchical_location'
=== added file 'stock_inventory_hierarchical_location/__init__.py'
--- stock_inventory_hierarchical_location/__init__.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/__init__.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,22 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21from . import inventory_hierarchical_location
22from . import wizard
023
=== added file 'stock_inventory_hierarchical_location/__openerp__.py'
--- stock_inventory_hierarchical_location/__openerp__.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/__openerp__.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,49 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21{
22 "name": "Exhaustive and hierarchical Stock Inventories",
23 "version": "1.1",
24 "depends": ["stock_inventory_hierarchical", "stock_inventory_location"],
25 "auto_install": True,
26 "author": u"Numérigraphe",
27 "category": "Hidden",
28 "description": """
29Make exhaustive Inventories aware of their Sub-Inventories.
30===========================================================
31
32This module allows an inventory to contain a general Location,
33and it's sub-inventories to contain some of it's sub-Locations.
34It will prevent you from setting the Inventories and sub-Inventories
35in inconsistent status.
36
37This module will be installed automatically if the modules
38"stock_inventory_location" and "stock_inventory_hierarchical" are both
39installed.
40You must keep this module installed to ensure proper functioning.
41
42 """,
43 "data": [
44 "inventory_hierarchical_location_view.xml",
45 "wizard/generate_inventory_view.xml",
46 ],
47 "test": ["tests/inventory_hierarchical_location_test.yml"],
48 "demo": ["inventory_hierarchical_location_demo.xml"],
49}
050
=== added directory 'stock_inventory_hierarchical_location/i18n'
=== added file 'stock_inventory_hierarchical_location/i18n/fr.po'
--- stock_inventory_hierarchical_location/i18n/fr.po 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/i18n/fr.po 2014-07-01 11:47:18 +0000
@@ -0,0 +1,164 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * stock_inventory_hierarchical_location
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-07-01 11:35+0000\n"
10"PO-Revision-Date: 2014-07-01 11:35+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: stock_inventory_hierarchical_location
19#: view:stock.generate.inventory:0
20msgid "Cancel"
21msgstr "Cancel"
22
23#. module: stock_inventory_hierarchical_location
24#: code:_description:0
25#: model:ir.actions.act_window,name:stock_inventory_hierarchical_location.action_view_stock_generate_inventory
26#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_generate_inventory
27#: model:ir.ui.menu,name:stock_inventory_hierarchical_location.menu_action_stock_generate_inventory_form
28#: view:stock.generate.inventory:0
29#, python-format
30msgid "Generate Inventory"
31msgstr "Générer l'inventaire"
32
33#. module: stock_inventory_hierarchical_location
34#: help:stock.generate.inventory,only_view:0
35msgid "If set, only inventory on view location can be created"
36msgstr "Si coché, seuls les inventaires des emplacements vues seront créés."
37
38#. module: stock_inventory_hierarchical_location
39#: code:_description:0
40#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_fill_inventory
41#, python-format
42msgid "Import Inventory"
43msgstr "Importer un inventaire"
44
45#. module: stock_inventory_hierarchical_location
46#: code:_description:0
47#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_inventory
48#, python-format
49msgid "Inventory"
50msgstr "Inventaire"
51
52#. module: stock_inventory_hierarchical_location
53#: code:addons/stock_inventory_hierarchical_location/wizard/generate_inventory.py:124
54#, python-format
55msgid "Inventory generated"
56msgstr "Inventaire généré"
57
58#. module: stock_inventory_hierarchical_location
59#: field:stock.generate.inventory,prefix_inv_name:0
60msgid "Inventory prefix"
61msgstr "Préfixe de l'inventaire"
62
63#. module: stock_inventory_hierarchical_location
64#: field:stock.generate.inventory,level:0
65msgid "Level"
66msgstr "Profondeur"
67
68#. module: stock_inventory_hierarchical_location
69#: sql_constraint:stock.generate.inventory:0
70msgid "Level must be positive!"
71msgstr "La profondeur doit être positive!"
72
73#. module: stock_inventory_hierarchical_location
74#: field:stock.generate.inventory,location_id:0
75msgid "Location"
76msgstr "Emplacement"
77
78#. module: stock_inventory_hierarchical_location
79#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:78
80#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84
81#, python-format
82msgid "No product in this location. Please select a location in the product form."
83msgstr ""
84"Aucun article dans cet emplacement. Veuillez choisir un emplacement dans le "
85"formulaire produit."
86
87#. module: stock_inventory_hierarchical_location
88#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:43
89#, python-format
90msgid "One of the parent inventories is not open."
91msgstr "Un des inventaires pères n'est pas ouvert."
92
93#. module: stock_inventory_hierarchical_location
94#: field:stock.generate.inventory,only_view:0
95msgid "Only view"
96msgstr "Vues seulement"
97
98#. module: stock_inventory_hierarchical_location
99#: help:stock.generate.inventory,prefix_inv_name:0
100msgid "Optional prefix for all created inventory"
101msgstr "Préfixe facultatif ajouté devant les noms des inventaires créés"
102
103#. module: stock_inventory_hierarchical_location
104#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:65
105#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:79
106#, python-format
107msgid "Some Sub-inventories are not confirmed."
108msgstr "Au moins un sous-inventaire n'est pas confirmé."
109
110#. module: stock_inventory_hierarchical_location
111#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:84
112#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:98
113#, python-format
114msgid "This location is not declared on the parent inventory\n"
115"It cannot be added."
116msgstr "Cet emplacement n'est pas déclaré dans l'inventaire parent\n"
117"Vous ne pouvez pas l'ajouter."
118
119#. module: stock_inventory_hierarchical_location
120#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:42
121#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:64
122#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:78
123#, python-format
124msgid "Warning"
125msgstr "Attention"
126
127#. module: stock_inventory_hierarchical_location
128#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84
129#, python-format
130msgid "Warning!"
131msgstr "Attention!"
132
133#. module: stock_inventory_hierarchical_location
134#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:83
135#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:97
136#, python-format
137msgid "Warning: Wrong location"
138msgstr "Attention: emplacement incorrect"
139
140#. module: stock_inventory_hierarchical_location
141#: help:stock.generate.inventory,level:0
142msgid "Maximum number of intermediate sub-inventories between the main inventory and the smallest sub-inventory."
143msgstr "Nombre maximum de niveaux entre l'inventaire principal et le plus petit sous-inventaire."
144
145#. module: stock_inventory_hierarchical_location
146#: view:stock.inventory:0
147msgid "onchange_location_id(location_id)"
148msgstr "onchange_location_id(location_id)"
149
150#. module: stock_inventory_hierarchical_location
151#: view:stock.generate.inventory:0
152msgid "or"
153msgstr "ou"
154
155#. module: stock_inventory_hierarchical_location
156#: view:stock.inventory:0
157msgid "{'default_parent_id': active_id, 'default_exhaustive': exhaustive}"
158msgstr "{'default_parent_id': active_id, 'default_exhaustive': exhaustive}"
159
160#. module: stock_inventory_hierarchical_location
161#: view:stock.inventory:0
162msgid "{'readonly':[('parent_id', '!=', False)]}"
163msgstr "{'readonly':[('parent_id', '!=', False)]}"
164
0165
=== added file 'stock_inventory_hierarchical_location/i18n/stock_inventory_hierarchical_location.pot'
--- stock_inventory_hierarchical_location/i18n/stock_inventory_hierarchical_location.pot 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/i18n/stock_inventory_hierarchical_location.pot 2014-07-01 11:47:18 +0000
@@ -0,0 +1,166 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * stock_inventory_hierarchical_location
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2014-07-01 11:32+0000\n"
10"PO-Revision-Date: 2014-07-01 11:32+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: stock_inventory_hierarchical_location
19#: view:stock.generate.inventory:0
20msgid "Cancel"
21msgstr ""
22
23#. module: stock_inventory_hierarchical_location
24#: code:_description:0
25#: model:ir.actions.act_window,name:stock_inventory_hierarchical_location.action_view_stock_generate_inventory
26#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_generate_inventory
27#: model:ir.ui.menu,name:stock_inventory_hierarchical_location.menu_action_stock_generate_inventory_form
28#: view:stock.generate.inventory:0
29#, python-format
30msgid "Generate Inventory"
31msgstr ""
32
33#. module: stock_inventory_hierarchical_location
34#: view:stock.generate.inventory:0
35msgid "Generate inventory"
36msgstr ""
37
38#. module: stock_inventory_hierarchical_location
39#: help:stock.generate.inventory,only_view:0
40msgid "If set, only inventory on view location can be created"
41msgstr ""
42
43#. module: stock_inventory_hierarchical_location
44#: code:_description:0
45#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_fill_inventory
46#, python-format
47msgid "Import Inventory"
48msgstr ""
49
50#. module: stock_inventory_hierarchical_location
51#: code:_description:0
52#: model:ir.model,name:stock_inventory_hierarchical_location.model_stock_inventory
53#, python-format
54msgid "Inventory"
55msgstr ""
56
57#. module: stock_inventory_hierarchical_location
58#: code:addons/stock_inventory_hierarchical_location/wizard/generate_inventory.py:124
59#, python-format
60msgid "Inventory generated"
61msgstr ""
62
63#. module: stock_inventory_hierarchical_location
64#: field:stock.generate.inventory,prefix_inv_name:0
65msgid "Inventory prefix"
66msgstr ""
67
68#. module: stock_inventory_hierarchical_location
69#: field:stock.generate.inventory,level:0
70msgid "Level"
71msgstr ""
72
73#. module: stock_inventory_hierarchical_location
74#: sql_constraint:stock.generate.inventory:0
75msgid "Level must be positive!"
76msgstr ""
77
78#. module: stock_inventory_hierarchical_location
79#: field:stock.generate.inventory,location_id:0
80msgid "Location"
81msgstr ""
82
83#. module: stock_inventory_hierarchical_location
84#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:78
85#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84
86#, python-format
87msgid "No product in this location. Please select a location in the product form."
88msgstr ""
89
90#. module: stock_inventory_hierarchical_location
91#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:43
92#, python-format
93msgid "One of the parent inventories is not open."
94msgstr ""
95
96#. module: stock_inventory_hierarchical_location
97#: field:stock.generate.inventory,only_view:0
98msgid "Only view"
99msgstr ""
100
101#. module: stock_inventory_hierarchical_location
102#: help:stock.generate.inventory,prefix_inv_name:0
103msgid "Optional prefix for all created inventory"
104msgstr ""
105
106#. module: stock_inventory_hierarchical_location
107#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:65
108#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:79
109#, python-format
110msgid "Some Sub-inventories are not confirmed."
111msgstr ""
112
113#. module: stock_inventory_hierarchical_location
114#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:84
115#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:98
116#, python-format
117msgid "This location is not declared on the parent inventory\n"
118"It cannot be added."
119msgstr ""
120
121#. module: stock_inventory_hierarchical_location
122#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:42
123#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:64
124#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:78
125#, python-format
126msgid "Warning"
127msgstr ""
128
129#. module: stock_inventory_hierarchical_location
130#: code:addons/stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py:84
131#, python-format
132msgid "Warning!"
133msgstr ""
134
135#. module: stock_inventory_hierarchical_location
136#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:83
137#: code:addons/stock_inventory_hierarchical_location/inventory_hierarchical_location.py:97
138#, python-format
139msgid "Warning: Wrong location"
140msgstr ""
141
142#. module: stock_inventory_hierarchical_location
143#: help:stock.generate.inventory,level:0
144msgid "Maximum number of intermediate sub-inventories between the main inventory and the smallest sub-inventory."
145msgstr ""
146
147#. module: stock_inventory_hierarchical_location
148#: view:stock.inventory:0
149msgid "onchange_location_id(location_id)"
150msgstr ""
151
152#. module: stock_inventory_hierarchical_location
153#: view:stock.generate.inventory:0
154msgid "or"
155msgstr ""
156
157#. module: stock_inventory_hierarchical_location
158#: view:stock.inventory:0
159msgid "{'default_parent_id': active_id, 'default_exhaustive': exhaustive}"
160msgstr ""
161
162#. module: stock_inventory_hierarchical_location
163#: view:stock.inventory:0
164msgid "{'readonly':[('parent_id', '!=', False)]}"
165msgstr ""
166
0167
=== added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location.py'
--- stock_inventory_hierarchical_location/inventory_hierarchical_location.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/inventory_hierarchical_location.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,102 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21from openerp.osv import orm
22from openerp.tools.translate import _
23
24from stock_inventory_hierarchical import HierarchicalInventoryException
25
26# Add the date to the list of fields we must propagate to children inventories
27from stock_inventory_hierarchical import PARENT_VALUES
28PARENT_VALUES.append('exhaustive')
29
30
31class HierarchicalExhInventory(orm.Model):
32 """Add hierarchical structure features to exhaustive Inventories"""
33 _inherit = 'stock.inventory'
34
35 def action_open(self, cr, uid, ids, context=None):
36 """Open only if all the parents are Open."""
37 for inventory in self.browse(cr, uid, ids, context=context):
38 while inventory.parent_id:
39 inventory = inventory.parent_id
40 if inventory.state != 'open':
41 raise HierarchicalInventoryException(
42 _('Warning'),
43 _('One of the parent inventories is not open.'))
44 return super(HierarchicalExhInventory, self).action_open(
45 cr, uid, ids, context=context)
46
47 def get_missing_locations(self, cr, uid, ids, context=None):
48 """Extend the list of inventories with their children"""
49 ids = self.search(
50 cr, uid, [('parent_id', 'child_of', ids)], context=context)
51 missing_ids = super(HierarchicalExhInventory,
52 self).get_missing_locations(
53 cr, uid, ids, context=context)
54 # Find the locations already included in sub-inventories
55 inventories = self.browse(cr, uid, ids, context=context)
56 subinv_location_ids = [sub.location_id.id
57 for i in inventories
58 for sub in i.inventory_ids]
59 if not subinv_location_ids:
60 return missing_ids
61 # Extend to the children locations
62 subinv_location_ids = set(self.pool['stock.location'].search(
63 cr, uid, [
64 ('location_id', 'child_of', subinv_location_ids),
65 ('usage', '=', 'internal')], context=context))
66 return list(set(missing_ids) - subinv_location_ids)
67
68 # TODO v8: probably only keep the state "done"
69 def confirm_missing_locations(self, cr, uid, ids, context=None):
70 """Do something only if children state are confirm or done."""
71 children_count = self.search(
72 cr, uid, [('parent_id', 'child_of', ids),
73 ('id', 'not in', ids),
74 ('state', 'not in', ['confirm', 'done'])],
75 context=context, count=True)
76 if children_count > 0:
77 raise HierarchicalInventoryException(
78 _('Warning'),
79 _('Some Sub-inventories are not confirmed.'))
80 return super(HierarchicalExhInventory,
81 self).confirm_missing_locations(
82 cr, uid, ids, context=context)
83
84 def onchange_location_id(self, cr, uid, ids, location_id, context=None):
85 """Check if location is a child of parent inventory location"""
86 loc_obj = self.pool['stock.location']
87 for inventory in self.browse(cr, uid, ids, context=context):
88 if inventory.parent_id:
89 allowed_location_ids = loc_obj.search(
90 cr, uid, [('location_id', 'child_of',
91 inventory.parent_id.location_id.id)],
92 context=context)
93 if location_id not in allowed_location_ids:
94 return {
95 'location_id': False,
96 'warning': {
97 'title': _('Warning: Wrong location'),
98 'message': _("This location is not declared on "
99 "the parent inventory\n"
100 "It cannot be added.")}
101 }
102 return {}
0103
=== added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml'
--- stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/inventory_hierarchical_location_demo.xml 2014-07-01 11:47:18 +0000
@@ -0,0 +1,28 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data noupdate="0">
4
5 <!-- Record inventories we can use in the tests. -->
6 <!-- We need them in the demo data because test data is rolled back
7 whenever an exception is raised. -->
8
9 <!-- Record a hierarchical exhaustive inventory -->
10 <record id="parent_inventory" model="stock.inventory">
11 <field name="name">Hierarchical exhaustive inventory</field>
12 <field name="state">draft</field>
13 <field name="date">2020-04-15 00:00:00</field>
14 <field name="exhaustive">True</field>
15 <field name="location_id" model="stock.location" ref="stock.stock_location_stock"/>
16 </record>
17 <record id="child_1_id" model="stock.inventory">
18 <field name="name">Team A</field>
19 <field name="parent_id" ref="parent_inventory"/>
20 <field name="location_id" model="stock.location" ref="stock.stock_location_14"/>
21 </record>
22 <record id="child_2_id" model="stock.inventory">
23 <field name="name">Team B</field>
24 <field name="parent_id" ref="parent_inventory"/>
25 <field name="location_id" model="stock.location" ref="stock.stock_location_components"/>
26 </record>
27 </data>
28</openerp>
029
=== added file 'stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml'
--- stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/inventory_hierarchical_location_view.xml 2014-07-01 11:47:18 +0000
@@ -0,0 +1,37 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <record model="ir.ui.view" id="stock_inventory_hierarchical_location_form_view">
5 <field name="name">hierarchical.inventory.location.form</field>
6 <field name="model">stock.inventory</field>
7 <field name="inherit_id" ref="stock.view_inventory_form" />
8 <field name="arch" type="xml">
9
10 <xpath expr="/form//field[@name='exhaustive']" position="attributes">
11 <attribute name="attrs">{'readonly':[('parent_id', '!=', False)]}</attribute>
12 </xpath>
13
14 <xpath expr="/form//field[@name='location_id']" position="attributes">
15 <attribute name="on_change">onchange_location_id(location_id)</attribute>
16 </xpath>
17
18 </field>
19 </record>
20
21 <record model="ir.ui.view" id="stock_ihl_exhautive_form_view">
22 <field name="name">hierarchical.inventory.location.exhautive.form</field>
23 <field name="model">stock.inventory</field>
24 <field name="inherit_id" ref="stock_inventory_hierarchical.stock_inventory_hierarchical_form_view" />
25 <field name="arch" type="xml">
26 <xpath expr="//field[@name='inventory_ids']" position="attributes">
27 <attribute name="context">{'default_parent_id': active_id, 'default_exhaustive': exhaustive}</attribute>
28 </xpath>
29 </field>
30 </record>
31
32 <!-- Show hierarchical exhaustive inventories by default -->
33 <record id="stock.action_inventory_form" model="ir.actions.act_window">
34 <field name="context">{'full':'1', 'search_default_exhaustive':1, 'search_default_main_inventories':1}</field>
35 </record>
36 </data>
37</openerp>
038
=== added directory 'stock_inventory_hierarchical_location/static'
=== added directory 'stock_inventory_hierarchical_location/static/src'
=== added directory 'stock_inventory_hierarchical_location/static/src/img'
=== added file 'stock_inventory_hierarchical_location/static/src/img/icon.png'
1Binary 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 differ39Binary 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
=== added directory 'stock_inventory_hierarchical_location/tests'
=== added file 'stock_inventory_hierarchical_location/tests/__init__.py'
--- stock_inventory_hierarchical_location/tests/__init__.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/tests/__init__.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,39 @@
1# -*- coding: utf-8 -*-
2#
3#
4# Authors: Laetitia Gangloff
5# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
6# All Rights Reserved
7#
8# WARNING: This program as such is intended to be used by professional
9# programmers who take the whole responsibility of assessing all potential
10# consequences resulting from its eventual inadequacies and bugs.
11# End users who are looking for a ready-to-use solution with commercial
12# guarantees and support are strongly advised to contact a Free Software
13# Service Company.
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU Affero General Public License as
17# published by the Free Software Foundation, either version 3 of the
18# License, or (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU Affero General Public License for more details.
24#
25# You should have received a copy of the GNU Affero General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27#
28#
29
30import fill_inventory_test
31
32fast_suite = [
33]
34
35checks = [
36 fill_inventory_test,
37]
38
39# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
040
=== added file 'stock_inventory_hierarchical_location/tests/fill_inventory_test.py'
--- stock_inventory_hierarchical_location/tests/fill_inventory_test.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/tests/fill_inventory_test.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,118 @@
1# -*- coding: utf-8 -*-
2#
3#
4# Authors: Laetitia Gangloff
5# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
6# All Rights Reserved
7#
8# WARNING: This program as such is intended to be used by professional
9# programmers who take the whole responsibility of assessing all potential
10# consequences resulting from its eventual inadequacies and bugs.
11# End users who are looking for a ready-to-use solution with commercial
12# guarantees and support are strongly advised to contact a Free Software
13# Service Company.
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU Affero General Public License as
17# published by the Free Software Foundation, either version 3 of the
18# License, or (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU Affero General Public License for more details.
24#
25# You should have received a copy of the GNU Affero General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27#
28#
29
30import openerp.tests.common as common
31
32DB = common.DB
33ADMIN_USER_ID = common.ADMIN_USER_ID
34
35
36class fill_inventory_test(common.TransactionCase):
37
38 def setUp(self):
39 super(fill_inventory_test, self).setUp()
40
41 def test_missing_location(self):
42 """
43 Test that when confirm a parent inventory, the child location are not in the confirmation result
44 """
45 parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory')
46 self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id])
47 # confirm shelf 1 inventory
48 inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id')
49 self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
50 missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
51 self.assertEqual(len(missing_location), 1, "1 missing location should be find, because the inventory is empty")
52 wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]})
53 self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]})
54 missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
55 self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is confirmed")
56 # confirm shelf 2 inventory
57 inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id')
58 self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
59 missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
60 self.assertEqual(len(missing_location), 1, "1 missing location should be fine, because the inventory is empty")
61 self.registry('stock.inventory.line').create(self.cr, self.uid, {'product_id': self.ref('product.product_product_7'),
62 'product_uom': self.ref('product.product_uom_unit'),
63 'company_id': self.ref('base.main_company'),
64 'inventory_id': inventory_id,
65 'product_qty': 18.0,
66 'location_id': self.ref('stock.stock_location_14')})
67 missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [inventory_id])
68 self.assertEqual(len(missing_location), 0, "No missing location should be find, because the inventory is filled")
69 wizard_id = self.registry('stock.inventory.uninventoried.locations').create(self.cr, self.uid, {}, context={'active_ids': [inventory_id]})
70 wizard = self.registry('stock.inventory.uninventoried.locations').browse(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]})
71 self.assertEqual(len(wizard.location_ids), 0, "The wizard should not contain any lines but contains %s." % wizard.location_ids)
72 self.registry('stock.inventory.uninventoried.locations').confirm_uninventoried_locations(self.cr, self.uid, wizard_id, context={'active_ids': [inventory_id]})
73 # confirm parent inventory
74 missing_location = self.registry('stock.inventory').get_missing_locations(self.cr, self.uid, [parent_inventory_id])
75 self.assertEqual(len(missing_location), 1, "Only 1 missing location should be find, because there is some location in child inventory")
76
77 def test_fill_inventory(self):
78 """
79 Test that when fill a parent inventory, the child location are not in the result
80 """
81 parent_inventory_id = self.ref('stock_inventory_hierarchical_location.parent_inventory')
82 self.registry('stock.inventory').action_open(self.cr, self.uid, [parent_inventory_id])
83 # confirm shelf 1 inventory
84 inventory_id = self.ref('stock_inventory_hierarchical_location.child_2_id')
85 self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
86 wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_components'),
87 'recursive': True,
88 'exhaustive': True,
89 'set_stock_zero': True}, context={'active_ids': [inventory_id]})
90 self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]})
91 inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)])
92 self.assertEqual(len(inventory_line_ids), 12, "12 inventory line is fount after filling inventory")
93 # confirm shelf 2 inventory
94 inventory_id = self.ref('stock_inventory_hierarchical_location.child_1_id')
95 self.registry('stock.inventory').action_open(self.cr, self.uid, [inventory_id])
96 wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_14'),
97 'recursive': True,
98 'exhaustive': True,
99 'set_stock_zero': True}, context={'active_ids': [inventory_id]})
100 self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [inventory_id]})
101 inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', inventory_id)])
102 self.assertEqual(len(inventory_line_ids), 4, "1 inventory line is fount after filling inventory")
103 # confirm parent inventory
104 wizard_id = self.registry('stock.fill.inventory').create(self.cr, self.uid, {'location_id': self.ref('stock.stock_location_stock'),
105 'recursive': True,
106 'exhaustive': True,
107 'set_stock_zero': True}, context={'active_ids': [parent_inventory_id]})
108 try:
109 self.registry('stock.fill.inventory').fill_inventory(self.cr, self.uid, [wizard_id], context={'active_ids': [parent_inventory_id]})
110 except Exception, e:
111 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.''")
112 exception_happened = True
113 pass
114 self.assertTrue(exception_happened)
115 inventory_line_ids = self.registry('stock.inventory.line').search(self.cr, self.uid, [('inventory_id', '=', parent_inventory_id)])
116 self.assertEqual(len(inventory_line_ids), 0, "No inventory line is fount after filling inventory")
117
118# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0119
=== added file 'stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml'
--- stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/tests/inventory_hierarchical_location_test.yml 2014-07-01 11:47:18 +0000
@@ -0,0 +1,56 @@
1-
2 Check that the exhaustive field of parent inventory has been propagated to children.
3-
4 !python {model: stock.inventory}: |
5 exhaustive = self.read(cr, uid, [ref("child_1_id")], ['exhaustive'])[0]['exhaustive']
6 assert exhaustive, "Exhaustive field not propagated to child inventory"
7
8-
9 Check that I can't open child inventory while parent inventory is open.
10-
11 !python {model: stock.inventory}: |
12 from stock_inventory_hierarchical import HierarchicalInventoryException
13 parent_state = self.read(cr, uid, [ref("parent_inventory")], ['state'])[0]['state']
14 assert parent_state == 'draft', "Parent inventory in state '%s'. It should be 'draft'" % parent_state
15 try:
16 self.action_open(cr, uid, [ref("child_1_id")])
17 except HierarchicalInventoryException as e:
18 log("Good ! The Inventory could not be opened: %s" % e)
19 child_1_state = self.read(cr, uid, [ref("child_1_id")], ['state'])[0]['state']
20 assert child_1_state == 'draft', "Child inventory 1 have '%s' state. It should be 'draft'" % child_1_state
21
22-
23 I will check that the function get_missing_locations return some locations.
24-
25 !python {model: stock.inventory}: |
26 missing_loc_ids = self.get_missing_locations(cr, uid, [ref('parent_inventory')], context=context)
27 assert len(missing_loc_ids)==3, "get_missing_locations did not return any ID."
28
29-
30 I will fill the inventory and check that the function get_missing_locations return no locations.
31 Adding 17” LCD Monitor.
32-
33 !record {model: stock.inventory.line, id: lines_inventory_location_pc1}:
34 product_id: product.product_product_7
35 product_uom: product.product_uom_unit
36 company_id: base.main_company
37 inventory_id: child_1_id
38 product_qty: 18.0
39 location_id: stock.stock_location_14
40
41-
42 Adding USB Keyboard, QWERTY.
43-
44 !record {model: stock.inventory.line, id: lines_inventory_location_pc3}:
45 product_id: product.product_product_8
46 product_uom: product.product_uom_unit
47 company_id: base.main_company
48 inventory_id: child_2_id
49 product_qty: 5.0
50 location_id: stock.stock_location_components
51
52-
53 !python {model: stock.inventory}: |
54
55 missing_loc_ids = self.get_missing_locations(cr, uid, [ref('parent_inventory')], context=context)
56 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)
057
=== added directory 'stock_inventory_hierarchical_location/wizard'
=== added file 'stock_inventory_hierarchical_location/wizard/__init__.py'
--- stock_inventory_hierarchical_location/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/wizard/__init__.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,22 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# This module is copyright (C) 2013 Numérigraphe SARL. All Rights Reserved.
5#
6# This program is free software: you can redistribute it and/or modify
7# it under the terms of the GNU General Public License as published by
8# the Free Software Foundation, either version 3 of the License, or
9# (at your option) any later version.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14# GNU General Public License for more details.
15#
16# You should have received a copy of the GNU General Public License
17# along with this program. If not, see <http://www.gnu.org/licenses/>.
18#
19##############################################################################
20
21from . import stock_fill_location_inventory
22from . import generate_inventory
023
=== added file 'stock_inventory_hierarchical_location/wizard/generate_inventory.py'
--- stock_inventory_hierarchical_location/wizard/generate_inventory.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/wizard/generate_inventory.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,134 @@
1# -*- coding: utf-8 -*-
2#
3#
4# Authors: Laetitia Gangloff
5# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
6# All Rights Reserved
7#
8# WARNING: This program as such is intended to be used by professional
9# programmers who take the whole responsibility of assessing all potential
10# consequences resulting from its eventual inadequacies and bugs.
11# End users who are looking for a ready-to-use solution with commercial
12# guarantees and support are strongly advised to contact a Free Software
13# Service Company.
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU Affero General Public License as
17# published by the Free Software Foundation, either version 3 of the
18# License, or (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU Affero General Public License for more details.
24#
25# You should have received a copy of the GNU Affero General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27#
28#
29
30from openerp.osv import fields, orm
31from openerp.tools.translate import _
32
33
34class GenerateInventoryWizard(orm.TransientModel):
35 """ This wizard generate an inventory and all related sub-inventories for the specified location and level
36 Example: location = Stock / level = 1 => 1 inventory on Stock (similar to create)
37 location = Stock / level = 2 => 1 inventory on Stock, 1 sub-inventory on Shelf1, 1 sub-inventory on Shelf2
38 """
39
40 _name = "stock.generate.inventory"
41 _description = "Generate Inventory"
42
43 _columns = {
44 'prefix_inv_name': fields.char('Inventory prefix', help="Optional prefix for all created inventory"),
45 'location_id': fields.many2one('stock.location', 'Location', required=True),
46 'level': fields.integer("Level", help="Maximum number of intermediate sub-inventories between the main inventory and the smallest sub-inventory."),
47 'only_view': fields.boolean('Only view', help="If set, only inventory on view location can be created"),
48 }
49
50 def _default_location(self, cr, uid, ids, context=None):
51 """Default stock location
52
53 @return: id of the stock location of the first warehouse of the
54 default company"""
55 location_id = False
56 company_id = self.pool['res.company']._company_default_get(
57 cr, uid, 'stock.warehouse', context=context)
58 warehouse_id = self.pool['stock.warehouse'].search(
59 cr, uid, [('company_id', '=', company_id)], limit=1)
60 if warehouse_id:
61 location_id = self.pool['stock.warehouse'].read(
62 cr, uid, warehouse_id[0], ['lot_stock_id'])['lot_stock_id'][0]
63 return location_id
64
65 _defaults = {
66 'location_id': _default_location,
67 'level': 1,
68 'only_view': True,
69 }
70
71 _sql_constraints = [
72 ('level', 'CHECK (level>0)', 'Level must be positive!'),
73 ]
74
75 def _create_subinventory(self, cr, uid, inventory_ids, prefix_inv_name, only_view, context):
76 new_inventory_ids = []
77 for inventory_id in inventory_ids:
78 location_id = self.pool['stock.inventory'].read(cr, uid, inventory_id, ['location_id'], context=context)['location_id'][0]
79 domain = [('location_id', '=', location_id)]
80 if only_view:
81 domain.append(('usage', '=', 'view'))
82 location_ids = self.pool['stock.location'].search(cr, uid, domain, context=context)
83 for location_id in location_ids:
84 location_name = self.pool['stock.location'].read(cr, uid, location_id, ['name'], context=context)['name']
85 new_inventory_ids.append(self.pool['stock.inventory'].create(cr, uid, {'name': prefix_inv_name + location_name,
86 'exhaustive': True,
87 'location_id': location_id,
88 'parent_id': inventory_id}, context=context))
89 return new_inventory_ids
90
91 def generate_inventory(self, cr, uid, ids, context=None):
92 """ Generate inventory and sub-inventories for specified location and level
93
94 @param self: The object pointer.
95 @param cr: A database cursor
96 @param uid: ID of the user currently logged in
97 @param ids: the ID or list of IDs if we want more than one
98 @param context: A standard dictionary
99 @return:
100 """
101 if context is None:
102 context = {}
103
104 if ids and len(ids):
105 ids = ids[0]
106 else:
107 return {'type': 'ir.actions.act_window_close'}
108 generate_inventory = self.browse(cr, uid, ids, context=context)
109 # create first level inventory
110 prefix_inv_name = generate_inventory.prefix_inv_name or ''
111 location_id = generate_inventory.location_id.id
112 only_view = generate_inventory.only_view
113 parent_inventory_id = self.pool['stock.inventory'].create(cr, uid, {'name': prefix_inv_name + generate_inventory.location_id.name,
114 'exhaustive': True,
115 'location_id': location_id}, context=context)
116
117 inventory_ids = [parent_inventory_id]
118 for i in range(1, generate_inventory.level):
119 inventory_ids = self._create_subinventory(cr, uid, inventory_ids, prefix_inv_name, only_view, context)
120
121 mod_obj = self.pool['ir.model.data']
122 result = mod_obj.get_object_reference(cr, uid, 'stock', 'view_inventory_form')
123 view_id = result and result[1] or False
124 return {'name': _('Inventory generated'),
125 'view_mode': 'form',
126 'view_type': 'form',
127 'res_model': 'stock.inventory',
128 'type': 'ir.actions.act_window',
129 'view_id': view_id,
130 'res_id': int(parent_inventory_id),
131 }
132
133
134# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0135
=== added file 'stock_inventory_hierarchical_location/wizard/generate_inventory_view.xml'
--- stock_inventory_hierarchical_location/wizard/generate_inventory_view.xml 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/wizard/generate_inventory_view.xml 2014-07-01 11:47:18 +0000
@@ -0,0 +1,42 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4 <record id="view_stock_generate_inventory" model="ir.ui.view">
5 <field name="name">Generate Inventory</field>
6 <field name="model">stock.generate.inventory</field>
7 <field name="arch" type="xml">
8 <form string="Generate Inventory" version="7.0">
9 <separator string="Generate Inventory"/>
10 <group>
11 <field name="prefix_inv_name"/>
12 <field name="location_id"/>
13 <field name="only_view"/>
14 <field name="level"/>
15 </group>
16 <footer>
17 <button name="generate_inventory" string="Generate Inventory" type="object" class="oe_highlight"/>
18 or
19 <button string="Cancel" class="oe_link" special="cancel" />
20 </footer>
21 </form>
22 </field>
23 </record>
24
25 <record id="action_view_stock_generate_inventory" model="ir.actions.act_window">
26 <field name="name">Generate Inventory</field>
27 <field name="type">ir.actions.act_window</field>
28 <field name="res_model">stock.generate.inventory</field>
29 <field name="view_type">form</field>
30 <field name="view_mode">form</field>
31 <field name="view_id" ref="view_stock_generate_inventory"/>
32 <field name="target">new</field>
33 </record>
34
35 <menuitem action="action_view_stock_generate_inventory"
36 id="menu_action_stock_generate_inventory_form"
37 parent="stock.menu_stock_inventory_control"
38 sequence="20"
39 groups="stock.group_locations"/>
40
41 </data>
42</openerp>
043
=== added file 'stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py'
--- stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 1970-01-01 00:00:00 +0000
+++ stock_inventory_hierarchical_location/wizard/stock_fill_location_inventory.py 2014-07-01 11:47:18 +0000
@@ -0,0 +1,89 @@
1# -*- coding: utf-8 -*-
2#
3#
4# Authors: Laetitia Gangloff
5# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu)
6# All Rights Reserved
7#
8# WARNING: This program as such is intended to be used by professional
9# programmers who take the whole responsibility of assessing all potential
10# consequences resulting from its eventual inadequacies and bugs.
11# End users who are looking for a ready-to-use solution with commercial
12# guarantees and support are strongly advised to contact a Free Software
13# Service Company.
14#
15# This program is free software: you can redistribute it and/or modify
16# it under the terms of the GNU Affero General Public License as
17# published by the Free Software Foundation, either version 3 of the
18# License, or (at your option) any later version.
19#
20# This program is distributed in the hope that it will be useful,
21# but WITHOUT ANY WARRANTY; without even the implied warranty of
22# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23# GNU Affero General Public License for more details.
24#
25# You should have received a copy of the GNU Affero General Public License
26# along with this program. If not, see <http://www.gnu.org/licenses/>.
27#
28#
29
30from openerp.osv import orm, osv
31from openerp.tools.translate import _
32
33
34class FillInventoryWizard(orm.TransientModel):
35 """If inventory as sub inventories, do not fill with sub inventories location"""
36 _inherit = 'stock.fill.inventory'
37
38 def fill_inventory(self, cr, uid, ids, context=None):
39 """ To Import stock inventory according to products available in the location and not already in a sub inventory
40
41 We split fill_inventory on many fill_inventory (one for each location)
42 @param self: The object pointer.
43 @param cr: A database cursor
44 @param uid: ID of the user currently logged in
45 @param ids: the ID or list of IDs if we want more than one
46 @param context: A standard dictionary
47 @return:
48 """
49 if context is None:
50 context = {}
51
52 if ids and len(ids):
53 ids = ids[0]
54 else:
55 return {'type': 'ir.actions.act_window_close'}
56 fill_inventory = self.browse(cr, uid, ids, context=context)
57 if fill_inventory.recursive and fill_inventory.exhaustive:
58 exclude_location_ids = []
59 for i in self.pool['stock.inventory'].browse(cr, uid, context['active_ids']):
60 for sub_inventory in i.inventory_ids:
61 # exclude these location
62 exclude_location_ids.append(sub_inventory.location_id.id)
63 domain = [('location_id', 'child_of', [fill_inventory.location_id.id])]
64 if exclude_location_ids:
65 domain.append('!')
66 domain.append(('location_id', 'child_of', exclude_location_ids))
67 location_ids = self.pool['stock.location'].search(cr, uid, domain,
68 order="id",
69 context=context)
70 all_in_exception = 0
71 for location_id in location_ids:
72 try:
73 super(FillInventoryWizard, self).fill_inventory(cr, uid,
74 [self.copy(cr, uid, ids, {'location_id': location_id,
75 'recursive': False, }, context=context)],
76 context=context)
77 except osv.except_osv, e:
78 if e.value == _('No product in this location. Please select a location in the product form.'):
79 all_in_exception = all_in_exception + 1
80 pass
81 else:
82 raise e
83 if all_in_exception == len(location_ids):
84 raise osv.except_osv(_('Warning!'), _('No product in this location. Please select a location in the product form.'))
85 return {'type': 'ir.actions.act_window_close'}
86 else:
87 return super(FillInventoryWizard, self).fill_inventory(cr, uid, [ids], context=context)
88
89# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: