Merge lp:~numerigraphe-team/stock-logistic-warehouse/7.0-add-stock-available into lp:stock-logistic-warehouse
- 7.0-add-stock-available
- Merge into 7.0
Status: | Rejected |
---|---|
Rejected by: | Pedro Manuel Baeza |
Proposed branch: | lp:~numerigraphe-team/stock-logistic-warehouse/7.0-add-stock-available |
Merge into: | lp:stock-logistic-warehouse |
Diff against target: |
549 lines (+299/-129) 10 files modified
configurable_stock_level/product.py (+1/-1) stock_available/__init__.py (+24/-0) stock_available/__openerp__.py (+42/-0) stock_available/product.py (+125/-0) stock_available/product_view.xml (+15/-13) stock_available/res_config.py (+34/-0) stock_available/res_config_view.xml (+25/-0) stock_available_immediately/__openerp__.py (+18/-13) stock_available_immediately/product.py (+14/-101) stock_inventory_existing_lines/stock.py (+1/-1) |
To merge this branch: | bzr merge lp:~numerigraphe-team/stock-logistic-warehouse/7.0-add-stock-available |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alexandre Fayolle - camptocamp | Needs Resubmitting | ||
Sébastien BEAU - http://www.akretion.com | Pending | ||
Guewen Baconnier @ Camptocamp | Pending | ||
Laurent Mignon (Acsone) | Pending | ||
Review via email: mp+220758@code.launchpad.net |
Commit message
Description of the change
Add a generic module to compute the stock quantity available to promise using several implementations and make stock_available
stock_available
The field name "immediately_
By default function fields are not very modular (you need to redefine the whole field to override the method). stock_available takes care of this by making the function fields call the pool instead, so that stock_available
The new module also has a context trick that lets it return the value of the stock available to promise in the field "virtual stock". This lets future sub-modules change the behavior of modules that were written to use the virtual stock, to use the new value instead with minimal impact.
Module Co-authored by Loïc Bellier and your humble servant.
- 36. By Numérigraphe
-
[IMP] Change category to 'warehouse'
- 37. By Numérigraphe
-
[MERGE] merge an unrelated fix regarding the UoM precision, to avoid conflicts
Alexandre Fayolle - camptocamp (alexandre-fayolle-c2c) wrote : | # |
Lionel Sausin - Initiatives/Numérigraphe (ls-initiatives) wrote : | # |
I'm migrating this to github, please mark "refused".
Unmerged revisions
- 37. By Numérigraphe
-
[MERGE] merge an unrelated fix regarding the UoM precision, to avoid conflicts
- 36. By Numérigraphe
-
[IMP] Change category to 'warehouse'
- 35. By Numérigraphe
-
[ADD] stock_available: generic module to compute the stock quantity available to promise using several implementations. Make stock_available
_immediatly the first configurable implementation
Preview Diff
1 | === modified file 'configurable_stock_level/product.py' | |||
2 | --- configurable_stock_level/product.py 2012-04-04 11:20:48 +0000 | |||
3 | +++ configurable_stock_level/product.py 2014-06-20 09:38:06 +0000 | |||
4 | @@ -48,7 +48,7 @@ | |||
5 | 48 | 48 | ||
6 | 49 | _columns = {'configurable_stock_level': fields.function(_compute_configurable_level, | 49 | _columns = {'configurable_stock_level': fields.function(_compute_configurable_level, |
7 | 50 | type='float', | 50 | type='float', |
9 | 51 | digits_compute=dp.get_precision('Product UoM'), | 51 | digits_compute=dp.get_precision('Product Unit of Measure'), |
10 | 52 | string='Custom level')} | 52 | string='Custom level')} |
11 | 53 | 53 | ||
12 | 54 | 54 | ||
13 | 55 | 55 | ||
14 | === added directory 'stock_available' | |||
15 | === added file 'stock_available/__init__.py' | |||
16 | --- stock_available/__init__.py 1970-01-01 00:00:00 +0000 | |||
17 | +++ stock_available/__init__.py 2014-06-20 09:38:06 +0000 | |||
18 | @@ -0,0 +1,24 @@ | |||
19 | 1 | # -*- coding: utf-8 -*- | ||
20 | 2 | ############################################################################## | ||
21 | 3 | # | ||
22 | 4 | # This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved. | ||
23 | 5 | # | ||
24 | 6 | # This program is free software: you can redistribute it and/or modify | ||
25 | 7 | # it under the terms of the GNU Affero General Public License as | ||
26 | 8 | # published by the Free Software Foundation, either version 3 of the | ||
27 | 9 | # License, or (at your option) any later version. | ||
28 | 10 | # | ||
29 | 11 | # This program is distributed in the hope that it will be useful, | ||
30 | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
31 | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
32 | 14 | # GNU Affero General Public License for more details. | ||
33 | 15 | # | ||
34 | 16 | # You should have received a copy of the GNU Affero General Public License | ||
35 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
36 | 18 | # | ||
37 | 19 | ############################################################################## | ||
38 | 20 | |||
39 | 21 | from . import product | ||
40 | 22 | from . import res_config | ||
41 | 23 | |||
42 | 24 | from .product import _product_available_fnct | ||
43 | 0 | 25 | ||
44 | === added file 'stock_available/__openerp__.py' | |||
45 | --- stock_available/__openerp__.py 1970-01-01 00:00:00 +0000 | |||
46 | +++ stock_available/__openerp__.py 2014-06-20 09:38:06 +0000 | |||
47 | @@ -0,0 +1,42 @@ | |||
48 | 1 | # -*- coding: utf-8 -*- | ||
49 | 2 | ############################################################################## | ||
50 | 3 | # | ||
51 | 4 | # This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved. | ||
52 | 5 | # | ||
53 | 6 | # This program is free software: you can redistribute it and/or modify | ||
54 | 7 | # it under the terms of the GNU Affero General Public License as | ||
55 | 8 | # published by the Free Software Foundation, either version 3 of the | ||
56 | 9 | # License, or (at your option) any later version. | ||
57 | 10 | # | ||
58 | 11 | # This program is distributed in the hope that it will be useful, | ||
59 | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
60 | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
61 | 14 | # GNU Affero General Public License for more details. | ||
62 | 15 | # | ||
63 | 16 | # You should have received a copy of the GNU Affero General Public License | ||
64 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
65 | 18 | # | ||
66 | 19 | ############################################################################## | ||
67 | 20 | |||
68 | 21 | { | ||
69 | 22 | 'name': 'Stock available to promise', | ||
70 | 23 | 'version': '2.0', | ||
71 | 24 | 'author': u'Numérigraphe', | ||
72 | 25 | 'category': 'Warehouse', | ||
73 | 26 | 'depends': ['stock'], | ||
74 | 27 | 'description': """ | ||
75 | 28 | Stock available to promise | ||
76 | 29 | ========================== | ||
77 | 30 | This module proposes several options to compute the quantity available to | ||
78 | 31 | promise for each product. | ||
79 | 32 | This quantity is based on the projected stock and, depending on the | ||
80 | 33 | configuration, it can account for various data such as sales quotations or | ||
81 | 34 | immediate production capacity. | ||
82 | 35 | This can be configured in the menu Settings > Configuration > Warehouse. | ||
83 | 36 | """, | ||
84 | 37 | 'license': 'AGPL-3', | ||
85 | 38 | 'data': [ | ||
86 | 39 | 'product_view.xml', | ||
87 | 40 | 'res_config_view.xml', | ||
88 | 41 | ] | ||
89 | 42 | } | ||
90 | 0 | 43 | ||
91 | === added file 'stock_available/product.py' | |||
92 | --- stock_available/product.py 1970-01-01 00:00:00 +0000 | |||
93 | +++ stock_available/product.py 2014-06-20 09:38:06 +0000 | |||
94 | @@ -0,0 +1,125 @@ | |||
95 | 1 | # -*- coding: utf-8 -*- | ||
96 | 2 | ############################################################################## | ||
97 | 3 | # | ||
98 | 4 | # This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved. | ||
99 | 5 | # | ||
100 | 6 | # This program is free software: you can redistribute it and/or modify | ||
101 | 7 | # it under the terms of the GNU Affero General Public License as | ||
102 | 8 | # published by the Free Software Foundation, either version 3 of the | ||
103 | 9 | # License, or (at your option) any later version. | ||
104 | 10 | # | ||
105 | 11 | # This program is distributed in the hope that it will be useful, | ||
106 | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
107 | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
108 | 14 | # GNU Affero General Public License for more details. | ||
109 | 15 | # | ||
110 | 16 | # You should have received a copy of the GNU Affero General Public License | ||
111 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
112 | 18 | # | ||
113 | 19 | ############################################################################## | ||
114 | 20 | |||
115 | 21 | from openerp.osv import orm, fields | ||
116 | 22 | import openerp.addons.decimal_precision as dp | ||
117 | 23 | |||
118 | 24 | |||
119 | 25 | # Expose the method as a function, like when the fields are defined, | ||
120 | 26 | # and use the pool to call the method from the other modules too. | ||
121 | 27 | def _product_available_fnct(self, cr, uid, ids, field_names=None, arg=False, | ||
122 | 28 | context=None): | ||
123 | 29 | return self.pool['product.product']._product_available( | ||
124 | 30 | cr, uid, ids, field_names=field_names, arg=arg, context=context) | ||
125 | 31 | |||
126 | 32 | |||
127 | 33 | class ProductProduct(orm.Model): | ||
128 | 34 | """Add a field for the stock available to promise. | ||
129 | 35 | |||
130 | 36 | Useful implementations need to be installed through the Settings menu or by | ||
131 | 37 | installing one of the modules stock_available_* | ||
132 | 38 | """ | ||
133 | 39 | _inherit = 'product.product' | ||
134 | 40 | |||
135 | 41 | def __init__(self, pool, cr): | ||
136 | 42 | """Use _product_available_fnct to compute all the quantities.""" | ||
137 | 43 | # Doing this lets us change the function and not redefine fields | ||
138 | 44 | super(ProductProduct, self).__init__(pool, cr) | ||
139 | 45 | for coldef in self._columns.values(): | ||
140 | 46 | if (isinstance(coldef, fields.function) | ||
141 | 47 | and coldef._multi == 'qty_available'): | ||
142 | 48 | coldef._fnct = _product_available_fnct | ||
143 | 49 | |||
144 | 50 | def _product_available(self, cr, uid, ids, field_names=None, arg=False, | ||
145 | 51 | context=None): | ||
146 | 52 | """Dummy field for the stock available to promise. | ||
147 | 53 | |||
148 | 54 | Must be overridden by another module that actually implement | ||
149 | 55 | computations. | ||
150 | 56 | The sub-modules MUST call super()._product_available BEFORE their own | ||
151 | 57 | computations with | ||
152 | 58 | context['virtual_is_immediately_usable_qty']=False | ||
153 | 59 | AND call _update_virtual_available() AFTER their own computations | ||
154 | 60 | with the context from the caller. | ||
155 | 61 | |||
156 | 62 | @param context: see _update_virtual_available()""" | ||
157 | 63 | if context is None: | ||
158 | 64 | context = {} | ||
159 | 65 | if field_names is None: | ||
160 | 66 | field_names = [] | ||
161 | 67 | else: | ||
162 | 68 | # We don't want to change the caller's list | ||
163 | 69 | field_names = list(field_names) | ||
164 | 70 | |||
165 | 71 | # Load virtual_available if it's not already asked for | ||
166 | 72 | # We need it to compute immediately_usable_qty | ||
167 | 73 | if ('virtual_available' not in field_names | ||
168 | 74 | and 'immediately_usable_qty' in field_names): | ||
169 | 75 | field_names.append('virtual_available') | ||
170 | 76 | if context.get('virtual_is_immediately_usable', False): | ||
171 | 77 | # _update_virtual_available will get/set these fields | ||
172 | 78 | if 'virtual_available' not in field_names: | ||
173 | 79 | field_names.append('virtual_available') | ||
174 | 80 | if 'immediately_usable_qty' not in field_names: | ||
175 | 81 | field_names.append('immediately_usable_qty') | ||
176 | 82 | |||
177 | 83 | # Compute the core quantities | ||
178 | 84 | res = super(ProductProduct, self)._product_available( | ||
179 | 85 | cr, uid, ids, field_names=field_names, arg=arg, context=context) | ||
180 | 86 | |||
181 | 87 | # By default, available to promise = forecasted quantity | ||
182 | 88 | if ('immediately_usable_qty' in field_names): | ||
183 | 89 | for stock_qty in res.itervalues(): | ||
184 | 90 | stock_qty['immediately_usable_qty'] = \ | ||
185 | 91 | stock_qty['virtual_available'] | ||
186 | 92 | |||
187 | 93 | return self.pool['product.product']._update_virtual_available( | ||
188 | 94 | cr, uid, res, context=context) | ||
189 | 95 | |||
190 | 96 | def _update_virtual_available(self, cr, uid, res, context=None): | ||
191 | 97 | """Copy immediately_usable_qty to virtual_available if context asks | ||
192 | 98 | |||
193 | 99 | @param context: If the key virtual_is_immediately_usable is True, | ||
194 | 100 | then the virtual stock is computed as the stock | ||
195 | 101 | available to promise. This lets existing code base | ||
196 | 102 | their computations on the new value with a minimum of | ||
197 | 103 | change (i.e.: warn salesmen when the stock available | ||
198 | 104 | for sale is insufficient to honor a quotation)""" | ||
199 | 105 | if (context is None | ||
200 | 106 | or not context.get('virtual_is_immediately_usable', False)): | ||
201 | 107 | return res | ||
202 | 108 | for stock_qty in res.itervalues(): | ||
203 | 109 | # _product_available makes sure both fields are loaded | ||
204 | 110 | # We're changing the caller's state but it's not be a problem | ||
205 | 111 | stock_qty['virtual_available'] = \ | ||
206 | 112 | stock_qty['immediately_usable_qty'] | ||
207 | 113 | return res | ||
208 | 114 | |||
209 | 115 | _columns = { | ||
210 | 116 | 'immediately_usable_qty': fields.function( | ||
211 | 117 | _product_available_fnct, multi='qty_available', | ||
212 | 118 | type='float', | ||
213 | 119 | digits_compute=dp.get_precision('Product Unit of Measure'), | ||
214 | 120 | string='Available to promise', | ||
215 | 121 | help="Stock for this Product that can be safely proposed " | ||
216 | 122 | "for sale to Customers.\n" | ||
217 | 123 | "The definition of this value can be configured to suit " | ||
218 | 124 | "your needs"), | ||
219 | 125 | } | ||
220 | 0 | 126 | ||
221 | === renamed file 'stock_available_immediately/product_view.xml' => 'stock_available/product_view.xml' | |||
222 | --- stock_available_immediately/product_view.xml 2014-01-24 17:11:21 +0000 | |||
223 | +++ stock_available/product_view.xml 2014-06-20 09:38:06 +0000 | |||
224 | @@ -1,27 +1,19 @@ | |||
225 | 1 | <?xml version="1.0" encoding="utf-8"?> | 1 | <?xml version="1.0" encoding="utf-8"?> |
226 | 2 | |||
227 | 3 | <!-- | ||
228 | 4 | stock available_immediately for OpenERP | ||
229 | 5 | Author Guewen Baconnier. Copyright Camptocamp SA | ||
230 | 6 | Copyright (C) 2011 Akretion Sébastien BEAU <sebastien.beau@akretion.com> | ||
231 | 7 | The licence is in the file __openerp__.py | ||
232 | 8 | --> | ||
233 | 9 | |||
234 | 10 | <openerp> | 2 | <openerp> |
235 | 11 | <data> | 3 | <data> |
238 | 12 | <record model="ir.ui.view" id="view_normal_stock_active_qty_form"> | 4 | <record model="ir.ui.view" id="view_stock_available_form"> |
239 | 13 | <field name="name">product.normal.stock.active.qty.form.inherit</field> | 5 | <field name="name">Stock available to promise (form)</field> |
240 | 14 | <field name="model">product.product</field> | 6 | <field name="model">product.product</field> |
241 | 15 | <field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/> | 7 | <field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/> |
242 | 16 | <field name="arch" type="xml"> | 8 | <field name="arch" type="xml"> |
243 | 17 | <field name="virtual_available" position="after"> | 9 | <field name="virtual_available" position="after"> |
244 | 18 | <newline/> | 10 | <newline/> |
245 | 19 | <field name="immediately_usable_qty" /> | 11 | <field name="immediately_usable_qty" /> |
247 | 20 | </field> | 12 | </field> |
248 | 21 | </field> | 13 | </field> |
249 | 22 | </record> | 14 | </record> |
250 | 23 | 15 | ||
252 | 24 | <record model="ir.ui.view" id="product_product_tree_view"> | 16 | <record model="ir.ui.view" id="view_stock_available_tree"> |
253 | 25 | <field name="name">product_immediately_usable.product_product_tree_view</field> | 17 | <field name="name">product_immediately_usable.product_product_tree_view</field> |
254 | 26 | <field name="model">product.product</field> | 18 | <field name="model">product.product</field> |
255 | 27 | <field name="inherit_id" ref="product.product_product_tree_view"/> | 19 | <field name="inherit_id" ref="product.product_product_tree_view"/> |
256 | @@ -30,12 +22,22 @@ | |||
257 | 30 | <tree position="attributes"> | 22 | <tree position="attributes"> |
258 | 31 | <attribute name="colors">red:immediately_usable_qty<0;blue:immediately_usable_qty>=0 and state in ('draft', 'end', 'obsolete');black:immediately_usable_qty>=0 and state not in ('draft', 'end', 'obsolete')</attribute> | 23 | <attribute name="colors">red:immediately_usable_qty<0;blue:immediately_usable_qty>=0 and state in ('draft', 'end', 'obsolete');black:immediately_usable_qty>=0 and state not in ('draft', 'end', 'obsolete')</attribute> |
259 | 32 | </tree> | 24 | </tree> |
261 | 33 | <field name="virtual_available" position="replace"> | 25 | <field name="virtual_available" position="after"> |
262 | 34 | <field name="immediately_usable_qty" /> | 26 | <field name="immediately_usable_qty" /> |
263 | 35 | </field> | 27 | </field> |
264 | 36 | </data> | 28 | </data> |
265 | 37 | </field> | 29 | </field> |
266 | 38 | </record> | 30 | </record> |
267 | 39 | 31 | ||
268 | 32 | <record model="ir.ui.view" id="view_stock_available_kanban"> | ||
269 | 33 | <field name="name">Product Kanban Stock</field> | ||
270 | 34 | <field name="model">product.product</field> | ||
271 | 35 | <field name="inherit_id" ref="stock.product_kanban_stock_view"/> | ||
272 | 36 | <field name="arch" type="xml"> | ||
273 | 37 | <xpath expr="//field[@name='virtual_available']/.." position="replace"> | ||
274 | 38 | <li t-if="record.type.raw_value != 'service'">Available to promise: <field name="immediately_usable_qty"/> <field name="uom_id"/></li> | ||
275 | 39 | </xpath> | ||
276 | 40 | </field> | ||
277 | 41 | </record> | ||
278 | 40 | </data> | 42 | </data> |
279 | 41 | </openerp> | 43 | </openerp> |
280 | 42 | 44 | ||
281 | === added file 'stock_available/res_config.py' | |||
282 | --- stock_available/res_config.py 1970-01-01 00:00:00 +0000 | |||
283 | +++ stock_available/res_config.py 2014-06-20 09:38:06 +0000 | |||
284 | @@ -0,0 +1,34 @@ | |||
285 | 1 | # -*- coding: utf-8 -*- | ||
286 | 2 | ############################################################################## | ||
287 | 3 | # | ||
288 | 4 | # This module is copyright (C) 2014 Numérigraphe SARL. All Rights Reserved. | ||
289 | 5 | # | ||
290 | 6 | # This program is free software: you can redistribute it and/or modify | ||
291 | 7 | # it under the terms of the GNU General Public License as published by | ||
292 | 8 | # the Free Software Foundation, either version 3 of the License, or | ||
293 | 9 | # (at your option) any later version. | ||
294 | 10 | # | ||
295 | 11 | # This program is distributed in the hope that it will be useful, | ||
296 | 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
297 | 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
298 | 14 | # GNU General Public License for more details. | ||
299 | 15 | # | ||
300 | 16 | # You should have received a copy of the GNU General Public License | ||
301 | 17 | # along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
302 | 18 | # | ||
303 | 19 | ############################################################################## | ||
304 | 20 | |||
305 | 21 | from openerp.osv import orm, fields | ||
306 | 22 | |||
307 | 23 | |||
308 | 24 | class StockConfig(orm.TransientModel): | ||
309 | 25 | """Add options to easily install the submodules""" | ||
310 | 26 | _inherit = 'stock.config.settings' | ||
311 | 27 | |||
312 | 28 | _columns = { | ||
313 | 29 | 'module_stock_available_immediately': fields.boolean( | ||
314 | 30 | 'Exclude incoming goods', | ||
315 | 31 | help="This will subtract incoming quantities from the quantities" | ||
316 | 32 | "available to promise.\n" | ||
317 | 33 | "This installs the module stock_available_immediately."), | ||
318 | 34 | } | ||
319 | 0 | 35 | ||
320 | === added file 'stock_available/res_config_view.xml' | |||
321 | --- stock_available/res_config_view.xml 1970-01-01 00:00:00 +0000 | |||
322 | +++ stock_available/res_config_view.xml 2014-06-20 09:38:06 +0000 | |||
323 | @@ -0,0 +1,25 @@ | |||
324 | 1 | <?xml version="1.0" encoding="utf-8"?> | ||
325 | 2 | <openerp> | ||
326 | 3 | <data> | ||
327 | 4 | <record id="view_stock_configuration" model="ir.ui.view"> | ||
328 | 5 | <field name="name">Stock settings: quantity available to promise</field> | ||
329 | 6 | <field name="model">stock.config.settings</field> | ||
330 | 7 | <field name="inherit_id" ref="stock.view_stock_config_settings" /> | ||
331 | 8 | <field name="arch" type="xml"> | ||
332 | 9 | <data> | ||
333 | 10 | <xpath expr="//group[last()]" position="after"> | ||
334 | 11 | <group> | ||
335 | 12 | <label for="id" string="Stock available to promise" /> | ||
336 | 13 | <div> | ||
337 | 14 | <div> | ||
338 | 15 | <field name="module_stock_available_immediately" class="oe_inline" /> | ||
339 | 16 | <label for="module_stock_available_immediately" /> | ||
340 | 17 | </div> | ||
341 | 18 | </div> | ||
342 | 19 | </group> | ||
343 | 20 | </xpath> | ||
344 | 21 | </data> | ||
345 | 22 | </field> | ||
346 | 23 | </record> | ||
347 | 24 | </data> | ||
348 | 25 | </openerp> | ||
349 | 0 | \ No newline at end of file | 26 | \ No newline at end of file |
350 | 1 | 27 | ||
351 | === modified file 'stock_available_immediately/__openerp__.py' | |||
352 | --- stock_available_immediately/__openerp__.py 2014-01-24 17:11:21 +0000 | |||
353 | +++ stock_available_immediately/__openerp__.py 2014-06-20 09:38:06 +0000 | |||
354 | @@ -20,21 +20,26 @@ | |||
355 | 20 | # | 20 | # |
356 | 21 | # | 21 | # |
357 | 22 | 22 | ||
358 | 23 | |||
359 | 24 | { | 23 | { |
363 | 25 | "name": "Immediately Usable Stock Quantity", | 24 | "name": "Ignore planned receptions in quantity available to promise", |
364 | 26 | "version": "1.0", | 25 | "version": "2.0", |
365 | 27 | "depends": ["product", "stock", ], | 26 | "depends": ["stock_available"], |
366 | 28 | "author": "Camptocamp", | 27 | "author": "Camptocamp", |
367 | 29 | "license": "AGPL-3", | 28 | "license": "AGPL-3", |
371 | 30 | "description": """ | 29 | "description": u""" |
372 | 31 | Compute the immediately usable stock. | 30 | Ignore planned receptions in quantity available to promise |
373 | 32 | Immediately usable is computed : Quantity on Hand - Outgoing Stock. | 31 | ---------------------------------------------------------- |
374 | 32 | |||
375 | 33 | Normally the quantity available to promise is based on the virtual stock, | ||
376 | 34 | which includes both planned outgoing and incoming goods. | ||
377 | 35 | This module will subtract the planned receptions from the quantity available to | ||
378 | 36 | promise. | ||
379 | 37 | |||
380 | 38 | Contributors | ||
381 | 39 | ------------ | ||
382 | 40 | * Author: Guewen Baconnier (Camptocamp SA) | ||
383 | 41 | * Sébastien BEAU (Akretion) <sebastien.beau@akretion.com> | ||
384 | 42 | * Lionel Sausin (Numérigraphe) <ls@numerigraphe.com> | ||
385 | 33 | """, | 43 | """, |
392 | 34 | "website": "http://tinyerp.com/module_account.html", | 44 | "category": "Hidden", |
387 | 35 | "category": "Generic Modules/Stock", | ||
388 | 36 | "data": ["product_view.xml", | ||
389 | 37 | ], | ||
390 | 38 | "active": False, | ||
391 | 39 | "installable": True | ||
393 | 40 | } | 45 | } |
394 | 41 | 46 | ||
395 | === modified file 'stock_available_immediately/product.py' | |||
396 | --- stock_available_immediately/product.py 2014-02-19 11:43:35 +0000 | |||
397 | +++ stock_available_immediately/product.py 2014-06-20 09:38:06 +0000 | |||
398 | @@ -19,124 +19,37 @@ | |||
399 | 19 | # | 19 | # |
400 | 20 | ############################################################################## | 20 | ############################################################################## |
401 | 21 | 21 | ||
405 | 22 | from openerp.addons import decimal_precision as dp | 22 | from openerp.osv import orm |
403 | 23 | |||
404 | 24 | from openerp.osv import orm, fields | ||
406 | 25 | 23 | ||
407 | 26 | 24 | ||
408 | 27 | class product_immediately_usable(orm.Model): | 25 | class product_immediately_usable(orm.Model): |
414 | 28 | """ | 26 | """Subtract incoming qty from immediately_usable_qty |
415 | 29 | Inherit Product in order to add an "immediately usable quantity" | 27 | |
416 | 30 | stock field | 28 | We don't need to override the function fields, the module stock_available |
417 | 31 | Immediately usable quantity is : real stock - outgoing qty | 29 | takes of it for us.""" |
413 | 32 | """ | ||
418 | 33 | _inherit = 'product.product' | 30 | _inherit = 'product.product' |
419 | 34 | 31 | ||
420 | 35 | def _product_available(self, cr, uid, ids, field_names=None, | 32 | def _product_available(self, cr, uid, ids, field_names=None, |
421 | 36 | arg=False, context=None): | 33 | arg=False, context=None): |
426 | 37 | """ | 34 | """Ignore the incoming goods in the quantity available to promise""" |
427 | 38 | Get super() _product_available and compute immediately_usable_qty | 35 | # We need available and incoming quantities to compute |
424 | 39 | """ | ||
425 | 40 | # We need available and outgoing quantities to compute | ||
428 | 41 | # immediately usable quantity. | 36 | # immediately usable quantity. |
429 | 42 | # When immediately_usable_qty is displayed but | 37 | # When immediately_usable_qty is displayed but |
431 | 43 | # not qty_available and outgoing_qty, | 38 | # not qty_available and incoming_qty, |
432 | 44 | # they are not computed in the super method so we cannot | 39 | # they are not computed in the super method so we cannot |
433 | 45 | # compute immediately_usable_qty. | 40 | # compute immediately_usable_qty. |
434 | 46 | # To avoid this issue, we add the 2 fields in | 41 | # To avoid this issue, we add the 2 fields in |
435 | 47 | # field_names to compute them. | 42 | # field_names to compute them. |
436 | 48 | if 'immediately_usable_qty' in field_names: | 43 | if 'immediately_usable_qty' in field_names: |
437 | 49 | field_names.append('qty_available') | 44 | field_names.append('qty_available') |
439 | 50 | field_names.append('outgoing_qty') | 45 | field_names.append('incoming_qty') |
440 | 51 | 46 | ||
441 | 52 | res = super(product_immediately_usable, self)._product_available( | 47 | res = super(product_immediately_usable, self)._product_available( |
442 | 53 | cr, uid, ids, field_names, arg, context) | 48 | cr, uid, ids, field_names, arg, context) |
443 | 54 | 49 | ||
444 | 55 | if 'immediately_usable_qty' in field_names: | 50 | if 'immediately_usable_qty' in field_names: |
532 | 56 | for product_id, stock_qty in res.iteritems(): | 51 | for stock_qty in res.itervalues(): |
533 | 57 | res[product_id]['immediately_usable_qty'] = \ | 52 | stock_qty['immediately_usable_qty'] -= \ |
534 | 58 | stock_qty['qty_available'] + stock_qty['outgoing_qty'] | 53 | stock_qty['incoming_qty'] |
535 | 59 | 54 | ||
536 | 60 | return res | 55 | return self._update_virtual_available(cr, uid, res, context=context) |
450 | 61 | |||
451 | 62 | _columns = { | ||
452 | 63 | 'qty_available': fields.function( | ||
453 | 64 | _product_available, | ||
454 | 65 | multi='qty_available', | ||
455 | 66 | type='float', | ||
456 | 67 | digits_compute=dp.get_precision('Product UoM'), | ||
457 | 68 | string='Quantity On Hand', | ||
458 | 69 | help="Current quantity of products.\n" | ||
459 | 70 | "In a context with a single Stock Location, this includes " | ||
460 | 71 | "goods stored at this Location, or any of its children.\n" | ||
461 | 72 | "In a context with a single Warehouse, this includes " | ||
462 | 73 | "goods stored in the Stock Location of this Warehouse, " | ||
463 | 74 | "or any " | ||
464 | 75 | "of its children.\n" | ||
465 | 76 | "In a context with a single Shop, this includes goods " | ||
466 | 77 | "stored in the Stock Location of the Warehouse of this Shop, " | ||
467 | 78 | "or any of its children.\n" | ||
468 | 79 | "Otherwise, this includes goods stored in any Stock Location " | ||
469 | 80 | "typed as 'internal'."), | ||
470 | 81 | 'virtual_available': fields.function( | ||
471 | 82 | _product_available, | ||
472 | 83 | multi='qty_available', | ||
473 | 84 | type='float', | ||
474 | 85 | digits_compute=dp.get_precision('Product UoM'), | ||
475 | 86 | string='Quantity Available', | ||
476 | 87 | help="Forecast quantity (computed as Quantity On Hand " | ||
477 | 88 | "- Outgoing + Incoming)\n" | ||
478 | 89 | "In a context with a single Stock Location, this includes " | ||
479 | 90 | "goods stored at this Location, or any of its children.\n" | ||
480 | 91 | "In a context with a single Warehouse, this includes " | ||
481 | 92 | "goods stored in the Stock Location of this Warehouse, " | ||
482 | 93 | "or any " | ||
483 | 94 | "of its children.\n" | ||
484 | 95 | "In a context with a single Shop, this includes goods " | ||
485 | 96 | "stored in the Stock Location of the Warehouse of this Shop, " | ||
486 | 97 | "or any of its children.\n" | ||
487 | 98 | "Otherwise, this includes goods stored in any Stock Location " | ||
488 | 99 | "typed as 'internal'."), | ||
489 | 100 | 'incoming_qty': fields.function( | ||
490 | 101 | _product_available, | ||
491 | 102 | multi='qty_available', | ||
492 | 103 | type='float', | ||
493 | 104 | digits_compute=dp.get_precision('Product UoM'), | ||
494 | 105 | string='Incoming', | ||
495 | 106 | help="Quantity of products that are planned to arrive.\n" | ||
496 | 107 | "In a context with a single Stock Location, this includes " | ||
497 | 108 | "goods arriving to this Location, or any of its children.\n" | ||
498 | 109 | "In a context with a single Warehouse, this includes " | ||
499 | 110 | "goods arriving to the Stock Location of this Warehouse, or " | ||
500 | 111 | "any of its children.\n" | ||
501 | 112 | "In a context with a single Shop, this includes goods " | ||
502 | 113 | "arriving to the Stock Location of the Warehouse of this " | ||
503 | 114 | "Shop, or any of its children.\n" | ||
504 | 115 | "Otherwise, this includes goods arriving to any Stock " | ||
505 | 116 | "Location typed as 'internal'."), | ||
506 | 117 | 'outgoing_qty': fields.function( | ||
507 | 118 | _product_available, | ||
508 | 119 | multi='qty_available', | ||
509 | 120 | type='float', | ||
510 | 121 | digits_compute=dp.get_precision('Product UoM'), | ||
511 | 122 | string='Outgoing', | ||
512 | 123 | help="Quantity of products that are planned to leave.\n" | ||
513 | 124 | "In a context with a single Stock Location, this includes " | ||
514 | 125 | "goods leaving from this Location, or any of its children.\n" | ||
515 | 126 | "In a context with a single Warehouse, this includes " | ||
516 | 127 | "goods leaving from the Stock Location of this Warehouse, or " | ||
517 | 128 | "any of its children.\n" | ||
518 | 129 | "In a context with a single Shop, this includes goods " | ||
519 | 130 | "leaving from the Stock Location of the Warehouse of this " | ||
520 | 131 | "Shop, or any of its children.\n" | ||
521 | 132 | "Otherwise, this includes goods leaving from any Stock " | ||
522 | 133 | "Location typed as 'internal'."), | ||
523 | 134 | 'immediately_usable_qty': fields.function( | ||
524 | 135 | _product_available, | ||
525 | 136 | digits_compute=dp.get_precision('Product UoM'), | ||
526 | 137 | type='float', | ||
527 | 138 | string='Immediately Usable', | ||
528 | 139 | multi='qty_available', | ||
529 | 140 | help="Quantity of products really available for sale." \ | ||
530 | 141 | "Computed as: Quantity On Hand - Outgoing."), | ||
531 | 142 | } | ||
537 | 143 | 56 | ||
538 | === modified file 'stock_inventory_existing_lines/stock.py' | |||
539 | --- stock_inventory_existing_lines/stock.py 2012-03-07 12:56:37 +0000 | |||
540 | +++ stock_inventory_existing_lines/stock.py 2014-06-20 09:38:06 +0000 | |||
541 | @@ -81,7 +81,7 @@ | |||
542 | 81 | 'location_id': fields.many2one('stock.location', 'Location', required=True), | 81 | 'location_id': fields.many2one('stock.location', 'Location', required=True), |
543 | 82 | 'product_id': fields.many2one('product.product', 'Product', required=True, select=True), | 82 | 'product_id': fields.many2one('product.product', 'Product', required=True, select=True), |
544 | 83 | 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True), | 83 | 'product_uom': fields.many2one('product.uom', 'Product UOM', required=True), |
546 | 84 | 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product UoM')), | 84 | 'product_qty': fields.float('Quantity', digits_compute=dp.get_precision('Product Unit of Measure')), |
547 | 85 | 'company_id': fields.related('inventory_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, select=True, readonly=True), | 85 | 'company_id': fields.related('inventory_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, select=True, readonly=True), |
548 | 86 | 'prod_lot_id': fields.many2one('stock.production.lot', 'Production Lot', domain="[('product_id','=',product_id)]"), | 86 | 'prod_lot_id': fields.many2one('stock.production.lot', 'Production Lot', domain="[('product_id','=',product_id)]"), |
549 | 87 | 'state': fields.related('inventory_id', 'state', type='char', string='State',readonly=True), | 87 | 'state': fields.related('inventory_id', 'state', type='char', string='State',readonly=True), |
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?