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
=== added directory 'product_inventory_warning'
=== added file 'product_inventory_warning/__init__.py'
--- product_inventory_warning/__init__.py 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/__init__.py 2013-08-26 08:54:27 +0000
@@ -0,0 +1,27 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
6# Author: Andy Lu <andy.lu@elico-corp.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import product
24import wizard
25#import sale_compare
26
27# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0\ No newline at end of file28\ No newline at end of file
129
=== added file 'product_inventory_warning/__openerp__.py'
--- product_inventory_warning/__openerp__.py 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/__openerp__.py 2013-08-26 08:54:27 +0000
@@ -0,0 +1,53 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
6# Author: Andy Lu <andy.lu@elico-corp.com>
7# LIN Yu <lin.yu@elico-corp.com>
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU Affero General Public License as
11# published by the Free Software Foundation, either version 3 of the
12# License, or (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU Affero General Public License for more details.
18#
19# You should have received a copy of the GNU Affero General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
21#
22##############################################################################
23
24{
25 'name': 'Product Inventory Warning',
26 'version': '1',
27 'category': 'Product',
28 'sequence': 1,
29 'summary': 'Product Inventory Warning',
30 'description': """
31Product Inventory Warning
32==================================================
33
34Add a wizard to calculate the QTY of product.
35 """,
36 'author': 'Elico Corp',
37 'website': 'http://www.elico-corp.com',
38 'images' : [],
39 'depends': ['product', 'product_stock_type','product_separate_cost','stock_with_cost'],
40 'data': [
41 'product_view.xml',
42 'wizard/product_qty_view.xml',
43 'wizard/product_sfc_view.xml',
44 'security/ir.model.access.csv',
45 ],
46 'test': [],
47 'demo': [],
48 'installable': True,
49 'auto_install': False,
50 'application': False,
51}
52
53# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
054
=== added directory 'product_inventory_warning/i18n'
=== added file 'product_inventory_warning/i18n/zh_CN.po'
--- product_inventory_warning/i18n/zh_CN.po 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/i18n/zh_CN.po 2013-08-26 08:54:27 +0000
@@ -0,0 +1,315 @@
1# Translation of OpenERP Server.
2# This file contains the translation of the following modules:
3# * fc_product
4#
5msgid ""
6msgstr ""
7"Project-Id-Version: OpenERP Server 7.0\n"
8"Report-Msgid-Bugs-To: \n"
9"POT-Creation-Date: 2013-05-17 08:19+0000\n"
10"PO-Revision-Date: 2013-05-17 08:19+0000\n"
11"Last-Translator: <>\n"
12"Language-Team: \n"
13"MIME-Version: 1.0\n"
14"Content-Type: text/plain; charset=UTF-8\n"
15"Content-Transfer-Encoding: \n"
16"Plural-Forms: \n"
17
18#. module: fc_product
19#: view:product.inventory:0
20#: field:product.inventory,category_id:0
21#: view:product.inventory.dates:0
22#: field:product.inventory.dates,category_id:0
23msgid "Category"
24msgstr "种类"
25
26#. module: fc_product
27#: field:product.inventory,code:0
28#: field:product.inventory.dates,code:0
29msgid "SKU"
30msgstr "SKU"
31
32#. module: fc_product
33#: field:run.product.inventory.dates,from_date:0
34msgid "From"
35msgstr "开始"
36
37#. module: fc_product
38#: field:product.inventory.dates,produce_qty:0
39msgid "Production Quantity"
40msgstr "生产数量"
41
42#. module: fc_product
43#: model:ir.model,name:fc_product.model_run_product_inventory_dates
44msgid "Compute Product Inventory betweend dates"
45msgstr "根据时间生成产品粗困报表"
46
47#. module: fc_product
48#: field:run.product.inventory.dates,to_date:0
49msgid "To"
50msgstr "到"
51
52#. module: fc_product
53#: field:product.inventory.dates,start_value:0
54msgid "Start Value"
55msgstr "起初金额"
56
57#. module: fc_product
58#: field:product.inventory,ondraft_qty:0
59msgid "Not Confirm Quantity"
60msgstr "未审核采购数"
61
62#. module: fc_product
63#: field:product.inventory.dates,end_qty:0
64msgid "End Quantity"
65msgstr "期末数量"
66
67#. module: fc_product
68#: model:ir.model,name:fc_product.model_run_product_inventory
69#: view:run.product.inventory:0
70msgid "Compute Product Inventory"
71msgstr "计算产品库存"
72
73#. module: fc_product
74#: field:product.inventory.dates,consume_qty:0
75msgid "Consumption Quantity"
76msgstr "消耗数量"
77
78#. module: fc_product
79#: code:addons/fc_product/wizard/product_sfc.py:61
80#: code:addons/fc_product/wizard/sale_compare_wizard.py:61
81#: model:ir.actions.act_window,name:fc_product.action_product_inventory_dates_tree
82#: model:ir.model,name:fc_product.model_product_inventory_dates
83#: model:ir.ui.menu,name:fc_product.menu_action_product_inventory_dates_tree
84#: view:product.inventory.dates:0
85#, python-format
86msgid "Product Inventory between dates"
87msgstr "期间产品库存"
88
89#. module: fc_product
90#: field:product.inventory,onorder_qty:0
91msgid "Future Quantity"
92msgstr "预测数量"
93
94#. module: fc_product
95#: code:addons/fc_product/product.py:104
96#: code:addons/fc_product/product.py:106
97#: field:product.inventory,name_en:0
98#: field:product.inventory,name_sort_en:0
99#, python-format
100msgid "Name EN"
101msgstr "英文名"
102
103#. module: fc_product
104#: field:product.inventory.dates,start_qty:0
105msgid "Beginning Quantity"
106msgstr "起初数量"
107
108#. module: fc_product
109#: view:product.inventory:0
110#: field:product.inventory,stock_type_id:0
111#: view:product.inventory.dates:0
112#: field:product.inventory.dates,stock_type_id:0
113msgid "Stock Type"
114msgstr "仓储种类"
115
116#. module: fc_product
117#: field:product.inventory,date:0
118msgid "Creation Date"
119msgstr "创建时间"
120
121#. module: fc_product
122#: code:addons/fc_product/wizard/product_qty.py:55
123#: model:ir.model,name:fc_product.model_product_inventory
124#: view:product.inventory:0
125#, python-format
126msgid "Product Inventory"
127msgstr "产品库存"
128
129#. module: fc_product
130#: field:product.inventory.dates,produce_value:0
131msgid "Production Value"
132msgstr "生产金额"
133
134#. module: fc_product
135#: field:product.inventory,product_safe_qty:0
136#: field:product.product,product_safe_qty:0
137msgid "Minimum stock warning Quantity"
138msgstr "最小库存数量"
139
140#. module: fc_product
141#: code:addons/fc_product/sale_compare.py:63
142#, python-format
143msgid "ERP sub total"
144msgstr "ERP sub total"
145
146#. module: fc_product
147#: field:product.inventory.dates,consume_value:0
148msgid "Consumption Value"
149msgstr "消耗金额"
150
151#. module: fc_product
152#: code:addons/fc_product/product.py:101
153#: field:product.inventory,joomla_unit_cn:0
154#, python-format
155msgid "Website Product Unit in CN"
156msgstr "中文采购单位"
157
158#. module: fc_product
159#: field:product.inventory,onhand_qty:0
160msgid "Onhand Quantity"
161msgstr "在手数量"
162
163#. module: fc_product
164#: field:product.inventory,uom_id:0
165#: field:product.inventory.dates,uom_id:0
166msgid "UoM"
167msgstr "单位"
168
169#. module: fc_product
170#: field:product.inventory.dates,scrap_value:0
171msgid "Scrap Value"
172msgstr "报废金额"
173
174#. module: fc_product
175#: field:product.inventory.dates,to_date:0
176msgid "End Date"
177msgstr "结束时间"
178
179#. module: fc_product
180#: view:run.product.inventory:0
181#: view:run.product.inventory.dates:0
182msgid "Compute"
183msgstr "计算"
184
185#. module: fc_product
186#: view:run.product.inventory.dates:0
187msgid "Compute Product Inventory based on current stock moves and dates"
188msgstr "根据当前调拨和日期计算产品库存"
189
190#. module: fc_product
191#: view:run.product.inventory:0
192msgid "Compute Product Inventory based on current stock moves"
193msgstr "根据库存调拨计算产品数量"
194
195#. module: fc_product
196#: model:ir.actions.act_window,name:fc_product.action_product_inventory_tree
197#: model:ir.ui.menu,name:fc_product.menu_action_product_inventory_tree
198msgid "Product Inventory Warning"
199msgstr "最小库存报警"
200
201#. module: fc_product
202#: model:ir.model,name:fc_product.model_product_product
203#: view:product.inventory:0
204#: view:product.inventory.dates:0
205#: field:product.inventory.dates,product_id:0
206msgid "Product"
207msgstr "产品"
208
209#. module: fc_product
210#: model:ir.actions.act_window,name:fc_product.action_run_product_inventory
211#: model:ir.ui.menu,name:fc_product.menu_action_run_product_inventory
212msgid "Compute Product Inventory Warning"
213msgstr "计算最小库存报警"
214
215#. module: fc_product
216#: field:product.inventory.dates,end_price:0
217msgid "End Price"
218msgstr "期末价格"
219
220#. module: fc_product
221#: field:product.inventory,product_id:0
222msgid "Products"
223msgstr "产品"
224
225#. module: fc_product
226#: code:addons/fc_product/product.py:100
227#: field:product.inventory,joomla_unit:0
228#, python-format
229msgid "Website Product Unit"
230msgstr "产品单位中文"
231
232#. module: fc_product
233#: field:product.inventory.dates,sale_value:0
234msgid "Sale Value"
235msgstr "销售金额"
236
237#. module: fc_product
238#: field:product.inventory.dates,sale_qty:0
239msgid "Sale Quantity"
240msgstr "销售数量"
241
242#. module: fc_product
243#: model:ir.actions.act_window,name:fc_product.action_run_product_inventory_dates
244#: model:ir.ui.menu,name:fc_product.menu_action_run_product_inventory_dates
245#: view:run.product.inventory.dates:0
246msgid "Compute Product Inventory between dates"
247msgstr "根据日期计算产品库存"
248
249#. module: fc_product
250#: field:product.inventory.dates,buy_value:0
251msgid "Purchase Value"
252msgstr "采购金额"
253
254#. module: fc_product
255#: view:product.inventory:0
256msgid "Out of Stock"
257msgstr "缺货产品"
258
259#. module: fc_product
260#: model:ir.model,name:fc_product.model_product_template
261#: field:product.inventory.dates,product_tmpl_id:0
262msgid "Product Template"
263msgstr "产品模板"
264
265#. module: fc_product
266#: field:product.inventory.dates,scrap_qty:0
267msgid "Scrap Quantity"
268msgstr "Scrap Quantity"
269
270#. module: fc_product
271#: field:product.inventory,out_stock:0
272msgid "Out Stock"
273msgstr "Out Stock"
274
275#. module: fc_product
276#: view:product.inventory:0
277#: view:product.inventory.dates:0
278msgid "Group by..."
279msgstr "分组..."
280
281#. module: fc_product
282#: field:product.inventory.dates,end_value:0
283msgid "End Value"
284msgstr "期末金额"
285
286#. module: fc_product
287#: view:run.product.inventory:0
288#: view:run.product.inventory.dates:0
289msgid "_Cancel"
290msgstr "_取消"
291
292#. module: fc_product
293#: code:addons/fc_product/product.py:105
294#: code:addons/fc_product/product.py:107
295#: field:product.inventory,name_cn:0
296#: field:product.inventory,name_sort_cn:0
297#, python-format
298msgid "Name CN"
299msgstr "中文名"
300
301#. module: fc_product
302#: field:product.inventory.dates,from_date:0
303msgid "Start Date"
304msgstr "开始时间"
305
306#. module: fc_product
307#: field:product.inventory.dates,start_price:0
308msgid "Start Price"
309msgstr "开始价格"
310
311#. module: fc_product
312#: field:product.inventory.dates,buy_qty:0
313msgid "Purchase Quantity"
314msgstr "采购数量"
315
0316
=== added file 'product_inventory_warning/product.py'
--- product_inventory_warning/product.py 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/product.py 2013-08-26 08:54:27 +0000
@@ -0,0 +1,613 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
6# Author: Yannick Gouin <yannick.gouin@elico-corp.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it wil l be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23from osv import osv, fields
24import openerp.addons.decimal_precision as dp
25import time, pytz
26from datetime import datetime
27from tools.translate import _
28
29class product_product(osv.osv):
30 _inherit = 'product.product'
31
32 _columns = {
33 'product_safe_qty': fields.float('Minimum stock warning Quantity', digits_compute=dp.get_precision('Product Unit of Measure')),
34 }
35 _defaults = {
36 'product_safe_qty': 0.0,
37 }
38product_product()
39
40
41class product_inventory(osv.osv):
42 _name = 'product.inventory'
43 _description = 'Product Inventory'
44 _rec_name = "code"
45 _order = 'code'
46
47 _columns = {
48 'product_id': fields.many2one('product.product', 'Products', required=True),
49 'onhand_qty': fields.float("Onhand Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
50 'onorder_qty': fields.float("Future Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
51 'ondraft_qty': fields.float("Not Confirm Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
52 'date': fields.datetime('Creation Date'),
53 'category_id': fields.many2one('product.category',string='Category'),
54 'stock_type_id': fields.many2one('product.stock_type',string='Stock Type'),
55 'uom_id': fields.many2one('product.uom',string='UoM'),
56 'code': fields.char('SKU', size=128,),
57 'product_safe_qty': fields.float('Minimum stock warning Quantity', digits_compute=dp.get_precision('Product Unit of Measure')),
58 'name': fields.related('product_id', 'name', string=_('Name'), type='char', size=128),
59 'out_stock':fields.boolean("Out Stock"),
60 }
61 _defaults = {
62 'onhand_qty': 0.0,
63 'onorder_qty': 0.0,
64 'ondraft_qty': 0.0,
65 'product_safe_qty': 0.0,
66 'date': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
67 }
68
69
70 def compute_inventory(self, cr, uid, context=None):
71 #prod_obj = self.pool.get('product.product')
72 cr.execute("""TRUNCATE TABLE product_inventory""")
73 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""")
74 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""")
75 cr.execute("""
76 UPDATE product_inventory AS i
77 SET code = p.default_code, category_id = t.categ_id,
78 stock_type_id = t.stock_type_id, uom_id = t.uom_id, product_safe_qty = p.product_safe_qty
79 FROM product_product p, product_template t
80 WHERE i.product_id = p.id AND p.product_tmpl_id = t.id""")
81
82 #onhand_qty
83 cr.execute("""
84 UPDATE product_inventory
85 SET onhand_qty = sl.product_qty
86 FROM
87 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
88 FROM stock_move m
89 LEFT JOIN product_product pp ON (m.product_id=pp.id)
90 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
91 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
92 LEFT JOIN product_uom u ON (m.product_uom=u.id)
93 WHERE m.state = 'done'
94 AND m.location_id NOT IN (SELECT distinct d.id
95 FROM stock_warehouse w, stock_location h, stock_location d
96 WHERE w.lot_stock_id = h.id
97 AND d.parent_left >= h.parent_left
98 AND d.parent_right <= h.parent_right)
99 AND m.location_dest_id IN (SELECT distinct d.id
100 FROM stock_warehouse w, stock_location h, stock_location d
101 WHERE w.lot_stock_id = h.id
102 AND d.parent_left >= h.parent_left
103 AND d.parent_right <= h.parent_right)
104 GROUP BY m.product_id ORDER BY m.product_id) sl
105 WHERE product_inventory.product_id = sl.product_id """)
106
107 # Useless, no ?
108 #cr.execute("""UPDATE product_inventory SET onhand_qty = 0.0 WHERE coalesce(onhand_qty,0.0) = 0.0""")
109
110 cr.execute("""
111 UPDATE product_inventory SET onhand_qty = onhand_qty - sl.product_qty
112 FROM
113 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
114 FROM stock_move m
115 LEFT JOIN product_product pp ON (m.product_id=pp.id)
116 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
117 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
118 LEFT JOIN product_uom u ON (m.product_uom=u.id)
119 WHERE m.state = 'done'
120 AND m.location_id IN (SELECT distinct d.id
121 FROM stock_warehouse w, stock_location h, stock_location d
122 WHERE w.lot_stock_id = h.id
123 AND d.parent_left >= h.parent_left
124 AND d.parent_right <= h.parent_right)
125 AND m.location_dest_id NOT IN (SELECT distinct d.id
126 FROM stock_warehouse w, stock_location h, stock_location d
127 WHERE w.lot_stock_id = h.id
128 AND d.parent_left >= h.parent_left
129 AND d.parent_right <= h.parent_right)
130 GROUP BY m.product_id ORDER BY m.product_id) sl
131 WHERE product_inventory.product_id = sl.product_id """)
132
133
134 #onorder_qty
135 cr.execute("""
136 UPDATE product_inventory SET onorder_qty = sl.product_qty
137 FROM
138 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
139 FROM stock_move m
140 LEFT JOIN product_product pp ON (m.product_id=pp.id)
141 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
142 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
143 LEFT JOIN product_uom u ON (m.product_uom=u.id)
144 WHERE m.state != 'cancel' AND m.state != 'new'
145 AND m.location_id NOT IN (SELECT distinct d.id
146 FROM stock_warehouse w, stock_location h, stock_location d
147 WHERE w.lot_stock_id = h.id
148 AND d.parent_left >= h.parent_left
149 AND d.parent_right <= h.parent_right)
150 AND m.location_dest_id IN (SELECT distinct d.id
151 FROM stock_warehouse w, stock_location h, stock_location d
152 WHERE w.lot_stock_id = h.id
153 AND d.parent_left >= h.parent_left
154 AND d.parent_right <= h.parent_right)
155 GROUP BY m.product_id ORDER BY m.product_id) sl
156 WHERE product_inventory.product_id = sl.product_id """)
157
158 # Useless, no ?
159 #cr.execute("""UPDATE product_inventory SET onorder_qty = 0.0 WHERE coalesce(onorder_qty,0.0) = 0.0""")
160
161 cr.execute("""
162 UPDATE product_inventory SET onorder_qty = onorder_qty - sl.product_qty
163 FROM
164 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
165 FROM stock_move m
166 LEFT JOIN product_product pp ON (m.product_id=pp.id)
167 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
168 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
169 LEFT JOIN product_uom u ON (m.product_uom=u.id)
170 WHERE m.state != 'cancel' AND m.state != 'new'
171 AND m.location_id IN (SELECT distinct d.id
172 FROM stock_warehouse w, stock_location h, stock_location d
173 WHERE w.lot_stock_id = h.id
174 AND d.parent_left >= h.parent_left
175 AND d.parent_right <= h.parent_right)
176 AND m.location_dest_id NOT IN (SELECT distinct d.id
177 FROM stock_warehouse w, stock_location h, stock_location d
178 WHERE w.lot_stock_id = h.id
179 AND d.parent_left >= h.parent_left
180 AND d.parent_right <= h.parent_right)
181 GROUP BY m.product_id ORDER BY m.product_id) sl
182 WHERE product_inventory.product_id = sl.product_id """)
183
184
185 #ondraft_qty
186 cr.execute("""
187 UPDATE product_inventory SET ondraft_qty = sl.product_qty
188 FROM
189 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
190 FROM purchase_order_line m
191 LEFT JOIN product_product pp ON (m.product_id=pp.id)
192 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
193 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
194 LEFT JOIN product_uom u ON (m.product_uom=u.id)
195 WHERE m.state = 'draft'
196 GROUP BY m.product_id ORDER BY m.product_id) sl
197 WHERE product_inventory.product_id = sl.product_id """)
198
199 # Useless, no ?
200 #cr.execute("""UPDATE product_inventory SET ondraft_qty = 0.0 WHERE coalesce(ondraft_qty,0.0) = 0.0""")
201
202 cr.execute("""UPDATE product_inventory SET out_stock = True WHERE onhand_qty < product_safe_qty""")
203 return True
204
205product_inventory()
206
207
208class product_inventory_dates(osv.osv):
209 _name = 'product.inventory.dates'
210 _description = 'Product Inventory between dates'
211 _rec_name = "code"
212 _order = 'code'
213
214 _columns = {
215 'product_id': fields.many2one('product.product', 'Product', required=True),
216 'product_tmpl_id': fields.many2one('product.template', 'Product Template', required=True),
217 'start_qty': fields.float("Beginning Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
218 'buy_qty': fields.float("Purchase Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
219 'sale_qty': fields.float("Sale Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
220 'scrap_qty': fields.float("Scrap Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
221 'consume_qty': fields.float("Consumption Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
222 'produce_qty': fields.float("Production Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
223 'end_qty': fields.float("End Quantity", digits_compute=dp.get_precision('Product Unit of Measure')),
224 'start_value': fields.float("Start Value", digits_compute=dp.get_precision('Account')),
225 'start_price': fields.float("Start Price", digits_compute=dp.get_precision('Account')),
226 'buy_value': fields.float("Purchase Value", digits_compute=dp.get_precision('Account')),
227 'sale_value': fields.float("Sale Value", digits_compute=dp.get_precision('Account')),
228 'scrap_value': fields.float("Scrap Value", digits_compute=dp.get_precision('Account')),
229 'consume_value': fields.float("Consumption Value", digits_compute=dp.get_precision('Account')),
230 'produce_value': fields.float("Production Value", digits_compute=dp.get_precision('Account')),
231 'end_value': fields.float("End Value", digits_compute=dp.get_precision('Account')),
232 'end_price': fields.float("End Price", digits_compute=dp.get_precision('Account')),
233 'category_id': fields.many2one('product.category',string='Category'),
234 'stock_type_id': fields.many2one('product.stock_type',string='Stock Type'),
235 'uom_id': fields.many2one('product.uom',string='UoM'),
236 'code': fields.char('SKU', size=128,),
237 'from_date': fields.datetime('Start Date'),
238 'to_date': fields.datetime('End Date'),
239 'prod_active': fields.boolean("Product Active?"),
240 }
241 _defaults = {
242 'start_qty': 0.00,
243 'end_qty': 0.00,
244 'scrap_qty': 0.00,
245 'consume_qty': 0.00,
246 'produce_qty': 0.00,
247 'buy_qty': 0.00,
248 'sale_qty':0.00,
249 }
250
251
252 def _auto_init(self, cr, context=None):
253 super(product_inventory_dates, self)._auto_init(cr, context=context)
254 ###### Create Stored Function which calculated the Start and End prices ######
255 cr.execute("SELECT proname FROM pg_catalog.pg_proc WHERE proname = 'set_product_inventory_dates_prices'")
256 if not cr.fetchone():
257 cr.execute("""
258 CREATE OR REPLACE FUNCTION set_product_inventory_dates_prices() RETURNS integer AS $$
259 DECLARE
260 inventory RECORD;
261 product_value numeric(5);
262 BEGIN
263 FOR inventory IN (SELECT product_id, product_tmpl_id, from_date, to_date FROM product_inventory_dates) LOOP
264 -- Start Price
265 product_value := 0;
266 SELECT standard_price INTO product_value
267 FROM product_price_history
268 WHERE date <= inventory.from_date
269 AND template_id = inventory.product_tmpl_id
270 ORDER BY date DESC LIMIT 1;
271
272 IF NOT FOUND THEN
273 UPDATE product_inventory_dates SET start_price=0.0 WHERE product_id=inventory.product_id;
274 ELSE
275 UPDATE product_inventory_dates SET start_price=product_value WHERE product_id=inventory.product_id;
276 END IF;
277
278 -- End Price
279 product_value := 0;
280 SELECT standard_price INTO product_value
281 FROM product_price_history
282 WHERE date <= inventory.to_date
283 AND template_id = inventory.product_tmpl_id
284 ORDER BY date DESC LIMIT 1;
285
286 IF NOT FOUND THEN
287 UPDATE product_inventory_dates SET end_price=0.0 WHERE product_id=inventory.product_id;
288 ELSE
289 UPDATE product_inventory_dates SET end_price=product_value WHERE product_id=inventory.product_id;
290 END IF;
291
292 END LOOP;
293 RETURN 1;
294 END;
295 $$ LANGUAGE plpgsql;""")
296 cr.commit()
297 ###### /END: Create Stored Functions ######
298
299
300
301 def compute_inventory(self, cr, uid, context=None):
302 from_date = context.get('from_date','2013-04-01')
303 to_date = context.get('to_date','2099-12-31')
304
305 cr.execute("""TRUNCATE TABLE product_inventory_dates""")
306
307 cr.execute("""INSERT INTO product_inventory_dates(product_id, product_tmpl_id, prod_active, from_date, to_date)
308 SELECT id, product_tmpl_id, active, %s, %s FROM product_product
309 ORDER BY default_code""", (from_date, to_date))
310
311 cr.execute("""
312 UPDATE product_inventory_dates AS i
313 SET code = p.default_code, uom_id = t.uom_id, category_id=t.categ_id, stock_type_id = t.stock_type_id,
314 scrap_qty=0.000, consume_qty=0.000, produce_qty=0.000, buy_qty=0.000,sale_qty=0.000
315 FROM product_product p, product_template t
316 WHERE i.product_id = p.id AND p.product_tmpl_id = t.id""")
317
318 cr.execute("""SELECT * FROM set_product_inventory_dates_prices()""")
319
320 #start
321 cr.execute("""
322 UPDATE product_inventory_dates
323 SET start_qty = sl.product_qty, start_value = round(coalesce((sl.product_qty * product_inventory_dates.start_price), 0.0),3)
324 FROM
325 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
326 FROM stock_move m
327 LEFT JOIN product_product pp ON (m.product_id=pp.id)
328 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
329 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
330 LEFT JOIN product_uom u ON (m.product_uom=u.id)
331 WHERE m.state = 'done' AND m.date <= %s
332 AND m.location_id NOT IN (SELECT distinct d.id
333 FROM stock_warehouse w, stock_location h, stock_location d
334 WHERE w.lot_stock_id = h.id
335 AND d.parent_left >= h.parent_left
336 AND d.parent_right <= h.parent_right)
337 AND m.location_dest_id IN (SELECT distinct d.id
338 FROM stock_warehouse w, stock_location h, stock_location d
339 WHERE w.lot_stock_id = h.id
340 AND d.parent_left >= h.parent_left
341 AND d.parent_right <= h.parent_right)
342 GROUP BY m.product_id ORDER BY m.product_id) sl
343 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date,))
344
345 # Useless, no ?
346 #cr.execute("""UPDATE product_inventory_dates SET start_qty = 0.0 WHERE coalesce(start_qty,0.0) = 0.0""")
347
348 cr.execute("""
349 UPDATE product_inventory_dates
350 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)
351 FROM
352 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
353 FROM stock_move m
354 LEFT JOIN product_product pp ON (m.product_id=pp.id)
355 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
356 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
357 LEFT JOIN product_uom u ON (m.product_uom=u.id)
358 WHERE m.state = 'done' AND m.date <= %s
359 AND m.location_id IN (SELECT distinct d.id
360 FROM stock_warehouse w, stock_location h, stock_location d
361 WHERE w.lot_stock_id = h.id
362 AND d.parent_left >= h.parent_left
363 AND d.parent_right <= h.parent_right)
364 AND m.location_dest_id NOT IN (SELECT distinct d.id
365 FROM stock_warehouse w, stock_location h, stock_location d
366 WHERE w.lot_stock_id = h.id
367 AND d.parent_left >= h.parent_left
368 AND d.parent_right <= h.parent_right)
369 GROUP BY m.product_id ORDER BY m.product_id) sl
370 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date,))
371
372
373 #end
374 cr.execute("""
375 UPDATE product_inventory_dates
376 SET end_qty = sl.product_qty, end_value = round(coalesce((sl.product_qty * product_inventory_dates.end_price), 0.0),3)
377 FROM
378 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
379 FROM stock_move m
380 LEFT JOIN product_product pp ON (m.product_id=pp.id)
381 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
382 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
383 LEFT JOIN product_uom u ON (m.product_uom=u.id)
384 WHERE m.state = 'done' AND m.date <= %s
385 AND m.location_id NOT IN (SELECT distinct d.id
386 FROM stock_warehouse w, stock_location h, stock_location d
387 WHERE w.lot_stock_id = h.id
388 AND d.parent_left >= h.parent_left
389 AND d.parent_right <= h.parent_right)
390 AND m.location_dest_id IN (SELECT distinct d.id
391 FROM stock_warehouse w, stock_location h, stock_location d
392 WHERE w.lot_stock_id = h.id
393 AND d.parent_left >= h.parent_left
394 AND d.parent_right <= h.parent_right)
395 GROUP BY m.product_id ORDER BY m.product_id) sl
396 WHERE product_inventory_dates.product_id = sl.product_id """, (to_date,))
397
398 # Useless, no ?
399 #cr.execute("""UPDATE product_inventory_dates SET end_qty = 0.0 WHERE coalesce(end_qty,0.0) = 0.0""")
400
401 cr.execute("""
402 UPDATE product_inventory_dates
403 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)
404 FROM
405 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty
406 FROM stock_move m
407 LEFT JOIN product_product pp ON (m.product_id=pp.id)
408 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
409 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
410 LEFT JOIN product_uom u ON (m.product_uom=u.id)
411 WHERE m.state = 'done' AND m.date <= %s
412 AND m.location_id IN (SELECT distinct d.id
413 FROM stock_warehouse w, stock_location h, stock_location d
414 WHERE w.lot_stock_id = h.id
415 AND d.parent_left >= h.parent_left
416 AND d.parent_right <= h.parent_right)
417 AND m.location_dest_id NOT IN (SELECT distinct d.id
418 FROM stock_warehouse w, stock_location h, stock_location d
419 WHERE w.lot_stock_id = h.id
420 AND d.parent_left >= h.parent_left
421 AND d.parent_right <= h.parent_right)
422 GROUP BY m.product_id ORDER BY m.product_id) sl
423 WHERE product_inventory_dates.product_id = sl.product_id """, (to_date,))
424
425
426 #buy
427 cr.execute("""
428 UPDATE product_inventory_dates
429 SET buy_qty = sl.product_qty, buy_value = sl.product_value
430 FROM
431 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor),0.0),3) AS product_qty,
432 round(coalesce(sum(m.amount_total), 0.0),3) AS product_value
433 FROM stock_move m
434 LEFT JOIN product_product pp ON (m.product_id=pp.id)
435 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
436 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
437 LEFT JOIN product_uom u ON (m.product_uom=u.id)
438 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
439 AND m.location_id IN (SELECT id FROM stock_location WHERE usage='supplier')
440 AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='supplier')
441 GROUP BY m.product_id ORDER BY m.product_id) sl
442 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
443 #po_price for return is negative
444 cr.execute("""
445 UPDATE product_inventory_dates
446 SET buy_qty = buy_qty - sl.product_qty, buy_value = buy_value + sl.product_value
447 FROM
448 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor),0.0),3) AS product_qty,
449 round(coalesce(sum(m.amount_total), 0.0),3) AS product_value
450 FROM stock_move m
451 LEFT JOIN product_product pp ON (m.product_id=pp.id)
452 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
453 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
454 LEFT JOIN product_uom u ON (m.product_uom=u.id)
455 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
456 AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='supplier')
457 AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='supplier')
458 GROUP BY m.product_id ORDER BY m.product_id) sl
459 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
460
461
462 #sale
463 cr.execute("""
464 UPDATE product_inventory_dates
465 SET sale_qty = sl.product_qty, sale_value = sl.product_value
466 FROM
467 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
468 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
469 FROM stock_move m
470 LEFT JOIN product_product pp ON (m.product_id=pp.id)
471 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
472 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
473 LEFT JOIN product_uom u ON (m.product_uom=u.id)
474 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
475 AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='customer')
476 AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='customer')
477 GROUP BY m.product_id ORDER BY m.product_id) sl
478 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
479
480 cr.execute("""
481 UPDATE product_inventory_dates
482 SET sale_qty = sale_qty - sl.product_qty, sale_value = sale_value - sl.product_value
483 FROM
484 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
485 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
486 FROM stock_move m
487 LEFT JOIN product_product pp ON (m.product_id=pp.id)
488 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
489 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
490 LEFT JOIN product_uom u ON (m.product_uom=u.id)
491 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
492 AND m.location_id IN (SELECT id FROM stock_location WHERE usage='customer')
493 AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='customer')
494 GROUP BY m.product_id ORDER BY m.product_id) sl
495 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
496
497
498 #scrap
499 cr.execute("""
500 UPDATE product_inventory_dates
501 SET scrap_qty = sl.product_qty, scrap_value = sl.product_value
502 FROM
503 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
504 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
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' AND m.date >= %s AND m.date <= %s
511 AND m.location_id IN (SELECT id FROM stock_location WHERE usage='inventory')
512 AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='inventory')
513 GROUP BY m.product_id ORDER BY m.product_id) sl
514 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
515
516 cr.execute("""
517 UPDATE product_inventory_dates
518 SET scrap_qty = scrap_qty - sl.product_qty, scrap_value = scrap_value - sl.product_value
519 FROM
520 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
521 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
522 FROM stock_move m
523 LEFT JOIN product_product pp ON (m.product_id=pp.id)
524 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
525 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
526 LEFT JOIN product_uom u ON (m.product_uom=u.id)
527 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
528 AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='inventory')
529 AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='inventory')
530 GROUP BY m.product_id ORDER BY m.product_id) sl
531 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
532
533
534 #consume
535 cr.execute("""
536 UPDATE product_inventory_dates
537 SET consume_qty = sl.product_qty, consume_value = sl.product_value
538 FROM
539 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
540 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
541 FROM stock_move m
542 --INNER JOIN mrp_production_move_ids mp on m.id = mp.move_id
543 LEFT JOIN product_product pp ON (m.product_id=pp.id)
544 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
545 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
546 LEFT JOIN product_uom u ON (m.product_uom=u.id)
547 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
548 AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
549 AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='production')
550 GROUP BY m.product_id ORDER BY m.product_id) sl
551 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
552
553 cr.execute("""
554 UPDATE product_inventory_dates
555 SET consume_qty = consume_qty - sl.product_qty, consume_value = consume_value - sl.product_value
556 FROM
557 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
558 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
559 FROM stock_move m
560 --INNER JOIN mrp_production_move_ids mp on m.id = mp.move_id
561 LEFT JOIN product_product pp ON (m.product_id=pp.id)
562 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
563 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
564 LEFT JOIN product_uom u ON (m.product_uom=u.id)
565 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
566 AND m.location_id IN (SELECT id FROM stock_location WHERE usage='production')
567 AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
568 GROUP BY m.product_id ORDER BY m.product_id) sl
569 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
570
571
572 #produce
573 cr.execute("""
574 UPDATE product_inventory_dates
575 SET produce_qty = sl.product_qty, produce_value = sl.product_value
576 FROM
577 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
578 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
579 FROM stock_move m
580 LEFT JOIN product_product pp ON (m.product_id=pp.id)
581 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
582 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
583 LEFT JOIN product_uom u ON (m.product_uom=u.id)
584 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
585 AND m.production_id IS NOT NULL
586 AND m.location_id IN (SELECT id FROM stock_location WHERE usage='production')
587 AND m.location_dest_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
588 GROUP BY m.product_id ORDER BY m.product_id) sl
589 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
590
591 cr.execute("""
592 UPDATE product_inventory_dates
593 SET produce_qty = produce_qty - sl.product_qty, produce_value = produce_value - sl.product_value
594 FROM
595 (SELECT m.product_id, round(coalesce(sum(m.product_qty * pu.factor / u.factor), 0.0),3) AS product_qty,
596 round(coalesce(sum(m.product_qty * pu.factor / u.factor * m.price_unit), 0.0),3) AS product_value
597 FROM stock_move m
598 LEFT JOIN product_product pp ON (m.product_id=pp.id)
599 LEFT JOIN product_template pt ON (pp.product_tmpl_id=pt.id)
600 LEFT JOIN product_uom pu ON (pt.uom_id=pu.id)
601 LEFT JOIN product_uom u ON (m.product_uom=u.id)
602 WHERE m.state = 'done' AND m.date >= %s AND m.date <= %s
603 AND m.production_id IS NOT NULL
604 AND m.location_id NOT IN (SELECT id FROM stock_location WHERE usage='production')
605 AND m.location_dest_id IN (SELECT id FROM stock_location WHERE usage='production')
606 GROUP BY m.product_id ORDER BY m.product_id) sl
607 WHERE product_inventory_dates.product_id = sl.product_id """, (from_date, to_date,))
608
609 return True
610
611product_inventory_dates()
612
613# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
0614
=== added file 'product_inventory_warning/product_view.xml'
--- product_inventory_warning/product_view.xml 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/product_view.xml 2013-08-26 08:54:27 +0000
@@ -0,0 +1,137 @@
1<?xml version="1.0" encoding="UTF-8"?>
2<openerp>
3 <data>
4 <record id="product_normal_form_view_safeqty" model="ir.ui.view">
5 <field name="name">product.normal.form.safeqty</field>
6 <field name="model">product.product</field>
7 <field name="type">form</field>
8 <field name="inherit_id" ref="stock.view_normal_procurement_locations_form"/>
9 <field name="arch" type="xml">
10 <xpath expr="//field[@name='incoming_qty']" position="before">
11 <field name="product_safe_qty"/>
12 </xpath>
13 </field>
14 </record>
15
16 <record id="view_product_inventory_tree" model="ir.ui.view">
17 <field name="name">product.inventory.tree</field>
18 <field name="model">product.inventory</field>
19 <field name="type">tree</field>
20 <field name="arch" type="xml">
21 <tree string="Product Inventory" colors="red:onhand_qty &lt; product_safe_qty" >
22 <field name="stock_type_id"/>
23 <field name="category_id"/>
24 <field name="product_id"/>
25 <field name="name"/>
26 <field name="onhand_qty"/>
27 <field name="onorder_qty"/>
28 <field name="uom_id"/>
29 <field name="ondraft_qty"/>
30 <field name="product_safe_qty"/>
31 <field name="code" invisible="1"/>
32 <field name="date"/>
33 </tree>
34 </field>
35 </record>
36
37 <record id="view_product_inventory_search" model="ir.ui.view">
38 <field name="name">product.inventory.search</field>
39 <field name="model">product.inventory</field>
40 <field name="type">search</field>
41 <field name="arch" type="xml">
42 <search string="Product Inventory">
43 <field name="product_id"/>
44 <field name="stock_type_id"/>
45 <field name="category_id"/>
46 <field name="onhand_qty"/>
47 <filter string='Out of Stock' icon="terp-mrp" domain="[('out_stock','=',True)]"/>
48 <group expand='0' string='Group by...'>
49 <filter string='Category' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'category_id'}"/>
50 <filter string='Stock Type' icon="terp-mrp" domain="[]" context="{'group_by' : 'stock_type_id'}"/>
51 <filter string='Product' icon="terp-go-home" domain="[]" context="{'group_by' : 'product_id'}"/>
52 </group>
53 </search>
54 </field>
55 </record>
56
57 <record id="action_product_inventory_tree" model="ir.actions.act_window">
58 <field name="name">Product Inventory Warning</field>
59 <field name="res_model">product.inventory</field>
60 <field name="view_type">form</field>
61 <field name="view_mode">tree</field>
62 <field name="search_view_id" ref="view_product_inventory_search"/>
63 <field name="limit">60</field>
64 </record>
65
66 <menuitem
67 id="menu_action_product_inventory_tree"
68 parent="purchase.menu_procurement_management_product"
69 action="action_product_inventory_tree"
70 sequence = "95"/>
71
72
73 <record id="view_product_inventory_dates_tree" model="ir.ui.view">
74 <field name="name">product.inventory.dates.tree</field>
75 <field name="model">product.inventory.dates</field>
76 <field name="type">tree</field>
77 <field name="arch" type="xml">
78 <tree string="Product Inventory between dates">
79 <field name="stock_type_id"/>
80 <field name="category_id"/>
81 <field name="product_id"/>
82 <field name="start_qty" sum="Start Qty"/>
83 <field name="start_value" sum="Start Value"/>
84 <field name="buy_qty" sum="Buy Qty"/>
85 <field name="buy_value" sum="Buy Value"/>
86 <field name="sale_qty" sum="Sale Qty"/>
87 <field name="sale_value" sum="Sale Value"/>
88 <field name="scrap_qty" sum="Scrap Qty"/>
89 <field name="scrap_value" sum="Scrap Value"/>
90 <field name="consume_qty" sum="Consume Qty"/>
91 <field name="consume_value" sum="Consume Value"/>
92 <field name="produce_qty" sum="Produce Qty"/>
93 <field name="produce_value" sum="Produce Value"/>
94 <field name="end_qty" sum="End Qty"/>
95 <field name="end_value" sum="End Value"/>
96 <field name="code" invisible="1"/>
97 <field name="uom_id"/>
98 <field name="from_date"/>
99 <field name="to_date"/>
100 </tree>
101 </field>
102 </record>
103
104 <record id="view_product_inventory_dates_search" model="ir.ui.view">
105 <field name="name">product.inventory.dates.search</field>
106 <field name="model">product.inventory.dates</field>
107 <field name="type">search</field>
108 <field name="arch" type="xml">
109 <search string="Product Inventory between dates">
110 <field name="product_id"/>
111 <field name="stock_type_id"/>
112 <field name="category_id"/>
113 <group expand='0' string='Group by...'>
114 <filter string='Category' icon="terp-stock_symbol-selection" domain="[]" context="{'group_by' : 'category_id'}"/>
115 <filter string='Stock Type' icon="terp-mrp" domain="[]" context="{'group_by' : 'stock_type_id'}"/>
116 <filter string='To Date' icon="terp-go-home" domain="[]" context="{'group_by' : 'to_date'}"/>
117 </group>
118 </search>
119 </field>
120 </record>
121
122 <record id="action_product_inventory_dates_tree" model="ir.actions.act_window">
123 <field name="name">Product Inventory between dates</field>
124 <field name="res_model">product.inventory.dates</field>
125 <field name="view_type">form</field>
126 <field name="view_mode">tree</field>
127 <field name="search_view_id" ref="view_product_inventory_dates_search"/>
128 <field name="limit">60</field>
129 </record>
130
131 <menuitem
132 id="menu_action_product_inventory_dates_tree"
133 parent="purchase.menu_procurement_management_product"
134 action="action_product_inventory_dates_tree"
135 sequence = "97"/>
136 </data>
137</openerp>
0138
=== added directory 'product_inventory_warning/security'
=== added file 'product_inventory_warning/security/ir.model.access.csv'
--- product_inventory_warning/security/ir.model.access.csv 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/security/ir.model.access.csv 2013-08-26 08:54:27 +0000
@@ -0,0 +1,3 @@
1id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
2access_product_inventory_wro,product_inventory wro,product_inventory_warning.model_product_inventory,stock.group_stock_user,1,0,0,0
3access_product_inventorydates_wro,product_inventory_dates wro,product_inventory_warning.model_product_inventory_dates,stock.group_stock_user,1,0,0,0
0\ No newline at end of file4\ No newline at end of file
15
=== added directory 'product_inventory_warning/wizard'
=== added file 'product_inventory_warning/wizard/__init__.py'
--- product_inventory_warning/wizard/__init__.py 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/wizard/__init__.py 2013-08-26 08:54:27 +0000
@@ -0,0 +1,26 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (c) 2010-2013 Elico Corp. All Rights Reserved.
6# Author: Andy Lu <andy.lu@elico-corp.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23import product_qty
24import product_sfc
25
26# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
027
=== added file 'product_inventory_warning/wizard/product_qty.py'
--- product_inventory_warning/wizard/product_qty.py 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/wizard/product_qty.py 2013-08-26 08:54:27 +0000
@@ -0,0 +1,69 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (c) 2010-Today Elico Corp. All Rights Reserved.
6# Author: Andy Lu <andy.lu@elico-corp.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23
24from osv import fields, osv
25from tools.translate import _
26
27class product_qty(osv.osv_memory):
28 _name = "run.product.inventory"
29 _description = "Compute Product Inventory"
30 _columns = {
31
32 }
33
34 def compute_inventory(self, cr, uid, ids, context=None):
35 """ To compute inventory.
36 @param self: The object pointer.
37 @param cr: A database cursor
38 @param uid: ID of the user currently logged in
39 @param ids: the ID or list of IDs if we want more than one
40 @param context: A standard dictionary
41 @return:
42 """
43 if context is None:
44 context = {}
45
46 pi_obj = self.pool.get('product.inventory')
47 pi_obj.compute_inventory(cr, uid)
48
49 mod_obj = self.pool.get('ir.model.data')
50
51 res = mod_obj.get_object_reference(cr, uid, 'product_inventory_warning', 'view_product_inventory_tree')
52 res_id = res and res[1] or False,
53
54 return {
55 'name': _('Product Inventory'),
56 'view_type': 'form',
57 'view_mode': 'tree',
58 'view_id': res_id,
59 'res_model': 'product.inventory',
60 'context': "{}",
61 'type': 'ir.actions.act_window',
62 'target': 'current',
63 'res_id': False,
64 }
65 #return {'type': 'ir.actions.act_window_close'}
66
67product_qty()
68
69# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
070
=== added file 'product_inventory_warning/wizard/product_qty_view.xml'
--- product_inventory_warning/wizard/product_qty_view.xml 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/wizard/product_qty_view.xml 2013-08-26 08:54:27 +0000
@@ -0,0 +1,32 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <record id="view_run_product_inventory" model="ir.ui.view">
6 <field name="name">Compute Product Inventory</field>
7 <field name="model">run.product.inventory</field>
8 <field name="type">form</field>
9 <field name="arch" type="xml">
10 <form string="Compute Product Inventory">
11 <separator string="Compute Product Inventory based on current stock moves" colspan="4" />
12 <separator string="" colspan="4" />
13 <button special="cancel" string="_Cancel" icon='gtk-cancel'/>
14 <button name="compute_inventory" string="Compute" type="object" icon="gtk-ok"/>
15 </form>
16 </field>
17 </record>
18
19 <act_window name="Compute Product Inventory Warning"
20 res_model="run.product.inventory"
21 view_mode="form"
22 target="new"
23 context="{}"
24 id="action_run_product_inventory"/>
25
26 <menuitem
27 id="menu_action_run_product_inventory"
28 parent="purchase.menu_procurement_management_product"
29 action="action_run_product_inventory"
30 sequence = "90"/>
31 </data>
32</openerp>
033
=== added file 'product_inventory_warning/wizard/product_sfc.py'
--- product_inventory_warning/wizard/product_sfc.py 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/wizard/product_sfc.py 2013-08-26 08:54:27 +0000
@@ -0,0 +1,80 @@
1# -*- coding: utf-8 -*-
2##############################################################################
3#
4# OpenERP, Open Source Management Solution
5# Copyright (c) 2010-Today Elico Corp. All Rights Reserved.
6# Author: Andy Lu <andy.lu@elico-corp.com>
7#
8# This program is free software: you can redistribute it and/or modify
9# it under the terms of the GNU Affero General Public License as
10# published by the Free Software Foundation, either version 3 of the
11# License, or (at your option) any later version.
12#
13# This program is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Affero General Public License for more details.
17#
18# You should have received a copy of the GNU Affero General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21##############################################################################
22
23
24from osv import fields, osv
25from tools.translate import _
26import time
27
28class product_sfc(osv.osv_memory):
29 _name = "run.product.inventory.dates"
30 _description = "Compute Product Inventory betweend dates"
31 _columns = {
32
33 'from_date': fields.datetime('From', required=True),
34 'to_date': fields.datetime('To', required=True),
35
36 }
37 _defaults = {
38 'from_date': lambda *a: time.strftime('%Y-%m-%d 16:00:00'),
39 'to_date': lambda *a: time.strftime('%Y-%m-%d 15:59:59'),
40 }
41
42 def compute_inventory(self, cr, uid, ids, context=None):
43 """ To compute inventory.
44 @param self: The object pointer.
45 @param cr: A database cursor
46 @param uid: ID of the user currently logged in
47 @param ids: the ID or list of IDs if we want more than one
48 @param context: A standard dictionary
49 @return:
50 """
51 if context is None:
52 context = {}
53 data = self.browse(cr, uid, ids, context=context)[0]
54 context['from_date'] = data.from_date
55 context['to_date'] = data.to_date
56
57 pi_obj = self.pool.get('product.inventory.dates')
58 pi_obj.compute_inventory(cr, uid, context)
59
60 mod_obj = self.pool.get('ir.model.data')
61
62 res = mod_obj.get_object_reference(cr, uid, 'product_inventory_warning', 'view_product_inventory_dates_tree')
63 res_id = res and res[1] or False,
64
65 return {
66 'name': _('Product Inventory between dates'),
67 'view_type': 'form',
68 'view_mode': 'tree',
69 'view_id': res_id,
70 'res_model': 'product.inventory.dates',
71 'context': "{}",
72 'type': 'ir.actions.act_window',
73 'target': 'current',
74 'res_id': False,
75 }
76 #return {'type': 'ir.actions.act_window_close'}
77
78product_sfc()
79
80# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
081
=== added file 'product_inventory_warning/wizard/product_sfc_view.xml'
--- product_inventory_warning/wizard/product_sfc_view.xml 1970-01-01 00:00:00 +0000
+++ product_inventory_warning/wizard/product_sfc_view.xml 2013-08-26 08:54:27 +0000
@@ -0,0 +1,62 @@
1<?xml version="1.0" encoding="utf-8"?>
2<openerp>
3 <data>
4
5 <record id="view_run_product_inventory" model="ir.ui.view">
6 <field name="name">Compute Product Inventory</field>
7 <field name="model">run.product.inventory</field>
8 <field name="type">form</field>
9 <field name="arch" type="xml">
10 <form string="Compute Product Inventory">
11 <separator string="Compute Product Inventory based on current stock moves" colspan="4" />
12 <separator string="" colspan="4" />
13 <button special="cancel" string="_Cancel" icon='gtk-cancel'/>
14 <button name="compute_inventory" string="Compute" type="object" icon="gtk-ok"/>
15 </form>
16 </field>
17 </record>
18
19 <act_window name="Compute Product Inventory Warning"
20 res_model="run.product.inventory"
21 view_mode="form"
22 target="new"
23 context="{}"
24 id="action_run_product_inventory"/>
25
26 <menuitem
27 id="menu_action_run_product_inventory"
28 parent="purchase.menu_procurement_management_product"
29 action="action_run_product_inventory"
30 sequence = "90"/>
31
32
33 <record id="view_run_product_inventory_dates" model="ir.ui.view">
34 <field name="name">Compute Product Inventory between dates</field>
35 <field name="model">run.product.inventory.dates</field>
36 <field name="type">form</field>
37 <field name="arch" type="xml">
38 <form string="Compute Product Inventory between dates">
39 <separator string="Compute Product Inventory based on current stock moves and dates" colspan="4" />
40 <field name="from_date"/>
41 <field name="to_date"/>
42 <separator string="" colspan="4" />
43 <button special="cancel" string="_Cancel" icon='gtk-cancel'/>
44 <button name="compute_inventory" string="Compute" type="object" icon="gtk-ok"/>
45 </form>
46 </field>
47 </record>
48
49 <act_window name="Compute Product Inventory between dates"
50 res_model="run.product.inventory.dates"
51 view_mode="form"
52 target="new"
53 context="{}"
54 id="action_run_product_inventory_dates"/>
55
56 <menuitem
57 id="menu_action_run_product_inventory_dates"
58 parent="purchase.menu_procurement_management_product"
59 action="action_run_product_inventory_dates"
60 sequence = "96"/>
61 </data>
62</openerp>

Subscribers

People subscribed via source and target branches