Merge lp:~jean-lelievre/purchase-report/product_inventory_warning into lp:~purchase-core-editors/purchase-report/7.0

Proposed by Jean LELIEVRE ElicoCorp
Status: Work in progress
Proposed branch: lp:~jean-lelievre/purchase-report/product_inventory_warning
Merge into: lp:~purchase-core-editors/purchase-report/7.0
Diff against target: 1477 lines (+1417/-0)
11 files modified
product_inventory_warning/__init__.py (+27/-0)
product_inventory_warning/__openerp__.py (+53/-0)
product_inventory_warning/i18n/zh_CN.po (+315/-0)
product_inventory_warning/product.py (+613/-0)
product_inventory_warning/product_view.xml (+137/-0)
product_inventory_warning/security/ir.model.access.csv (+3/-0)
product_inventory_warning/wizard/__init__.py (+26/-0)
product_inventory_warning/wizard/product_qty.py (+69/-0)
product_inventory_warning/wizard/product_qty_view.xml (+32/-0)
product_inventory_warning/wizard/product_sfc.py (+80/-0)
product_inventory_warning/wizard/product_sfc_view.xml (+62/-0)
To merge this branch: bzr merge lp:~jean-lelievre/purchase-report/product_inventory_warning
Reviewer Review Type Date Requested Status
Alexandre Fayolle - camptocamp Needs Resubmitting
Maxime Chambreuil (http://www.savoirfairelinux.com) code review Needs Fixing
Review via email: mp+182057@code.launchpad.net

Description of the change

[ADD] Add the module product_inventory_warning

Product Inventory Warning
==================================================

Add a wizard to calculate the QTY of product.

To post a comment you must log in.
Revision history for this message
Maxime Chambreuil (http://www.savoirfairelinux.com) (max3903) wrote :

Hello Jean,

Based on the description of the MP and the module, I would say that the feature is already in OpenERP (OpenERP already provides the qty of product). I think you should add some documentation to explain what OpenERP doesn't do, what your module brings and how to use it.

Please fix PEP8 issues and add the pot file.

I have never seen a module with so much SQL queries. I would be interested to know how it scales.

Otherwise LGTM.

Thanks for your work!

review: Needs Fixing (code review)
Revision history for this message
Yannick Vaucher @ Camptocamp (yvaucher-c2c) wrote :

No changes since 2013-11-10 after Need Fixing request -> I set this in WIP

@Jean LELIEVRE

Please do the required changes then set it in Needs Review again

Here you will find the community coding Guide Lines
which applies to new code and code ported from old version.
https://doc.openerp.com/contribute/05_developing_modules/#community-guidelines

Cheers,
Yannick

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

Hello,

The management of the project has moved to Github: https://github.com/OCA/purchase-reporting

Please migrate your merge proposal to Github. You may want to check https://github.com/OCA/maintainers-tools/wiki/How-to-move-a-Merge-Proposal-to-GitHub for an explanation on how to proceed.

Thanks for contributing to the project

review: Needs Resubmitting

Unmerged revisions

11. By Jean LELIEVRE ElicoCorp

[ADD] Add the module product_inventory_warning.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added directory 'product_inventory_warning'
2=== added file 'product_inventory_warning/__init__.py'
3--- product_inventory_warning/__init__.py 1970-01-01 00:00:00 +0000
4+++ product_inventory_warning/__init__.py 2013-08-26 08:54:27 +0000
5@@ -0,0 +1,27 @@
6+# -*- coding: utf-8 -*-
7+##############################################################################
8+#
9+# OpenERP, Open Source Management Solution
10+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
11+# Author: Andy Lu <andy.lu@elico-corp.com>
12+#
13+# This program is free software: you can redistribute it and/or modify
14+# it under the terms of the GNU Affero General Public License as
15+# published by the Free Software Foundation, either version 3 of the
16+# License, or (at your option) any later version.
17+#
18+# This program is distributed in the hope that it will be useful,
19+# but WITHOUT ANY WARRANTY; without even the implied warranty of
20+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21+# GNU Affero General Public License for more details.
22+#
23+# You should have received a copy of the GNU Affero General Public License
24+# along with this program. If not, see <http://www.gnu.org/licenses/>.
25+#
26+##############################################################################
27+
28+import product
29+import wizard
30+#import sale_compare
31+
32+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
33\ No newline at end of file
34
35=== added file 'product_inventory_warning/__openerp__.py'
36--- product_inventory_warning/__openerp__.py 1970-01-01 00:00:00 +0000
37+++ product_inventory_warning/__openerp__.py 2013-08-26 08:54:27 +0000
38@@ -0,0 +1,53 @@
39+# -*- coding: utf-8 -*-
40+##############################################################################
41+#
42+# OpenERP, Open Source Management Solution
43+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
44+# Author: Andy Lu <andy.lu@elico-corp.com>
45+# LIN Yu <lin.yu@elico-corp.com>
46+#
47+# This program is free software: you can redistribute it and/or modify
48+# it under the terms of the GNU Affero General Public License as
49+# published by the Free Software Foundation, either version 3 of the
50+# License, or (at your option) any later version.
51+#
52+# This program is distributed in the hope that it will be useful,
53+# but WITHOUT ANY WARRANTY; without even the implied warranty of
54+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
55+# GNU Affero General Public License for more details.
56+#
57+# You should have received a copy of the GNU Affero General Public License
58+# along with this program. If not, see <http://www.gnu.org/licenses/>.
59+#
60+##############################################################################
61+
62+{
63+ 'name': 'Product Inventory Warning',
64+ 'version': '1',
65+ 'category': 'Product',
66+ 'sequence': 1,
67+ 'summary': 'Product Inventory Warning',
68+ 'description': """
69+Product Inventory Warning
70+==================================================
71+
72+Add a wizard to calculate the QTY of product.
73+ """,
74+ 'author': 'Elico Corp',
75+ 'website': 'http://www.elico-corp.com',
76+ 'images' : [],
77+ 'depends': ['product', 'product_stock_type','product_separate_cost','stock_with_cost'],
78+ 'data': [
79+ 'product_view.xml',
80+ 'wizard/product_qty_view.xml',
81+ 'wizard/product_sfc_view.xml',
82+ 'security/ir.model.access.csv',
83+ ],
84+ 'test': [],
85+ 'demo': [],
86+ 'installable': True,
87+ 'auto_install': False,
88+ 'application': False,
89+}
90+
91+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
92
93=== added directory 'product_inventory_warning/i18n'
94=== added file 'product_inventory_warning/i18n/zh_CN.po'
95--- product_inventory_warning/i18n/zh_CN.po 1970-01-01 00:00:00 +0000
96+++ product_inventory_warning/i18n/zh_CN.po 2013-08-26 08:54:27 +0000
97@@ -0,0 +1,315 @@
98+# Translation of OpenERP Server.
99+# This file contains the translation of the following modules:
100+# * fc_product
101+#
102+msgid ""
103+msgstr ""
104+"Project-Id-Version: OpenERP Server 7.0\n"
105+"Report-Msgid-Bugs-To: \n"
106+"POT-Creation-Date: 2013-05-17 08:19+0000\n"
107+"PO-Revision-Date: 2013-05-17 08:19+0000\n"
108+"Last-Translator: <>\n"
109+"Language-Team: \n"
110+"MIME-Version: 1.0\n"
111+"Content-Type: text/plain; charset=UTF-8\n"
112+"Content-Transfer-Encoding: \n"
113+"Plural-Forms: \n"
114+
115+#. module: fc_product
116+#: view:product.inventory:0
117+#: field:product.inventory,category_id:0
118+#: view:product.inventory.dates:0
119+#: field:product.inventory.dates,category_id:0
120+msgid "Category"
121+msgstr "种类"
122+
123+#. module: fc_product
124+#: field:product.inventory,code:0
125+#: field:product.inventory.dates,code:0
126+msgid "SKU"
127+msgstr "SKU"
128+
129+#. module: fc_product
130+#: field:run.product.inventory.dates,from_date:0
131+msgid "From"
132+msgstr "开始"
133+
134+#. module: fc_product
135+#: field:product.inventory.dates,produce_qty:0
136+msgid "Production Quantity"
137+msgstr "生产数量"
138+
139+#. module: fc_product
140+#: model:ir.model,name:fc_product.model_run_product_inventory_dates
141+msgid "Compute Product Inventory betweend dates"
142+msgstr "根据时间生成产品粗困报表"
143+
144+#. module: fc_product
145+#: field:run.product.inventory.dates,to_date:0
146+msgid "To"
147+msgstr "到"
148+
149+#. module: fc_product
150+#: field:product.inventory.dates,start_value:0
151+msgid "Start Value"
152+msgstr "起初金额"
153+
154+#. module: fc_product
155+#: field:product.inventory,ondraft_qty:0
156+msgid "Not Confirm Quantity"
157+msgstr "未审核采购数"
158+
159+#. module: fc_product
160+#: field:product.inventory.dates,end_qty:0
161+msgid "End Quantity"
162+msgstr "期末数量"
163+
164+#. module: fc_product
165+#: model:ir.model,name:fc_product.model_run_product_inventory
166+#: view:run.product.inventory:0
167+msgid "Compute Product Inventory"
168+msgstr "计算产品库存"
169+
170+#. module: fc_product
171+#: field:product.inventory.dates,consume_qty:0
172+msgid "Consumption Quantity"
173+msgstr "消耗数量"
174+
175+#. module: fc_product
176+#: code:addons/fc_product/wizard/product_sfc.py:61
177+#: code:addons/fc_product/wizard/sale_compare_wizard.py:61
178+#: model:ir.actions.act_window,name:fc_product.action_product_inventory_dates_tree
179+#: model:ir.model,name:fc_product.model_product_inventory_dates
180+#: model:ir.ui.menu,name:fc_product.menu_action_product_inventory_dates_tree
181+#: view:product.inventory.dates:0
182+#, python-format
183+msgid "Product Inventory between dates"
184+msgstr "期间产品库存"
185+
186+#. module: fc_product
187+#: field:product.inventory,onorder_qty:0
188+msgid "Future Quantity"
189+msgstr "预测数量"
190+
191+#. module: fc_product
192+#: code:addons/fc_product/product.py:104
193+#: code:addons/fc_product/product.py:106
194+#: field:product.inventory,name_en:0
195+#: field:product.inventory,name_sort_en:0
196+#, python-format
197+msgid "Name EN"
198+msgstr "英文名"
199+
200+#. module: fc_product
201+#: field:product.inventory.dates,start_qty:0
202+msgid "Beginning Quantity"
203+msgstr "起初数量"
204+
205+#. module: fc_product
206+#: view:product.inventory:0
207+#: field:product.inventory,stock_type_id:0
208+#: view:product.inventory.dates:0
209+#: field:product.inventory.dates,stock_type_id:0
210+msgid "Stock Type"
211+msgstr "仓储种类"
212+
213+#. module: fc_product
214+#: field:product.inventory,date:0
215+msgid "Creation Date"
216+msgstr "创建时间"
217+
218+#. module: fc_product
219+#: code:addons/fc_product/wizard/product_qty.py:55
220+#: model:ir.model,name:fc_product.model_product_inventory
221+#: view:product.inventory:0
222+#, python-format
223+msgid "Product Inventory"
224+msgstr "产品库存"
225+
226+#. module: fc_product
227+#: field:product.inventory.dates,produce_value:0
228+msgid "Production Value"
229+msgstr "生产金额"
230+
231+#. module: fc_product
232+#: field:product.inventory,product_safe_qty:0
233+#: field:product.product,product_safe_qty:0
234+msgid "Minimum stock warning Quantity"
235+msgstr "最小库存数量"
236+
237+#. module: fc_product
238+#: code:addons/fc_product/sale_compare.py:63
239+#, python-format
240+msgid "ERP sub total"
241+msgstr "ERP sub total"
242+
243+#. module: fc_product
244+#: field:product.inventory.dates,consume_value:0
245+msgid "Consumption Value"
246+msgstr "消耗金额"
247+
248+#. module: fc_product
249+#: code:addons/fc_product/product.py:101
250+#: field:product.inventory,joomla_unit_cn:0
251+#, python-format
252+msgid "Website Product Unit in CN"
253+msgstr "中文采购单位"
254+
255+#. module: fc_product
256+#: field:product.inventory,onhand_qty:0
257+msgid "Onhand Quantity"
258+msgstr "在手数量"
259+
260+#. module: fc_product
261+#: field:product.inventory,uom_id:0
262+#: field:product.inventory.dates,uom_id:0
263+msgid "UoM"
264+msgstr "单位"
265+
266+#. module: fc_product
267+#: field:product.inventory.dates,scrap_value:0
268+msgid "Scrap Value"
269+msgstr "报废金额"
270+
271+#. module: fc_product
272+#: field:product.inventory.dates,to_date:0
273+msgid "End Date"
274+msgstr "结束时间"
275+
276+#. module: fc_product
277+#: view:run.product.inventory:0
278+#: view:run.product.inventory.dates:0
279+msgid "Compute"
280+msgstr "计算"
281+
282+#. module: fc_product
283+#: view:run.product.inventory.dates:0
284+msgid "Compute Product Inventory based on current stock moves and dates"
285+msgstr "根据当前调拨和日期计算产品库存"
286+
287+#. module: fc_product
288+#: view:run.product.inventory:0
289+msgid "Compute Product Inventory based on current stock moves"
290+msgstr "根据库存调拨计算产品数量"
291+
292+#. module: fc_product
293+#: model:ir.actions.act_window,name:fc_product.action_product_inventory_tree
294+#: model:ir.ui.menu,name:fc_product.menu_action_product_inventory_tree
295+msgid "Product Inventory Warning"
296+msgstr "最小库存报警"
297+
298+#. module: fc_product
299+#: model:ir.model,name:fc_product.model_product_product
300+#: view:product.inventory:0
301+#: view:product.inventory.dates:0
302+#: field:product.inventory.dates,product_id:0
303+msgid "Product"
304+msgstr "产品"
305+
306+#. module: fc_product
307+#: model:ir.actions.act_window,name:fc_product.action_run_product_inventory
308+#: model:ir.ui.menu,name:fc_product.menu_action_run_product_inventory
309+msgid "Compute Product Inventory Warning"
310+msgstr "计算最小库存报警"
311+
312+#. module: fc_product
313+#: field:product.inventory.dates,end_price:0
314+msgid "End Price"
315+msgstr "期末价格"
316+
317+#. module: fc_product
318+#: field:product.inventory,product_id:0
319+msgid "Products"
320+msgstr "产品"
321+
322+#. module: fc_product
323+#: code:addons/fc_product/product.py:100
324+#: field:product.inventory,joomla_unit:0
325+#, python-format
326+msgid "Website Product Unit"
327+msgstr "产品单位中文"
328+
329+#. module: fc_product
330+#: field:product.inventory.dates,sale_value:0
331+msgid "Sale Value"
332+msgstr "销售金额"
333+
334+#. module: fc_product
335+#: field:product.inventory.dates,sale_qty:0
336+msgid "Sale Quantity"
337+msgstr "销售数量"
338+
339+#. module: fc_product
340+#: model:ir.actions.act_window,name:fc_product.action_run_product_inventory_dates
341+#: model:ir.ui.menu,name:fc_product.menu_action_run_product_inventory_dates
342+#: view:run.product.inventory.dates:0
343+msgid "Compute Product Inventory between dates"
344+msgstr "根据日期计算产品库存"
345+
346+#. module: fc_product
347+#: field:product.inventory.dates,buy_value:0
348+msgid "Purchase Value"
349+msgstr "采购金额"
350+
351+#. module: fc_product
352+#: view:product.inventory:0
353+msgid "Out of Stock"
354+msgstr "缺货产品"
355+
356+#. module: fc_product
357+#: model:ir.model,name:fc_product.model_product_template
358+#: field:product.inventory.dates,product_tmpl_id:0
359+msgid "Product Template"
360+msgstr "产品模板"
361+
362+#. module: fc_product
363+#: field:product.inventory.dates,scrap_qty:0
364+msgid "Scrap Quantity"
365+msgstr "Scrap Quantity"
366+
367+#. module: fc_product
368+#: field:product.inventory,out_stock:0
369+msgid "Out Stock"
370+msgstr "Out Stock"
371+
372+#. module: fc_product
373+#: view:product.inventory:0
374+#: view:product.inventory.dates:0
375+msgid "Group by..."
376+msgstr "分组..."
377+
378+#. module: fc_product
379+#: field:product.inventory.dates,end_value:0
380+msgid "End Value"
381+msgstr "期末金额"
382+
383+#. module: fc_product
384+#: view:run.product.inventory:0
385+#: view:run.product.inventory.dates:0
386+msgid "_Cancel"
387+msgstr "_取消"
388+
389+#. module: fc_product
390+#: code:addons/fc_product/product.py:105
391+#: code:addons/fc_product/product.py:107
392+#: field:product.inventory,name_cn:0
393+#: field:product.inventory,name_sort_cn:0
394+#, python-format
395+msgid "Name CN"
396+msgstr "中文名"
397+
398+#. module: fc_product
399+#: field:product.inventory.dates,from_date:0
400+msgid "Start Date"
401+msgstr "开始时间"
402+
403+#. module: fc_product
404+#: field:product.inventory.dates,start_price:0
405+msgid "Start Price"
406+msgstr "开始价格"
407+
408+#. module: fc_product
409+#: field:product.inventory.dates,buy_qty:0
410+msgid "Purchase Quantity"
411+msgstr "采购数量"
412+
413
414=== added file 'product_inventory_warning/product.py'
415--- product_inventory_warning/product.py 1970-01-01 00:00:00 +0000
416+++ product_inventory_warning/product.py 2013-08-26 08:54:27 +0000
417@@ -0,0 +1,613 @@
418+# -*- coding: utf-8 -*-
419+##############################################################################
420+#
421+# OpenERP, Open Source Management Solution
422+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
423+# Author: Yannick Gouin <yannick.gouin@elico-corp.com>
424+#
425+# This program is free software: you can redistribute it and/or modify
426+# it under the terms of the GNU Affero General Public License as
427+# published by the Free Software Foundation, either version 3 of the
428+# License, or (at your option) any later version.
429+#
430+# This program is distributed in the hope that it wil l be useful,
431+# but WITHOUT ANY WARRANTY; without even the implied warranty of
432+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
433+# GNU Affero General Public License for more details.
434+#
435+# You should have received a copy of the GNU Affero General Public License
436+# along with this program. If not, see <http://www.gnu.org/licenses/>.
437+#
438+##############################################################################
439+
440+from osv import osv, fields
441+import openerp.addons.decimal_precision as dp
442+import time, pytz
443+from datetime import datetime
444+from tools.translate import _
445+
446+class product_product(osv.osv):
447+ _inherit = 'product.product'
448+
449+ _columns = {
450+ 'product_safe_qty': fields.float('Minimum stock warning Quantity', digits_compute=dp.get_precision('Product Unit of Measure')),
451+ }
452+ _defaults = {
453+ 'product_safe_qty': 0.0,
454+ }
455+product_product()
456+
457+
458+class product_inventory(osv.osv):
459+ _name = 'product.inventory'
460+ _description = 'Product Inventory'
461+ _rec_name = "code"
462+ _order = 'code'
463+
464+ _columns = {
465+ 'product_id': fields.many2one('product.product', 'Products', required=True),
466+ 'onhand_qty': fields.float("Onhand Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
467+ 'onorder_qty': fields.float("Future Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
468+ 'ondraft_qty': fields.float("Not Confirm Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
469+ 'date': fields.datetime('Creation Date'),
470+ 'category_id': fields.many2one('product.category',string='Category'),
471+ 'stock_type_id': fields.many2one('product.stock_type',string='Stock Type'),
472+ 'uom_id': fields.many2one('product.uom',string='UoM'),
473+ 'code': fields.char('SKU', size=128,),
474+ 'product_safe_qty': fields.float('Minimum stock warning Quantity', digits_compute=dp.get_precision('Product Unit of Measure')),
475+ 'name': fields.related('product_id', 'name', string=_('Name'), type='char', size=128),
476+ 'out_stock':fields.boolean("Out Stock"),
477+ }
478+ _defaults = {
479+ 'onhand_qty': 0.0,
480+ 'onorder_qty': 0.0,
481+ 'ondraft_qty': 0.0,
482+ 'product_safe_qty': 0.0,
483+ 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
484+ }
485+
486+
487+ def compute_inventory(self, cr, uid, context=None):
488+ #prod_obj = self.pool.get('product.product')
489+ cr.execute("""TRUNCATE TABLE product_inventory""")
490+ cr.execute("""INSERT INTO product_inventory( product_id, date) SELECT id,current_timestamp at time zone 'UTC' FROM product_product WHERE active AND id IN (SELECT distinct product_id FROM stock_move ) ORDER BY id""")
491+ cr.execute("""INSERT INTO product_inventory( product_id, date) SELECT product_id,current_timestamp at time zone 'UTC' FROM purchase_order_line WHERE product_id NOT IN (SELECT distinct product_id FROM stock_move ) ORDER BY product_id""")
492+ cr.execute("""
493+ UPDATE product_inventory AS i
494+ SET code = p.default_code, category_id = t.categ_id,
495+ stock_type_id = t.stock_type_id, uom_id = t.uom_id, product_safe_qty = p.product_safe_qty
496+ FROM product_product p, product_template t
497+ WHERE i.product_id = p.id AND p.product_tmpl_id = t.id""")
498+
499+ #onhand_qty
500+ cr.execute("""
501+ UPDATE product_inventory
502+ SET onhand_qty = sl.product_qty
503+ FROM
504+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
505+ FROM stock_move m
506+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
507+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
508+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
509+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
510+ WHERE m.state = 'done'
511+ AND m.location_id NOT IN (SELECT distinct d.id
512+ FROM stock_warehouse w, stock_location h, stock_location d
513+ WHERE w.lot_stock_id = h.id
514+ AND d.parent_left >= h.parent_left
515+ AND d.parent_right <= h.parent_right)
516+ AND m.location_dest_id IN (SELECT distinct d.id
517+ FROM stock_warehouse w, stock_location h, stock_location d
518+ WHERE w.lot_stock_id = h.id
519+ AND d.parent_left >= h.parent_left
520+ AND d.parent_right <= h.parent_right)
521+ GROUP BY m.product_id ORDER BY m.product_id) sl
522+ WHERE product_inventory.product_id = sl.product_id """)
523+
524+ # Useless, no ?
525+ #cr.execute("""UPDATE product_inventory SET onhand_qty = 0.0 WHERE coalesce(onhand_qty,0.0) = 0.0""")
526+
527+ cr.execute("""
528+ UPDATE product_inventory SET onhand_qty = onhand_qty - sl.product_qty
529+ FROM
530+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
531+ FROM stock_move m
532+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
533+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
534+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
535+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
536+ WHERE m.state = 'done'
537+ AND m.location_id IN (SELECT distinct d.id
538+ FROM stock_warehouse w, stock_location h, stock_location d
539+ WHERE w.lot_stock_id = h.id
540+ AND d.parent_left >= h.parent_left
541+ AND d.parent_right <= h.parent_right)
542+ AND m.location_dest_id NOT IN (SELECT distinct d.id
543+ FROM stock_warehouse w, stock_location h, stock_location d
544+ WHERE w.lot_stock_id = h.id
545+ AND d.parent_left >= h.parent_left
546+ AND d.parent_right <= h.parent_right)
547+ GROUP BY m.product_id ORDER BY m.product_id) sl
548+ WHERE product_inventory.product_id = sl.product_id """)
549+
550+
551+ #onorder_qty
552+ cr.execute("""
553+ UPDATE product_inventory SET onorder_qty = sl.product_qty
554+ FROM
555+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
556+ FROM stock_move m
557+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
558+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
559+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
560+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
561+ WHERE m.state != 'cancel' AND m.state != 'new'
562+ AND m.location_id NOT IN (SELECT distinct d.id
563+ FROM stock_warehouse w, stock_location h, stock_location d
564+ WHERE w.lot_stock_id = h.id
565+ AND d.parent_left >= h.parent_left
566+ AND d.parent_right <= h.parent_right)
567+ AND m.location_dest_id IN (SELECT distinct d.id
568+ FROM stock_warehouse w, stock_location h, stock_location d
569+ WHERE w.lot_stock_id = h.id
570+ AND d.parent_left >= h.parent_left
571+ AND d.parent_right <= h.parent_right)
572+ GROUP BY m.product_id ORDER BY m.product_id) sl
573+ WHERE product_inventory.product_id = sl.product_id """)
574+
575+ # Useless, no ?
576+ #cr.execute("""UPDATE product_inventory SET onorder_qty = 0.0 WHERE coalesce(onorder_qty,0.0) = 0.0""")
577+
578+ cr.execute("""
579+ UPDATE product_inventory SET onorder_qty = onorder_qty - sl.product_qty
580+ FROM
581+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
582+ FROM stock_move m
583+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
584+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
585+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
586+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
587+ WHERE m.state != 'cancel' AND m.state != 'new'
588+ AND m.location_id IN (SELECT distinct d.id
589+ FROM stock_warehouse w, stock_location h, stock_location d
590+ WHERE w.lot_stock_id = h.id
591+ AND d.parent_left >= h.parent_left
592+ AND d.parent_right <= h.parent_right)
593+ AND m.location_dest_id NOT IN (SELECT distinct d.id
594+ FROM stock_warehouse w, stock_location h, stock_location d
595+ WHERE w.lot_stock_id = h.id
596+ AND d.parent_left >= h.parent_left
597+ AND d.parent_right <= h.parent_right)
598+ GROUP BY m.product_id ORDER BY m.product_id) sl
599+ WHERE product_inventory.product_id = sl.product_id """)
600+
601+
602+ #ondraft_qty
603+ cr.execute("""
604+ UPDATE product_inventory SET ondraft_qty = sl.product_qty
605+ FROM
606+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
607+ FROM purchase_order_line m
608+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
609+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
610+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
611+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
612+ WHERE m.state = 'draft'
613+ GROUP BY m.product_id ORDER BY m.product_id) sl
614+ WHERE product_inventory.product_id = sl.product_id """)
615+
616+ # Useless, no ?
617+ #cr.execute("""UPDATE product_inventory SET ondraft_qty = 0.0 WHERE coalesce(ondraft_qty,0.0) = 0.0""")
618+
619+ cr.execute("""UPDATE product_inventory SET out_stock = True WHERE onhand_qty < product_safe_qty""")
620+ return True
621+
622+product_inventory()
623+
624+
625+class product_inventory_dates(osv.osv):
626+ _name = 'product.inventory.dates'
627+ _description = 'Product Inventory between dates'
628+ _rec_name = "code"
629+ _order = 'code'
630+
631+ _columns = {
632+ 'product_id': fields.many2one('product.product', 'Product', required=True),
633+ 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True),
634+ 'start_qty': fields.float("Beginning Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
635+ 'buy_qty': fields.float("Purchase Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
636+ 'sale_qty': fields.float("Sale Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
637+ 'scrap_qty': fields.float("Scrap Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
638+ 'consume_qty': fields.float("Consumption Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
639+ 'produce_qty': fields.float("Production Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
640+ 'end_qty': fields.float("End Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
641+ 'start_value': fields.float("Start Value", digits_compute=dp.get_precision('Account')),
642+ 'start_price': fields.float("Start Price", digits_compute=dp.get_precision('Account')),
643+ 'buy_value': fields.float("Purchase Value", digits_compute=dp.get_precision('Account')),
644+ 'sale_value': fields.float("Sale Value", digits_compute=dp.get_precision('Account')),
645+ 'scrap_value': fields.float("Scrap Value", digits_compute=dp.get_precision('Account')),
646+ 'consume_value': fields.float("Consumption Value", digits_compute=dp.get_precision('Account')),
647+ 'produce_value': fields.float("Production Value", digits_compute=dp.get_precision('Account')),
648+ 'end_value': fields.float("End Value", digits_compute=dp.get_precision('Account')),
649+ 'end_price': fields.float("End Price", digits_compute=dp.get_precision('Account')),
650+ 'category_id': fields.many2one('product.category',string='Category'),
651+ 'stock_type_id': fields.many2one('product.stock_type',string='Stock Type'),
652+ 'uom_id': fields.many2one('product.uom',string='UoM'),
653+ 'code': fields.char('SKU', size=128,),
654+ 'from_date': fields.datetime('Start Date'),
655+ 'to_date': fields.datetime('End Date'),
656+ 'prod_active': fields.boolean("Product Active?"),
657+ }
658+ _defaults = {
659+ 'start_qty': 0.00,
660+ 'end_qty': 0.00,
661+ 'scrap_qty': 0.00,
662+ 'consume_qty': 0.00,
663+ 'produce_qty': 0.00,
664+ 'buy_qty': 0.00,
665+ 'sale_qty':0.00,
666+ }
667+
668+
669+ def _auto_init(self, cr, context=None):
670+ super(product_inventory_dates, self)._auto_init(cr, context=context)
671+ ###### Create Stored Function which calculated the Start and End prices ######
672+ cr.execute("SELECT proname FROM pg_catalog.pg_proc WHERE proname = 'set_product_inventory_dates_prices'")
673+ if not cr.fetchone():
674+ cr.execute("""
675+ CREATE OR REPLACE FUNCTION set_product_inventory_dates_prices() RETURNS integer AS $$
676+ DECLARE
677+ inventory RECORD;
678+ product_value numeric(5);
679+ BEGIN
680+ FOR inventory IN (SELECT product_id, product_tmpl_id, from_date, to_date FROM product_inventory_dates) LOOP
681+ -- Start Price
682+ product_value := 0;
683+ SELECT standard_price INTO product_value
684+ FROM product_price_history
685+ WHERE date <= inventory.from_date
686+ AND template_id = inventory.product_tmpl_id
687+ ORDER BY date DESC LIMIT 1;
688+
689+ IF NOT FOUND THEN
690+ UPDATE product_inventory_dates SET start_price=0.0 WHERE product_id=inventory.product_id;
691+ ELSE
692+ UPDATE product_inventory_dates SET start_price=product_value WHERE product_id=inventory.product_id;
693+ END IF;
694+
695+ -- End Price
696+ product_value := 0;
697+ SELECT standard_price INTO product_value
698+ FROM product_price_history
699+ WHERE date <= inventory.to_date
700+ AND template_id = inventory.product_tmpl_id
701+ ORDER BY date DESC LIMIT 1;
702+
703+ IF NOT FOUND THEN
704+ UPDATE product_inventory_dates SET end_price=0.0 WHERE product_id=inventory.product_id;
705+ ELSE
706+ UPDATE product_inventory_dates SET end_price=product_value WHERE product_id=inventory.product_id;
707+ END IF;
708+
709+ END LOOP;
710+ RETURN 1;
711+ END;
712+ $$ LANGUAGE plpgsql;""")
713+ cr.commit()
714+ ###### /END: Create Stored Functions ######
715+
716+
717+
718+ def compute_inventory(self, cr, uid, context=None):
719+ from_date = context.get('from_date','2013-04-01')
720+ to_date = context.get('to_date','2099-12-31')
721+
722+ cr.execute("""TRUNCATE TABLE product_inventory_dates""")
723+
724+ cr.execute("""INSERT INTO product_inventory_dates(product_id, product_tmpl_id, prod_active, from_date, to_date)
725+ SELECT id, product_tmpl_id, active, %s, %s FROM product_product
726+ ORDER BY default_code""", (from_date, to_date))
727+
728+ cr.execute("""
729+ UPDATE product_inventory_dates AS i
730+ SET code = p.default_code, uom_id = t.uom_id, category_id=t.categ_id, stock_type_id = t.stock_type_id,
731+ scrap_qty=0.000, consume_qty=0.000, produce_qty=0.000, buy_qty=0.000,sale_qty=0.000
732+ FROM product_product p, product_template t
733+ WHERE i.product_id = p.id AND p.product_tmpl_id = t.id""")
734+
735+ cr.execute("""SELECT * FROM set_product_inventory_dates_prices()""")
736+
737+ #start
738+ cr.execute("""
739+ UPDATE product_inventory_dates
740+ SET start_qty = sl.product_qty, start_value = round(coalesce((sl.product_qty * product_inventory_dates.start_price), 0.0),3)
741+ FROM
742+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
743+ FROM stock_move m
744+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
745+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
746+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
747+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
748+ WHERE m.state = 'done' AND m.date <= %s
749+ AND m.location_id NOT IN (SELECT distinct d.id
750+ FROM stock_warehouse w, stock_location h, stock_location d
751+ WHERE w.lot_stock_id = h.id
752+ AND d.parent_left >= h.parent_left
753+ AND d.parent_right <= h.parent_right)
754+ AND m.location_dest_id IN (SELECT distinct d.id
755+ FROM stock_warehouse w, stock_location h, stock_location d
756+ WHERE w.lot_stock_id = h.id
757+ AND d.parent_left >= h.parent_left
758+ AND d.parent_right <= h.parent_right)
759+ GROUP BY m.product_id ORDER BY m.product_id) sl
760+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date,))
761+
762+ # Useless, no ?
763+ #cr.execute("""UPDATE product_inventory_dates SET start_qty = 0.0 WHERE coalesce(start_qty,0.0) = 0.0""")
764+
765+ cr.execute("""
766+ UPDATE product_inventory_dates
767+ SET start_qty = start_qty - sl.product_qty, start_value = start_value - round(coalesce((sl.product_qty * product_inventory_dates.start_price), 0.0),3)
768+ FROM
769+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
770+ FROM stock_move m
771+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
772+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
773+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
774+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
775+ WHERE m.state = 'done' AND m.date <= %s
776+ AND m.location_id IN (SELECT distinct d.id
777+ FROM stock_warehouse w, stock_location h, stock_location d
778+ WHERE w.lot_stock_id = h.id
779+ AND d.parent_left >= h.parent_left
780+ AND d.parent_right <= h.parent_right)
781+ AND m.location_dest_id NOT IN (SELECT distinct d.id
782+ FROM stock_warehouse w, stock_location h, stock_location d
783+ WHERE w.lot_stock_id = h.id
784+ AND d.parent_left >= h.parent_left
785+ AND d.parent_right <= h.parent_right)
786+ GROUP BY m.product_id ORDER BY m.product_id) sl
787+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date,))
788+
789+
790+ #end
791+ cr.execute("""
792+ UPDATE product_inventory_dates
793+ SET end_qty = sl.product_qty, end_value = round(coalesce((sl.product_qty * product_inventory_dates.end_price), 0.0),3)
794+ FROM
795+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
796+ FROM stock_move m
797+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
798+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
799+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
800+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
801+ WHERE m.state = 'done' AND m.date <= %s
802+ AND m.location_id NOT IN (SELECT distinct d.id
803+ FROM stock_warehouse w, stock_location h, stock_location d
804+ WHERE w.lot_stock_id = h.id
805+ AND d.parent_left >= h.parent_left
806+ AND d.parent_right <= h.parent_right)
807+ AND m.location_dest_id IN (SELECT distinct d.id
808+ FROM stock_warehouse w, stock_location h, stock_location d
809+ WHERE w.lot_stock_id = h.id
810+ AND d.parent_left >= h.parent_left
811+ AND d.parent_right <= h.parent_right)
812+ GROUP BY m.product_id ORDER BY m.product_id) sl
813+ WHERE product_inventory_dates.product_id = sl.product_id """, (to_date,))
814+
815+ # Useless, no ?
816+ #cr.execute("""UPDATE product_inventory_dates SET end_qty = 0.0 WHERE coalesce(end_qty,0.0) = 0.0""")
817+
818+ cr.execute("""
819+ UPDATE product_inventory_dates
820+ SET end_qty = end_qty - sl.product_qty, end_value = end_value - round(coalesce((sl.product_qty * product_inventory_dates.end_price), 0.0),3)
821+ FROM
822+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
823+ FROM stock_move m
824+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
825+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
826+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
827+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
828+ WHERE m.state = 'done' AND m.date <= %s
829+ AND m.location_id IN (SELECT distinct d.id
830+ FROM stock_warehouse w, stock_location h, stock_location d
831+ WHERE w.lot_stock_id = h.id
832+ AND d.parent_left >= h.parent_left
833+ AND d.parent_right <= h.parent_right)
834+ AND m.location_dest_id NOT IN (SELECT distinct d.id
835+ FROM stock_warehouse w, stock_location h, stock_location d
836+ WHERE w.lot_stock_id = h.id
837+ AND d.parent_left >= h.parent_left
838+ AND d.parent_right <= h.parent_right)
839+ GROUP BY m.product_id ORDER BY m.product_id) sl
840+ WHERE product_inventory_dates.product_id = sl.product_id """, (to_date,))
841+
842+
843+ #buy
844+ cr.execute("""
845+ UPDATE product_inventory_dates
846+ SET buy_qty = sl.product_qty, buy_value = sl.product_value
847+ FROM
848+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor),0.0),3) AS product_qty,
849+ round(coalesce(sum(m.amount_total), 0.0),3) AS product_value
850+ FROM stock_move m
851+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
852+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
853+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
854+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
855+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
856+ AND m.location_id IN (SELECT id FROM stock_location WHERE usage='supplier')
857+ AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='supplier')
858+ GROUP BY m.product_id ORDER BY m.product_id) sl
859+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
860+ #po_price for return is negative
861+ cr.execute("""
862+ UPDATE product_inventory_dates
863+ SET buy_qty = buy_qty - sl.product_qty, buy_value = buy_value + sl.product_value
864+ FROM
865+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor),0.0),3) AS product_qty,
866+ round(coalesce(sum(m.amount_total), 0.0),3) AS product_value
867+ FROM stock_move m
868+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
869+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
870+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
871+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
872+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
873+ AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='supplier')
874+ AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='supplier')
875+ GROUP BY m.product_id ORDER BY m.product_id) sl
876+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
877+
878+
879+ #sale
880+ cr.execute("""
881+ UPDATE product_inventory_dates
882+ SET sale_qty = sl.product_qty, sale_value = sl.product_value
883+ FROM
884+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
885+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
886+ FROM stock_move m
887+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
888+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
889+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
890+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
891+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
892+ AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='customer')
893+ AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='customer')
894+ GROUP BY m.product_id ORDER BY m.product_id) sl
895+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
896+
897+ cr.execute("""
898+ UPDATE product_inventory_dates
899+ SET sale_qty = sale_qty - sl.product_qty, sale_value = sale_value - sl.product_value
900+ FROM
901+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
902+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
903+ FROM stock_move m
904+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
905+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
906+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
907+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
908+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
909+ AND m.location_id IN (SELECT id FROM stock_location WHERE usage='customer')
910+ AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='customer')
911+ GROUP BY m.product_id ORDER BY m.product_id) sl
912+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
913+
914+
915+ #scrap
916+ cr.execute("""
917+ UPDATE product_inventory_dates
918+ SET scrap_qty = sl.product_qty, scrap_value = sl.product_value
919+ FROM
920+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
921+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
922+ FROM stock_move m
923+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
924+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
925+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
926+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
927+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
928+ AND m.location_id IN (SELECT id FROM stock_location WHERE usage='inventory')
929+ AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='inventory')
930+ GROUP BY m.product_id ORDER BY m.product_id) sl
931+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
932+
933+ cr.execute("""
934+ UPDATE product_inventory_dates
935+ SET scrap_qty = scrap_qty - sl.product_qty, scrap_value = scrap_value - sl.product_value
936+ FROM
937+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
938+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
939+ FROM stock_move m
940+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
941+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
942+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
943+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
944+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
945+ AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='inventory')
946+ AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='inventory')
947+ GROUP BY m.product_id ORDER BY m.product_id) sl
948+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
949+
950+
951+ #consume
952+ cr.execute("""
953+ UPDATE product_inventory_dates
954+ SET consume_qty = sl.product_qty, consume_value = sl.product_value
955+ FROM
956+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
957+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
958+ FROM stock_move m
959+ --INNER JOIN mrp_production_move_ids mp on m.id = mp.move_id
960+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
961+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
962+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
963+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
964+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
965+ AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
966+ AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='production')
967+ GROUP BY m.product_id ORDER BY m.product_id) sl
968+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
969+
970+ cr.execute("""
971+ UPDATE product_inventory_dates
972+ SET consume_qty = consume_qty - sl.product_qty, consume_value = consume_value - sl.product_value
973+ FROM
974+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
975+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
976+ FROM stock_move m
977+ --INNER JOIN mrp_production_move_ids mp on m.id = mp.move_id
978+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
979+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
980+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
981+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
982+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
983+ AND m.location_id IN (SELECT id FROM stock_location WHERE usage='production')
984+ AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
985+ GROUP BY m.product_id ORDER BY m.product_id) sl
986+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
987+
988+
989+ #produce
990+ cr.execute("""
991+ UPDATE product_inventory_dates
992+ SET produce_qty = sl.product_qty, produce_value = sl.product_value
993+ FROM
994+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
995+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
996+ FROM stock_move m
997+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
998+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
999+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
1000+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
1001+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
1002+ AND m.production_id IS NOT NULL
1003+ AND m.location_id IN (SELECT id FROM stock_location WHERE usage='production')
1004+ AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
1005+ GROUP BY m.product_id ORDER BY m.product_id) sl
1006+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
1007+
1008+ cr.execute("""
1009+ UPDATE product_inventory_dates
1010+ SET produce_qty = produce_qty - sl.product_qty, produce_value = produce_value - sl.product_value
1011+ FROM
1012+ (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
1013+ round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
1014+ FROM stock_move m
1015+ LEFT JOIN product_product pp ON (m.product_id=pp.id)
1016+ LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
1017+ LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
1018+ LEFT JOIN product_uom u ON (m.product_uom=u.id)
1019+ WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
1020+ AND m.production_id IS NOT NULL
1021+ AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
1022+ AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='production')
1023+ GROUP BY m.product_id ORDER BY m.product_id) sl
1024+ WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
1025+
1026+ return True
1027+
1028+product_inventory_dates()
1029+
1030+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1031
1032=== added file 'product_inventory_warning/product_view.xml'
1033--- product_inventory_warning/product_view.xml 1970-01-01 00:00:00 +0000
1034+++ product_inventory_warning/product_view.xml 2013-08-26 08:54:27 +0000
1035@@ -0,0 +1,137 @@
1036+<?xml version="1.0" encoding="UTF-8"?>
1037+<openerp>
1038+ <data>
1039+ <record id="product_normal_form_view_safeqty" model="ir.ui.view">
1040+ <field name="name">product.normal.form.safeqty</field>
1041+ <field name="model">product.product</field>
1042+ <field name="type">form</field>
1043+ <field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/>
1044+ <field name="arch" type="xml">
1045+ <xpath expr="//field[@name='incoming_qty']" position="before">
1046+ <field name="product_safe_qty"/>
1047+ </xpath>
1048+ </field>
1049+ </record>
1050+
1051+ <record id="view_product_inventory_tree" model="ir.ui.view">
1052+ <field name="name">product.inventory.tree</field>
1053+ <field name="model">product.inventory</field>
1054+ <field name="type">tree</field>
1055+ <field name="arch" type="xml">
1056+ <tree string="Product Inventory" colors="red:onhand_qty &lt; product_safe_qty" >
1057+ <field name="stock_type_id"/>
1058+ <field name="category_id"/>
1059+ <field name="product_id"/>
1060+ <field name="name"/>
1061+ <field name="onhand_qty"/>
1062+ <field name="onorder_qty"/>
1063+ <field name="uom_id"/>
1064+ <field name="ondraft_qty"/>
1065+ <field name="product_safe_qty"/>
1066+ <field name="code" invisible="1"/>
1067+ <field name="date"/>
1068+ </tree>
1069+ </field>
1070+ </record>
1071+
1072+ <record id="view_product_inventory_search" model="ir.ui.view">
1073+ <field name="name">product.inventory.search</field>
1074+ <field name="model">product.inventory</field>
1075+ <field name="type">search</field>
1076+ <field name="arch" type="xml">
1077+ <search string="Product Inventory">
1078+ <field name="product_id"/>
1079+ <field name="stock_type_id"/>
1080+ <field name="category_id"/>
1081+ <field name="onhand_qty"/>
1082+ <filter string='Out of Stock' icon="terp-mrp" domain="[('out_stock','=',True)]"/>
1083+ <group expand='0' string='Group by...'>
1084+ <filter string='Category' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'category_id'}"/>
1085+ <filter string='Stock Type' icon="terp-mrp" domain="[]" context="{'group_by' : 'stock_type_id'}"/>
1086+ <filter string='Product' icon="terp-go-home" domain="[]" context="{'group_by' : 'product_id'}"/>
1087+ </group>
1088+ </search>
1089+ </field>
1090+ </record>
1091+
1092+ <record id="action_product_inventory_tree" model="ir.actions.act_window">
1093+ <field name="name">Product Inventory Warning</field>
1094+ <field name="res_model">product.inventory</field>
1095+ <field name="view_type">form</field>
1096+ <field name="view_mode">tree</field>
1097+ <field name="search_view_id" ref="view_product_inventory_search"/>
1098+ <field name="limit">60</field>
1099+ </record>
1100+
1101+ <menuitem
1102+ id="menu_action_product_inventory_tree"
1103+ parent="purchase.menu_procurement_management_product"
1104+ action="action_product_inventory_tree"
1105+ sequence = "95"/>
1106+
1107+
1108+ <record id="view_product_inventory_dates_tree" model="ir.ui.view">
1109+ <field name="name">product.inventory.dates.tree</field>
1110+ <field name="model">product.inventory.dates</field>
1111+ <field name="type">tree</field>
1112+ <field name="arch" type="xml">
1113+ <tree string="Product Inventory between dates">
1114+ <field name="stock_type_id"/>
1115+ <field name="category_id"/>
1116+ <field name="product_id"/>
1117+ <field name="start_qty" sum="Start Qty"/>
1118+ <field name="start_value" sum="Start Value"/>
1119+ <field name="buy_qty" sum="Buy Qty"/>
1120+ <field name="buy_value" sum="Buy Value"/>
1121+ <field name="sale_qty" sum="Sale Qty"/>
1122+ <field name="sale_value" sum="Sale Value"/>
1123+ <field name="scrap_qty" sum="Scrap Qty"/>
1124+ <field name="scrap_value" sum="Scrap Value"/>
1125+ <field name="consume_qty" sum="Consume Qty"/>
1126+ <field name="consume_value" sum="Consume Value"/>
1127+ <field name="produce_qty" sum="Produce Qty"/>
1128+ <field name="produce_value" sum="Produce Value"/>
1129+ <field name="end_qty" sum="End Qty"/>
1130+ <field name="end_value" sum="End Value"/>
1131+ <field name="code" invisible="1"/>
1132+ <field name="uom_id"/>
1133+ <field name="from_date"/>
1134+ <field name="to_date"/>
1135+ </tree>
1136+ </field>
1137+ </record>
1138+
1139+ <record id="view_product_inventory_dates_search" model="ir.ui.view">
1140+ <field name="name">product.inventory.dates.search</field>
1141+ <field name="model">product.inventory.dates</field>
1142+ <field name="type">search</field>
1143+ <field name="arch" type="xml">
1144+ <search string="Product Inventory between dates">
1145+ <field name="product_id"/>
1146+ <field name="stock_type_id"/>
1147+ <field name="category_id"/>
1148+ <group expand='0' string='Group by...'>
1149+ <filter string='Category' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'category_id'}"/>
1150+ <filter string='Stock Type' icon="terp-mrp" domain="[]" context="{'group_by' : 'stock_type_id'}"/>
1151+ <filter string='To Date' icon="terp-go-home" domain="[]" context="{'group_by' : 'to_date'}"/>
1152+ </group>
1153+ </search>
1154+ </field>
1155+ </record>
1156+
1157+ <record id="action_product_inventory_dates_tree" model="ir.actions.act_window">
1158+ <field name="name">Product Inventory between dates</field>
1159+ <field name="res_model">product.inventory.dates</field>
1160+ <field name="view_type">form</field>
1161+ <field name="view_mode">tree</field>
1162+ <field name="search_view_id" ref="view_product_inventory_dates_search"/>
1163+ <field name="limit">60</field>
1164+ </record>
1165+
1166+ <menuitem
1167+ id="menu_action_product_inventory_dates_tree"
1168+ parent="purchase.menu_procurement_management_product"
1169+ action="action_product_inventory_dates_tree"
1170+ sequence = "97"/>
1171+ </data>
1172+</openerp>
1173
1174=== added directory 'product_inventory_warning/security'
1175=== added file 'product_inventory_warning/security/ir.model.access.csv'
1176--- product_inventory_warning/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
1177+++ product_inventory_warning/security/ir.model.access.csv 2013-08-26 08:54:27 +0000
1178@@ -0,0 +1,3 @@
1179+id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
1180+access_product_inventory_wro,product_inventory wro,product_inventory_warning.model_product_inventory,stock.group_stock_user,1,0,0,0
1181+access_product_inventorydates_wro,product_inventory_dates wro,product_inventory_warning.model_product_inventory_dates,stock.group_stock_user,1,0,0,0
1182\ No newline at end of file
1183
1184=== added directory 'product_inventory_warning/wizard'
1185=== added file 'product_inventory_warning/wizard/__init__.py'
1186--- product_inventory_warning/wizard/__init__.py 1970-01-01 00:00:00 +0000
1187+++ product_inventory_warning/wizard/__init__.py 2013-08-26 08:54:27 +0000
1188@@ -0,0 +1,26 @@
1189+# -*- coding: utf-8 -*-
1190+##############################################################################
1191+#
1192+# OpenERP, Open Source Management Solution
1193+# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
1194+# Author: Andy Lu <andy.lu@elico-corp.com>
1195+#
1196+# This program is free software: you can redistribute it and/or modify
1197+# it under the terms of the GNU Affero General Public License as
1198+# published by the Free Software Foundation, either version 3 of the
1199+# License, or (at your option) any later version.
1200+#
1201+# This program is distributed in the hope that it will be useful,
1202+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1203+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1204+# GNU Affero General Public License for more details.
1205+#
1206+# You should have received a copy of the GNU Affero General Public License
1207+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1208+#
1209+##############################################################################
1210+
1211+import product_qty
1212+import product_sfc
1213+
1214+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1215
1216=== added file 'product_inventory_warning/wizard/product_qty.py'
1217--- product_inventory_warning/wizard/product_qty.py 1970-01-01 00:00:00 +0000
1218+++ product_inventory_warning/wizard/product_qty.py 2013-08-26 08:54:27 +0000
1219@@ -0,0 +1,69 @@
1220+# -*- coding: utf-8 -*-
1221+##############################################################################
1222+#
1223+# OpenERP, Open Source Management Solution
1224+# Copyright (c) 2010-Today Elico Corp. All Rights Reserved.
1225+# Author: Andy Lu <andy.lu@elico-corp.com>
1226+#
1227+# This program is free software: you can redistribute it and/or modify
1228+# it under the terms of the GNU Affero General Public License as
1229+# published by the Free Software Foundation, either version 3 of the
1230+# License, or (at your option) any later version.
1231+#
1232+# This program is distributed in the hope that it will be useful,
1233+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1234+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1235+# GNU Affero General Public License for more details.
1236+#
1237+# You should have received a copy of the GNU Affero General Public License
1238+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1239+#
1240+##############################################################################
1241+
1242+
1243+from osv import fields, osv
1244+from tools.translate import _
1245+
1246+class product_qty(osv.osv_memory):
1247+ _name = "run.product.inventory"
1248+ _description = "Compute Product Inventory"
1249+ _columns = {
1250+
1251+ }
1252+
1253+ def compute_inventory(self, cr, uid, ids, context=None):
1254+ """ To compute inventory.
1255+ @param self: The object pointer.
1256+ @param cr: A database cursor
1257+ @param uid: ID of the user currently logged in
1258+ @param ids: the ID or list of IDs if we want more than one
1259+ @param context: A standard dictionary
1260+ @return:
1261+ """
1262+ if context is None:
1263+ context = {}
1264+
1265+ pi_obj = self.pool.get('product.inventory')
1266+ pi_obj.compute_inventory(cr, uid)
1267+
1268+ mod_obj = self.pool.get('ir.model.data')
1269+
1270+ res = mod_obj.get_object_reference(cr, uid, 'product_inventory_warning', 'view_product_inventory_tree')
1271+ res_id = res and res[1] or False,
1272+
1273+ return {
1274+ 'name': _('Product Inventory'),
1275+ 'view_type': 'form',
1276+ 'view_mode': 'tree',
1277+ 'view_id': res_id,
1278+ 'res_model': 'product.inventory',
1279+ 'context': "{}",
1280+ 'type': 'ir.actions.act_window',
1281+ 'target': 'current',
1282+ 'res_id': False,
1283+ }
1284+ #return {'type': 'ir.actions.act_window_close'}
1285+
1286+product_qty()
1287+
1288+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1289
1290=== added file 'product_inventory_warning/wizard/product_qty_view.xml'
1291--- product_inventory_warning/wizard/product_qty_view.xml 1970-01-01 00:00:00 +0000
1292+++ product_inventory_warning/wizard/product_qty_view.xml 2013-08-26 08:54:27 +0000
1293@@ -0,0 +1,32 @@
1294+<?xml version="1.0" encoding="utf-8"?>
1295+<openerp>
1296+ <data>
1297+
1298+ <record id="view_run_product_inventory" model="ir.ui.view">
1299+ <field name="name">Compute Product Inventory</field>
1300+ <field name="model">run.product.inventory</field>
1301+ <field name="type">form</field>
1302+ <field name="arch" type="xml">
1303+ <form string="Compute Product Inventory">
1304+ <separator string="Compute Product Inventory based on current stock moves" colspan="4" />
1305+ <separator string="" colspan="4" />
1306+ <button special="cancel" string="_Cancel" icon='gtk-cancel'/>
1307+ <button name="compute_inventory" string="Compute" type="object" icon="gtk-ok"/>
1308+ </form>
1309+ </field>
1310+ </record>
1311+
1312+ <act_window name="Compute Product Inventory Warning"
1313+ res_model="run.product.inventory"
1314+ view_mode="form"
1315+ target="new"
1316+ context="{}"
1317+ id="action_run_product_inventory"/>
1318+
1319+ <menuitem
1320+ id="menu_action_run_product_inventory"
1321+ parent="purchase.menu_procurement_management_product"
1322+ action="action_run_product_inventory"
1323+ sequence = "90"/>
1324+ </data>
1325+</openerp>
1326
1327=== added file 'product_inventory_warning/wizard/product_sfc.py'
1328--- product_inventory_warning/wizard/product_sfc.py 1970-01-01 00:00:00 +0000
1329+++ product_inventory_warning/wizard/product_sfc.py 2013-08-26 08:54:27 +0000
1330@@ -0,0 +1,80 @@
1331+# -*- coding: utf-8 -*-
1332+##############################################################################
1333+#
1334+# OpenERP, Open Source Management Solution
1335+# Copyright (c) 2010-Today Elico Corp. All Rights Reserved.
1336+# Author: Andy Lu <andy.lu@elico-corp.com>
1337+#
1338+# This program is free software: you can redistribute it and/or modify
1339+# it under the terms of the GNU Affero General Public License as
1340+# published by the Free Software Foundation, either version 3 of the
1341+# License, or (at your option) any later version.
1342+#
1343+# This program is distributed in the hope that it will be useful,
1344+# but WITHOUT ANY WARRANTY; without even the implied warranty of
1345+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1346+# GNU Affero General Public License for more details.
1347+#
1348+# You should have received a copy of the GNU Affero General Public License
1349+# along with this program. If not, see <http://www.gnu.org/licenses/>.
1350+#
1351+##############################################################################
1352+
1353+
1354+from osv import fields, osv
1355+from tools.translate import _
1356+import time
1357+
1358+class product_sfc(osv.osv_memory):
1359+ _name = "run.product.inventory.dates"
1360+ _description = "Compute Product Inventory betweend dates"
1361+ _columns = {
1362+
1363+ 'from_date': fields.datetime('From', required=True),
1364+ 'to_date': fields.datetime('To', required=True),
1365+
1366+ }
1367+ _defaults = {
1368+ 'from_date': lambda *a: time.strftime('%Y-%m-%d 16:00:00'),
1369+ 'to_date': lambda *a: time.strftime('%Y-%m-%d 15:59:59'),
1370+ }
1371+
1372+ def compute_inventory(self, cr, uid, ids, context=None):
1373+ """ To compute inventory.
1374+ @param self: The object pointer.
1375+ @param cr: A database cursor
1376+ @param uid: ID of the user currently logged in
1377+ @param ids: the ID or list of IDs if we want more than one
1378+ @param context: A standard dictionary
1379+ @return:
1380+ """
1381+ if context is None:
1382+ context = {}
1383+ data = self.browse(cr, uid, ids, context=context)[0]
1384+ context['from_date'] = data.from_date
1385+ context['to_date'] = data.to_date
1386+
1387+ pi_obj = self.pool.get('product.inventory.dates')
1388+ pi_obj.compute_inventory(cr, uid, context)
1389+
1390+ mod_obj = self.pool.get('ir.model.data')
1391+
1392+ res = mod_obj.get_object_reference(cr, uid, 'product_inventory_warning', 'view_product_inventory_dates_tree')
1393+ res_id = res and res[1] or False,
1394+
1395+ return {
1396+ 'name': _('Product Inventory between dates'),
1397+ 'view_type': 'form',
1398+ 'view_mode': 'tree',
1399+ 'view_id': res_id,
1400+ 'res_model': 'product.inventory.dates',
1401+ 'context': "{}",
1402+ 'type': 'ir.actions.act_window',
1403+ 'target': 'current',
1404+ 'res_id': False,
1405+ }
1406+ #return {'type': 'ir.actions.act_window_close'}
1407+
1408+product_sfc()
1409+
1410+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
1411
1412=== added file 'product_inventory_warning/wizard/product_sfc_view.xml'
1413--- product_inventory_warning/wizard/product_sfc_view.xml 1970-01-01 00:00:00 +0000
1414+++ product_inventory_warning/wizard/product_sfc_view.xml 2013-08-26 08:54:27 +0000
1415@@ -0,0 +1,62 @@
1416+<?xml version="1.0" encoding="utf-8"?>
1417+<openerp>
1418+ <data>
1419+
1420+ <record id="view_run_product_inventory" model="ir.ui.view">
1421+ <field name="name">Compute Product Inventory</field>
1422+ <field name="model">run.product.inventory</field>
1423+ <field name="type">form</field>
1424+ <field name="arch" type="xml">
1425+ <form string="Compute Product Inventory">
1426+ <separator string="Compute Product Inventory based on current stock moves" colspan="4" />
1427+ <separator string="" colspan="4" />
1428+ <button special="cancel" string="_Cancel" icon='gtk-cancel'/>
1429+ <button name="compute_inventory" string="Compute" type="object" icon="gtk-ok"/>
1430+ </form>
1431+ </field>
1432+ </record>
1433+
1434+ <act_window name="Compute Product Inventory Warning"
1435+ res_model="run.product.inventory"
1436+ view_mode="form"
1437+ target="new"
1438+ context="{}"
1439+ id="action_run_product_inventory"/>
1440+
1441+ <menuitem
1442+ id="menu_action_run_product_inventory"
1443+ parent="purchase.menu_procurement_management_product"
1444+ action="action_run_product_inventory"
1445+ sequence = "90"/>
1446+
1447+
1448+ <record id="view_run_product_inventory_dates" model="ir.ui.view">
1449+ <field name="name">Compute Product Inventory between dates</field>
1450+ <field name="model">run.product.inventory.dates</field>
1451+ <field name="type">form</field>
1452+ <field name="arch" type="xml">
1453+ <form string="Compute Product Inventory between dates">
1454+ <separator string="Compute Product Inventory based on current stock moves and dates" colspan="4" />
1455+ <field name="from_date"/>
1456+ <field name="to_date"/>
1457+ <separator string="" colspan="4" />
1458+ <button special="cancel" string="_Cancel" icon='gtk-cancel'/>
1459+ <button name="compute_inventory" string="Compute" type="object" icon="gtk-ok"/>
1460+ </form>
1461+ </field>
1462+ </record>
1463+
1464+ <act_window name="Compute Product Inventory between dates"
1465+ res_model="run.product.inventory.dates"
1466+ view_mode="form"
1467+ target="new"
1468+ context="{}"
1469+ id="action_run_product_inventory_dates"/>
1470+
1471+ <menuitem
1472+ id="menu_action_run_product_inventory_dates"
1473+ parent="purchase.menu_procurement_management_product"
1474+ action="action_run_product_inventory_dates"
1475+ sequence = "96"/>
1476+ </data>
1477+</openerp>

Subscribers

People subscribed via source and target branches