Merge lp:~unifield-team/unifield-wm/us-279 into lp:unifield-wm

Proposed by jftempo
Status: Merged
Merged at revision: 2718
Proposed branch: lp:~unifield-team/unifield-wm/us-279
Merge into: lp:unifield-wm
Diff against target: 987 lines (+915/-2)
9 files modified
specific_rules/__init__.py (+1/-0)
specific_rules/__openerp__.py (+1/-0)
specific_rules/report/__init__.py (+2/-1)
specific_rules/report/report_stock_inventory_view.xml (+12/-0)
specific_rules/report/report_unconsistent_stock.py (+39/-0)
specific_rules/report/unconsistent_stock_report_xls.mako (+146/-0)
specific_rules/security/ir.model.access.csv (+3/-1)
specific_rules/unconsistent_stock_report.py (+654/-0)
specific_rules/unconsistent_stock_report_view.xml (+57/-0)
To merge this branch: bzr merge lp:~unifield-team/unifield-wm/us-279
Reviewer Review Type Date Requested Status
UniField Reviewer Team Pending
Review via email: mp+283487@code.launchpad.net
To post a comment you must log in.
lp:~unifield-team/unifield-wm/us-279 updated
2713. By Quentin THEURET @Amaris

US-279 [IMP] Add a cron job to remove reports aged for 2 day

2714. By Quentin THEURET @Amaris

US-279 [FIX] Bad model used in the record for ir.cron

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'specific_rules/__init__.py'
2--- specific_rules/__init__.py 2012-07-25 08:03:41 +0000
3+++ specific_rules/__init__.py 2016-01-21 21:12:42 +0000
4@@ -19,6 +19,7 @@
5 #
6 ##############################################################################
7 import specific_rules
8+import unconsistent_stock_report
9 import stock
10 import wizard
11 import report
12
13=== modified file 'specific_rules/__openerp__.py'
14--- specific_rules/__openerp__.py 2015-03-02 16:18:37 +0000
15+++ specific_rules/__openerp__.py 2016-01-21 21:12:42 +0000
16@@ -42,6 +42,7 @@
17 'stock_view.xml',
18 'wizard/stock_partial_move_view.xml',
19 'report/report_stock_inventory_view.xml',
20+ 'unconsistent_stock_report_view.xml',
21 'stock_sequence.xml',
22 ],
23 'installable': True,
24
25=== modified file 'specific_rules/report/__init__.py'
26--- specific_rules/report/__init__.py 2015-03-02 16:18:37 +0000
27+++ specific_rules/report/__init__.py 2016-01-21 21:12:42 +0000
28@@ -19,5 +19,6 @@
29 #
30 ##############################################################################
31
32+import report_stock_inventory
33 import report_stock_virtual
34-import report_stock_inventory
35+import report_unconsistent_stock
36
37=== modified file 'specific_rules/report/report_stock_inventory_view.xml'
38--- specific_rules/report/report_stock_inventory_view.xml 2015-03-03 14:50:59 +0000
39+++ specific_rules/report/report_stock_inventory_view.xml 2016-01-21 21:12:42 +0000
40@@ -114,5 +114,17 @@
41 menu="False"
42 />
43
44+ <report
45+ id="report_unconsistent_stock_xls"
46+ string="Unconsistent stock"
47+ model="unconsistent.stock.report"
48+ name="unconsistent.stock.report_xls"
49+ file="specific_rules/report/unconsistent_stock_report_xls.mako"
50+ report_type="webkit"
51+ header="False"
52+ auto="False"
53+ menu="False"
54+ />
55+
56 </data>
57 </openerp>
58
59=== added file 'specific_rules/report/report_unconsistent_stock.py'
60--- specific_rules/report/report_unconsistent_stock.py 1970-01-01 00:00:00 +0000
61+++ specific_rules/report/report_unconsistent_stock.py 2016-01-21 21:12:42 +0000
62@@ -0,0 +1,39 @@
63+# -*- coding: utf-8 -*-
64+##############################################################################
65+#
66+# OpenERP, Open Source Management Solution
67+# Copyright (C) 2011 TeMPO Consulting, MSF. All Rights Reserved
68+#
69+# This program is free software: you can redistribute it and/or modify
70+# it under the terms of the GNU Affero General Public License as
71+# published by the Free Software Foundation, either version 3 of the
72+# License, or (at your option) any later version.
73+#
74+# This program is distributed in the hope that it will be useful,
75+# but WITHOUT ANY WARRANTY; without even the implied warranty of
76+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
77+# GNU Affero General Public License for more details.
78+#
79+# You should have received a copy of the GNU Affero General Public License
80+# along with this program. If not, see <http://www.gnu.org/licenses/>.
81+#
82+##############################################################################
83+
84+from report import report_sxw
85+from spreadsheet_xml.spreadsheet_xml_write import SpreadsheetReport
86+
87+class unconsistent_stock_report_xls(SpreadsheetReport):
88+ def __init__(self, name, table, rml=False, parser=report_sxw.rml_parse, header='external', store=False):
89+ super(unconsistent_stock_report_xls, self).__init__(name, table,
90+ rml=rml, parser=parser, header=header, store=store)
91+
92+ def create(self, cr, uid, ids, data, context=None):
93+ a = super(unconsistent_stock_report_xls, self).create(cr, uid, ids,
94+ data, context)
95+ return (a[0], 'xls')
96+
97+unconsistent_stock_report_xls(
98+ 'report.unconsistent.stock.report_xls',
99+ 'unconsistent.stock.report',
100+ 'addons/specific_rules/report/unconsistent_stock_report_xls.mako',
101+ header=False)
102\ No newline at end of file
103
104=== added file 'specific_rules/report/unconsistent_stock_report_xls.mako'
105--- specific_rules/report/unconsistent_stock_report_xls.mako 1970-01-01 00:00:00 +0000
106+++ specific_rules/report/unconsistent_stock_report_xls.mako 2016-01-21 21:12:42 +0000
107@@ -0,0 +1,146 @@
108+<?xml version="1.0"?>
109+<?mso-application progid="Excel.Sheet"?>
110+<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
111+ xmlns:o="urn:schemas-microsoft-com:office:office"
112+ xmlns:x="urn:schemas-microsoft-com:office:excel"
113+ xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
114+ xmlns:html="http://www.w3.org/TR/REC-html40">
115+ <DocumentProperties xmlns="urn:schemas-microsoft-com:office:office">
116+ <Author>MSFUser</Author>
117+ <LastAuthor>MSFUser</LastAuthor>
118+ <Created>2012-06-18T15:46:09Z</Created>
119+ <Company>Medecins Sans Frontieres</Company>
120+ <Version>11.9999</Version>
121+ </DocumentProperties>
122+ <ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
123+ <WindowHeight>13170</WindowHeight>
124+ <WindowWidth>19020</WindowWidth>
125+ <WindowTopX>120</WindowTopX>
126+ <WindowTopY>60</WindowTopY>
127+ <ProtectStructure>False</ProtectStructure>
128+ <ProtectWindows>False</ProtectWindows>
129+ </ExcelWorkbook>
130+<Styles>
131+ <Style ss:ID="header">
132+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
133+ <Font ss:FontName="Calibri" x:Family="Swiss" ss:Bold="1" ss:Color="#000000"/>
134+ <Interior ss:Color="#efefef" ss:Pattern="Solid" />
135+ <Borders>
136+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
137+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
138+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
139+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
140+ </Borders>
141+ </Style>
142+ <Style ss:ID="line">
143+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
144+ <Font ss:FontName="Calibri" x:Family="Swiss" ss:Color="#000000"/>
145+ <Borders>
146+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
147+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
148+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
149+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
150+ </Borders>
151+ </Style>
152+ <Style ss:ID="line_left">
153+ <Alignment ss:Horizontal="Left" ss:Vertical="Center" ss:WrapText="1"/>
154+ <Font ss:FontName="Calibri" x:Family="Swiss" ss:Color="#000000"/>
155+ <Borders>
156+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
157+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
158+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
159+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
160+ </Borders>
161+ </Style>
162+ <Style ss:ID="line_date">
163+ <Alignment ss:Horizontal="Center" ss:Vertical="Center" ss:WrapText="1"/>
164+ <Font ss:FontName="Calibri" x:Family="Swiss" ss:Color="#000000"/>
165+ <Borders>
166+ <Border ss:Position="Bottom" ss:LineStyle="Continuous" ss:Weight="1" />
167+ <Border ss:Position="Left" ss:LineStyle="Continuous" ss:Weight="1" />
168+ <Border ss:Position="Right" ss:LineStyle="Continuous" ss:Weight="1" />
169+ <Border ss:Position="Top" ss:LineStyle="Continuous" ss:Weight="1" />
170+ </Borders>
171+ <NumberFormat ss:Format="Short Date"/>
172+ </Style>
173+</Styles>
174+
175+<ss:Worksheet ss:Name="Unconsistent stock">
176+<Table x:FullColumns="1" x:FullRows="1">
177+
178+ # Product code
179+ <Column ss:AutoFitWidth="1" ss:Width="75" />
180+ # Product Description
181+ <Column ss:AutoFitWidth="1" ss:Width="200" />
182+ # BN-management
183+ <Column ss:AutoFitWidth="1" ss:Width="60" />
184+ # ED-management
185+ <Column ss:AutoFitWidth="1" ss:Width="60" />
186+ # BN
187+ <Column ss:AutoFitWidth="1" ss:Width="100" />
188+ # ED
189+ <Column ss:AutoFitWidth="1" ss:Width="75" />
190+ # Quantity
191+ <Column ss:AutoFitWidth="1" ss:Width="75" />
192+ # Location
193+ <Column ss:AutoFitWidth="1" ss:Width="120" />
194+ # Document number
195+ <Column ss:AutoFitWidth="1" ss:Width="120" />
196+
197+ % for o in objects:
198+ <Row ss:AutoFitHeight="1">
199+ <Cell ss:StyleID="header"><Data ss:Type="String">Code</Data></Cell>
200+ <Cell ss:StyleID="header"><Data ss:Type="String">Description</Data></Cell>
201+ <Cell ss:StyleID="header"><Data ss:Type="String">BN-management</Data></Cell>
202+ <Cell ss:StyleID="header"><Data ss:Type="String">ED-management</Data></Cell>
203+ <Cell ss:StyleID="header"><Data ss:Type="String">BN</Data></Cell>
204+ <Cell ss:StyleID="header"><Data ss:Type="String">ED</Data></Cell>
205+ <Cell ss:StyleID="header"><Data ss:Type="String">Quantity</Data></Cell>
206+ <Cell ss:StyleID="header"><Data ss:Type="String">Location</Data></Cell>
207+ <Cell ss:StyleID="header"><Data ss:Type="String">Document number</Data></Cell>
208+ </Row>
209+
210+ % for l in o.line_ids:
211+ <Row ss:AutoFitHeight="1">
212+ <Cell ss:StyleID="line"><Data ss:Type="String">${l.product_code or ''|x}</Data></Cell>
213+ <Cell ss:StyleID="line_left"><Data ss:Type="String">${l.product_id.name or ''|x}</Data></Cell>
214+ <Cell ss:StyleID="line"><Data ss:Type="String">${l.product_bn and 'TRUE' or '-'|x}</Data></Cell>
215+ <Cell ss:StyleID="line"><Data ss:Type="String">${l.product_ed and 'TRUE' or '-'|x}</Data></Cell>
216+ <Cell ss:StyleID="line"><Data ss:Type="String">${l.prodlot_name or '-'|x}</Data></Cell>
217+ % if l.expiry_date not in (False, 'False'):
218+ <Cell ss:StyleID="line_date"><Data ss:Type="DateTime">${l.expiry_date|n}T00:00:00.000</Data></Cell>
219+ % else:
220+ <Cell ss:StyleID="line"><Data ss:Type="String">-</Data></Cell>
221+ % endif
222+ <Cell ss:StyleID="line"><Data ss:Type="Number">${l.quantity|x}</Data></Cell>
223+ <Cell ss:StyleID="line"><Data ss:Type="String">${l.location_id.name or '-'|x}</Data></Cell>
224+ <Cell ss:StyleID="line"><Data ss:Type="String">${l.document_number or '-'|x}</Data></Cell>
225+ </Row>
226+ % endfor
227+ % endfor
228+</Table>
229+<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
230+ <PageSetup>
231+ <Layout x:Orientation="Landscape"/>
232+ <Header x:Data="&amp;C&amp;&quot;Arial,Bold&quot;&amp;14"/>
233+ <Footer x:Data="Page &amp;P of &amp;N"/>
234+ </PageSetup>
235+ <Print>
236+ <ValidPrinterInfo/>
237+ <PaperSizeIndex>9</PaperSizeIndex>
238+ <HorizontalResolution>600</HorizontalResolution>
239+ <VerticalResolution>600</VerticalResolution>
240+ </Print>
241+ <Selected/>
242+ <Panes>
243+ <Pane>
244+ <Number>3</Number>
245+ <ActiveRow>17</ActiveRow>
246+ </Pane>
247+ </Panes>
248+ <ProtectObjects>False</ProtectObjects>
249+ <ProtectScenarios>False</ProtectScenarios>
250+</WorksheetOptions>
251+</ss:Worksheet>
252+
253+</Workbook>
254
255=== modified file 'specific_rules/security/ir.model.access.csv'
256--- specific_rules/security/ir.model.access.csv 2012-08-17 11:04:13 +0000
257+++ specific_rules/security/ir.model.access.csv 2016-01-21 21:12:42 +0000
258@@ -3,4 +3,6 @@
259 "access_initial_inventory_all","initial.stock.inventory.all","model_initial_stock_inventory",,1,1,1,1
260 "access_initial_inventory_line_all","initial.stock.inventory.line.all","model_initial_stock_inventory_line",,1,1,1,1
261 "access_stock_cost_reevaluation_all","stock.cost.reevaluation.all","model_stock_cost_reevaluation",,1,1,1,1
262-"access_stock_cost_reevaluation_line_all","stock.cost.reevaluation.line.all","model_stock_cost_reevaluation_line",,1,1,1,1
263\ No newline at end of file
264+"access_stock_cost_reevaluation_line_all","stock.cost.reevaluation.line.all","model_stock_cost_reevaluation_line",,1,1,1,1
265+"access_unconsistent_stock_report_all","unconsistent.stock.report.all","model_unconsistent_stock_report",,1,1,1,1
266+"access_unconsistent_stock_report_line_all","unconsistent.stock.report.line.all","model_unconsistent_stock_report_line",,1,1,1,1
267
268=== added file 'specific_rules/unconsistent_stock_report.py'
269--- specific_rules/unconsistent_stock_report.py 1970-01-01 00:00:00 +0000
270+++ specific_rules/unconsistent_stock_report.py 2016-01-21 21:12:42 +0000
271@@ -0,0 +1,654 @@
272+# -*- coding: utf-8 -*-
273+##############################################################################
274+#
275+# OpenERP, Open Source Management Solution
276+# Copyright (C) 2004-2015 TeMPO Consulting, MSF.
277+#
278+# This program is free software: you can redistribute it and/or modify
279+# it under the terms of the GNU Affero General Public License as
280+# published by the Free Software Foundation, either version 3 of the
281+# License, or (at your option) any later version.
282+#
283+# This program is distributed in the hope that it will be useful,
284+# but WITHOUT ANY WARRANTY; without even the implied warranty of
285+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
286+# GNU Affero General Public License for more details.
287+#
288+# You should have received a copy of the GNU Affero General Public License
289+# along with this program. If not, see <http://www.gnu.org/licenses/>.
290+#
291+##############################################################################
292+
293+import datetime
294+import time
295+
296+from osv import osv
297+from osv import fields
298+
299+
300+class unconsistent_stock_report(osv.osv):
301+ _name = 'unconsistent.stock.report'
302+
303+ _columns = {
304+ 'name': fields.datetime(
305+ string='Name',
306+ ),
307+ 'line_ids': fields.one2many(
308+ 'unconsistent.stock.report.line',
309+ 'report_id',
310+ string='Lines',
311+ ),
312+ }
313+
314+ _defaults = {
315+ 'name': lambda *a: time.strftime('%Y-%m-%d'),
316+ }
317+
318+ def _get_unconsistent_prodlots(self, cr, uid, bm='f', perishable='f', context=None):
319+ """
320+ Returns a list of ID of stock.production.lot that aren't consistent
321+ :param cr: Cursor to the database
322+ :param uid: ID of the user that calls the method
323+ :param bm: Batch management value of the product
324+ :param perishable: Perishable value of the product
325+ :param context: Context of the call
326+ :return: A dictionnary with values to create unconsistent_stock_report_line
327+ """
328+ if bm == 't':
329+ extra_where = 'AND spl.type = \'internal\''
330+ elif perishable == 't':
331+ extra_where = 'AND spl.type != \'internal\''
332+ else:
333+ extra_where = 'AND srp.prodlot_id IS NOT NULL'
334+
335+ request = '''
336+ SELECT
337+ srp.product_id AS product_id,
338+ srp.prodlot_id AS prodlot_id,
339+ spl.life_date AS expiry_date,
340+ SUM(srp.qty) AS quantity,
341+ srp.location_id AS location_id
342+ FROM
343+ stock_report_prodlots srp
344+ LEFT JOIN
345+ product_product pp
346+ ON pp.id = srp.product_id
347+ LEFT JOIN
348+ stock_production_lot spl
349+ ON spl.id = srp.prodlot_id
350+ LEFT JOIN
351+ stock_location sl
352+ ON sl.id = srp.location_id
353+ WHERE
354+ pp.batch_management = %%s
355+ AND
356+ pp.perishable = %%s
357+ AND
358+ sl.usage = 'internal'
359+ %s
360+ GROUP BY
361+ srp.prodlot_id, srp.location_id, srp.product_id, spl.life_date
362+ ''' % extra_where
363+ cr.execute(request, (bm, perishable))
364+
365+ for r in cr.dictfetchall():
366+ if r['quantity'] > 0.00:
367+ yield r
368+
369+ raise StopIteration
370+
371+ def _get_unconsistent_non_managed_stock(self, cr, uid, context=None):
372+ """
373+ Search the list of production lots in stock that are unconsistent
374+ :param cr: Cursor to the database
375+ :param uid: ID of the user that calls the method
376+ :param bm: Batch management value of the product
377+ :param perishable: Perishable value of the product
378+ :param context: Context of the call
379+ :return: A dictionnary with values to create unconsistent_stock_report_line
380+ """
381+ request = '''
382+ SELECT
383+ rsi.product_id AS product_id,
384+ NULL AS prodlot_id,
385+ NULL AS expiry_date,
386+ SUM(rsi.product_qty) AS quantity,
387+ rsi.location_id AS location_id
388+ FROM
389+ report_stock_inventory rsi
390+ LEFT JOIN
391+ product_product pp
392+ ON pp.id = rsi.product_id
393+ WHERE
394+ pp.perishable = 't'
395+ AND
396+ rsi.location_type = 'internal'
397+ AND
398+ rsi.state = 'done'
399+ AND
400+ rsi.prodlot_id IS NULL
401+ GROUP BY
402+ rsi.prodlot_id, rsi.location_id, rsi.product_id, expiry_date
403+ '''
404+ cr.execute(request)
405+
406+ for r in cr.dictfetchall():
407+ if r['quantity'] > 0.00:
408+ yield r
409+
410+ raise StopIteration
411+
412+ def _get_unconsistent_moves(self, cr, uid, bm='f', perishable='t', context=None):
413+ """
414+ Search the stock.move that aren't not consistent with product parameters
415+ :param cr: Cursor to the database
416+ :param uid: ID of the user that calls the method
417+ :param context: Context of the call
418+ :return: A dictionnary with values to create unconsistent_stock_report_line
419+ """
420+ if bm == 't':
421+ extra_where = ' AND (sm.prodlot_id IS NULL OR spl.type = \'internal\')'
422+ elif perishable == 't':
423+ extra_where = ' AND (sm.prodlot_id IS NULL OR spl.type != \'internal\')'
424+ else:
425+ extra_where = ' AND sm.prodlot_id IS NOT NULL'
426+
427+ request = '''
428+ SELECT
429+ sm.product_id AS product_id,
430+ sm.product_qty AS quantity,
431+ sm.prodlot_id AS prodlot_id,
432+ sm.expired_date AS expiry_date,
433+ sm.location_id AS location_id,
434+ CASE
435+ WHEN sp.subtype = 'packing' AND sp.backorder_id IS NOT NULL
436+ THEN ship.name
437+ ELSE sp.name
438+ END AS document_number
439+ FROM
440+ stock_move sm
441+ LEFT JOIN
442+ product_product pp
443+ ON pp.id = sm.product_id
444+ LEFT JOIN
445+ stock_production_lot spl
446+ ON spl.id = sm.prodlot_id
447+ LEFT JOIN
448+ stock_picking sp
449+ ON sp.id = sm.picking_id
450+ LEFT JOIN
451+ shipment ship
452+ ON ship.id = sp.shipment_id
453+ WHERE
454+ sm.kit_creation_id_stock_move IS NULL
455+ AND
456+ sm.state NOT IN ('cancel', 'done')
457+ AND
458+ sm.picking_id IS NOT NULL
459+ AND
460+ sp.type != 'in'
461+ AND
462+ (
463+ (sp.subtype = 'packing' AND sp.state IN ('draft', 'assigned'))
464+ OR
465+ (sp.subtype != 'packing' AND sp.state NOT IN ('cancel', 'done'))
466+ )
467+ AND
468+ pp.batch_management = %%s
469+ AND
470+ pp.perishable = %%s
471+ %s
472+ ''' % extra_where
473+ cr.execute(request, (bm, perishable))
474+
475+ for r in cr.dictfetchall():
476+ if r['quantity'] > 0.00:
477+ yield r
478+
479+ raise StopIteration
480+
481+ def _get_unconsistent_upil(self, cr, uid, model='stock_inventory', context=None):
482+ """
483+ Search the list of stock.inventory.line that are unconsistent with product parameters
484+ :param cr: Cursor to the database
485+ :param uid: ID of the user that calls the method
486+ :param context: Context of the call
487+ :return: A dictionnary with values to create unconsistent_stock_report_line
488+ """
489+ if model == 'stock_inventory':
490+ name = 'Phy. Inv.'
491+ else:
492+ name = 'Ini. Stock'
493+
494+ request = '''
495+ SELECT
496+ sil.product_id AS product_id,
497+ sil.prod_lot_id AS prodlot_id,
498+ sil.expiry_date AS expiry_date,
499+ SUM(sil.product_qty) AS quantity,
500+ '%s ' || si.name AS document_number,
501+ sil.location_id AS location_id
502+ FROM
503+ %s_line sil
504+ LEFT JOIN
505+ %s si
506+ ON si.id = sil.inventory_id
507+ LEFT JOIN
508+ product_product pp
509+ ON pp.id = sil.product_id
510+ LEFT JOIN
511+ stock_location sl
512+ ON sl.id = sil.location_id
513+ LEFT JOIN
514+ stock_production_lot spl
515+ ON spl.id = sil.prod_lot_id
516+ WHERE
517+ sl.usage = 'internal'
518+ AND
519+ si.state NOT IN ('done', 'cancel')
520+ AND
521+ (
522+ (pp.perishable AND NOT pp.batch_management AND (sil.expiry_date IS NULL OR spl.type != 'internal'))
523+ OR
524+ (pp.batch_management AND (sil.prod_lot_id IS NULL OR spl.type = 'internal'))
525+ OR
526+ (
527+ NOT (pp.batch_management OR pp.perishable)
528+ AND
529+ (
530+ sil.prod_lot_id IS NOT NULL
531+ OR
532+ sil.expiry_date IS NOT NULL
533+ )
534+ )
535+ )
536+ GROUP BY
537+ sil.product_id, sil.prod_lot_id, sil.expiry_date, sil.location_id, document_number
538+ ''' % (name, model, model)
539+ cr.execute(request)
540+
541+ for r in cr.dictfetchall():
542+ if r['quantity'] > 0.00:
543+ yield r
544+
545+ raise StopIteration
546+
547+ def _get_unconsistent_ucrl(self, cr, uid, context=None):
548+ """
549+ Search the list of real.average.consumption.line that are unconsistent with product parameters
550+ :param cr: Cursor to the database
551+ :param uid: ID of the user that calls the method
552+ :param context: Context of the call
553+ :return: A dictionnary with values to create unconsistent_stock_report_line
554+ """
555+ request = '''
556+ SELECT
557+ racl.product_id AS product_id,
558+ racl.prodlot_id AS prodlot_id,
559+ racl.expiry_date AS expiry_date,
560+ SUM(racl.product_qty) AS quantity,
561+ 'Cons. report ' || rac.name AS document_number,
562+ rac.cons_location_id AS location_id
563+ FROM
564+ real_average_consumption_line racl
565+ LEFT JOIN
566+ real_average_consumption rac
567+ ON rac.id = racl.rac_id
568+ LEFT JOIN
569+ product_product pp
570+ ON pp.id = racl.product_id
571+ LEFT JOIN
572+ stock_location sl
573+ ON sl.id = rac.cons_location_id
574+ LEFT JOIN
575+ stock_production_lot spl
576+ ON spl.id = racl.prodlot_id
577+ WHERE
578+ sl.usage = 'internal'
579+ AND
580+ rac.state NOT IN ('done', 'cancel')
581+ AND
582+ (
583+ (pp.perishable AND not pp.batch_management AND (racl.expiry_date IS NULL OR spl.type != 'internal'))
584+ OR
585+ (pp.batch_management AND (racl.prodlot_id IS NULL OR spl.type = 'internal'))
586+ OR
587+ (
588+ NOT (pp.batch_management OR pp.perishable)
589+ AND
590+ (
591+ racl.prodlot_id IS NOT NULL
592+ OR
593+ racl.expiry_date IS NOT NULL
594+ )
595+ )
596+ )
597+ GROUP BY
598+ racl.product_id, racl.prodlot_id, racl.expiry_date, rac.cons_location_id, document_number
599+ '''
600+ cr.execute(request)
601+
602+ for r in cr.dictfetchall():
603+ if r['quantity'] > 0.00:
604+ yield r
605+
606+ raise StopIteration
607+
608+ def _get_unconsistent_ukol(self, cr, uid, context=None):
609+ """
610+ Search the list of stock.move that are unconsistent with product parameters
611+ :param cr: Cursor to the database
612+ :param uid: ID of the user that calls the method
613+ :param context: Context of the call
614+ :return: A dictionnary with values to create unconsistent_stock_report_line
615+ """
616+ request = '''
617+ SELECT
618+ sm.product_id AS product_id,
619+ sm.prodlot_id AS prodlot_id,
620+ sm.expired_date AS expiry_date,
621+ SUM(sm.product_qty) AS quantity,
622+ 'Kitting Order ' || ko.name AS document_number,
623+ sm.location_id AS location_id
624+ FROM
625+ stock_move sm
626+ LEFT JOIN
627+ kit_creation ko
628+ ON ko.id = sm.kit_creation_id_stock_move
629+ LEFT JOIN
630+ product_product pp
631+ ON pp.id = sm.product_id
632+ LEFT JOIN
633+ stock_location sl
634+ ON sl.id = sm.location_id
635+ LEFT JOIN
636+ stock_production_lot spl
637+ ON spl.id = sm.prodlot_id
638+ WHERE
639+ sl.usage = 'internal'
640+ AND
641+ ko.state NOT IN ('done', 'cancel')
642+ AND
643+ (
644+ (pp.perishable AND NOT pp.batch_management AND (sm.expired_date IS NULL OR spl.type != 'internal'))
645+ OR
646+ (pp.batch_management AND (sm.prodlot_id IS NULL OR spl.type = 'internal'))
647+ OR
648+ (
649+ NOT (pp.batch_management OR pp.perishable)
650+ AND
651+ (
652+ sm.prodlot_id IS NOT NULL
653+ OR
654+ sm.expired_date IS NOT NULL
655+ )
656+ )
657+ )
658+ GROUP BY
659+ sm.product_id, sm.prodlot_id, sm.expired_date, sm.location_id, document_number
660+ '''
661+ cr.execute(request)
662+
663+ for r in cr.dictfetchall():
664+ if r['quantity'] > 0.00:
665+ yield r
666+
667+ raise StopIteration
668+
669+ def _get_unconsistent_ucsm(self, cr, uid, context=None):
670+ """
671+ Search the list of claim.stock.move that are unconsistent with product parameters
672+ :param cr: Cursor to the database
673+ :param uid: ID of the user that calls the method
674+ :param context: Context of the call
675+ :return: A dictionnary with values to create unconsistent_stock_report_line
676+ """
677+ request = '''
678+ SELECT
679+ cpl.product_id_claim_product_line AS product_id,
680+ cpl.lot_id_claim_product_line AS prodlot_id,
681+ cpl.expiry_date_claim_product_line AS expiry_date,
682+ SUM(cpl.qty_claim_product_line) AS quantity,
683+ 'Claim ' || rc.name AS document_number
684+ FROM
685+ claim_product_line cpl
686+ LEFT JOIN
687+ return_claim rc
688+ ON rc.id = cpl.claim_id_claim_product_line
689+ LEFT JOIN
690+ product_product pp
691+ ON pp.id = cpl.product_id_claim_product_line
692+ LEFT JOIN
693+ stock_production_lot spl
694+ ON spl.id = cpl.lot_id_claim_product_line
695+ WHERE
696+ (
697+ (pp.perishable AND (cpl.expiry_date_claim_product_line IS NULL OR spl.type != 'internal'))
698+ OR
699+ (pp.batch_management AND (cpl.lot_id_claim_product_line IS NULL OR spl.type = 'internal'))
700+ OR
701+ cpl.lot_id_claim_product_line IS NOT NULL
702+ OR
703+ cpl.expiry_date_claim_product_line IS NOT NULL
704+ )
705+ GROUP BY
706+ cpl.product_id_claim_product_line, cpl.lot_id_claim_product_line, cpl.expiry_date_claim_product_line, document_number
707+ '''
708+ cr.execute(request)
709+
710+ for r in cr.dictfetchall():
711+ if r['quantity'] > 0.00:
712+ yield r
713+
714+ raise StopIteration
715+
716+ def generate_report(self, cr, uid, ids, context=None):
717+ """
718+ Generate the report. Call the different methods to find unconsistent data and put them in the report.
719+ :param cr: Cursor to the database
720+ :param uid: ID of the user that calls the method
721+ :param context: Context of the call
722+ :return: The ID of the new report
723+ """
724+ usrl_obj = self.pool.get('unconsistent.stock.report.line')
725+
726+ if context is None:
727+ context = {}
728+
729+ # Remove last report
730+ #self.unlink(cr, uid, self.search(cr, uid, [], context=context), context=context)
731+
732+ def create_usrl(vals):
733+ vals['report_id'] = ids[0]
734+ usrl_obj.create(cr, uid, vals, context=context)
735+
736+ # UN-CONSISTENT PRODLOTS
737+ # Get the un-consistent stock for non tracked products
738+ for ulot in self._get_unconsistent_prodlots(cr, uid, bm='f', perishable='f', context=context):
739+ create_usrl(ulot)
740+
741+ # Get the un-consistent stock for products that are now ED/BM but without batch
742+ for ulot in self._get_unconsistent_non_managed_stock(cr, uid, context=context):
743+ create_usrl(ulot)
744+
745+ # Get the un-consistent stock for ED products
746+ for ulot in self._get_unconsistent_prodlots(cr, uid, bm='f', perishable='t', context=context):
747+ create_usrl(ulot)
748+
749+ # Get the un-consistent stock for batch managed products
750+ for ulot in self._get_unconsistent_prodlots(cr, uid, bm='t', perishable='t', context=context):
751+ create_usrl(ulot)
752+
753+ # UN-CONSISTENT STOCK MOVES
754+ # Get the un-consistent stock moves for non tracked products
755+ for usm in self._get_unconsistent_moves(cr, uid, bm='f', perishable='f', context=context):
756+ create_usrl(usm)
757+
758+ # Get the un-consistent stock moves for ED products
759+ for usm in self._get_unconsistent_moves(cr, uid, bm='f', perishable='t', context=context):
760+ create_usrl(usm)
761+
762+ # Get the un-consistent stock moves for batch managed products
763+ for usm in self._get_unconsistent_moves(cr, uid, bm='t', perishable='t', context=context):
764+ create_usrl(usm)
765+
766+ # Get the un-consistent physical inventory lines
767+ for upil in self._get_unconsistent_upil(cr, uid, model='stock_inventory', context=context):
768+ create_usrl(upil)
769+
770+ # Get the un-consistent initial stock inventory lines
771+ for upil in self._get_unconsistent_upil(cr, uid, model='initial_stock_inventory', context=context):
772+ create_usrl(upil)
773+
774+ # Get the un-consistent consumption report lines
775+ for ucrl in self._get_unconsistent_ucrl(cr, uid, context=context):
776+ create_usrl(ucrl)
777+
778+ # Get the un-consistent kitting order lines
779+ for ukol in self._get_unconsistent_ukol(cr, uid, context=context):
780+ create_usrl(ukol)
781+
782+ # Get the un-consistent claim moves
783+ for ucsm in self._get_unconsistent_ucsm(cr, uid, context=context):
784+ create_usrl(ucsm)
785+
786+ '''
787+ Retrieve the data and print the report in Excel format.
788+ '''
789+ background_id = self.pool.get('memory.background.report').create(cr, uid, {
790+ 'file_name': 'Unconsistent stock report',
791+ 'report_name': 'unconsistent.stock.report_xls',
792+ }, context=context)
793+ context['background_id'] = background_id
794+ context['background_time'] = 30
795+
796+ data = {'ids': ids, 'context': context}
797+ return {
798+ 'type': 'ir.actions.report.xml',
799+ 'report_name': 'unconsistent.stock.report_xls',
800+ 'datas': data,
801+ 'context': context,
802+ }
803+
804+ def delete_unused_lines(self, cr, uid, ids, context=None):
805+ """
806+ Remove the unconsistent.stock.report.line and unconsistent.stock.report
807+ with age larger than 2 days.
808+ """
809+ if not ids:
810+ ids = []
811+
812+ max_age = datetime.datetime.now() - datetime.timedelta(days=2)
813+ report_ids = self.search(cr, uid, [
814+ ('name', '<', max_age.strftime('%Y-%m-%d %H:%M:%S')),
815+ ], context=context)
816+
817+ self.unlink(cr, uid, report_ids, context=context)
818+
819+ return True
820+
821+unconsistent_stock_report()
822+
823+
824+class unconsistent_stock_report_line(osv.osv):
825+ _name = 'unconsistent.stock.report.line'
826+ _order = 'report_id, product_code, prodlot_id, location_name, document_number desc'
827+
828+ _columns = {
829+ 'report_id': fields.many2one(
830+ 'unconsistent.stock.report',
831+ string='Report',
832+ required=True,
833+ ondelete='cascade',
834+ ),
835+ 'product_id': fields.many2one(
836+ 'product.product',
837+ string='Product',
838+ required=True,
839+ ondelete='cascade',
840+ ),
841+ 'product_code': fields.related(
842+ 'product_id',
843+ 'default_code',
844+ string='Product Code',
845+ type='char',
846+ size=128,
847+ readonly=True,
848+ store=True,
849+ ),
850+ 'product_name': fields.related(
851+ 'product_id',
852+ 'name',
853+ string='Product Name',
854+ type='char',
855+ size=512,
856+ readonly=True,
857+ store=True,
858+ ),
859+ 'product_bn': fields.related(
860+ 'product_id',
861+ 'batch_management',
862+ string='BN management',
863+ type='boolean',
864+ readonly=True,
865+ store=True,
866+ ),
867+ 'product_ed': fields.related(
868+ 'product_id',
869+ 'perishable',
870+ string='ED management',
871+ type='boolean',
872+ readonly=True,
873+ store=True,
874+ ),
875+ 'prodlot_id': fields.many2one(
876+ 'stock.production.lot',
877+ string='BN',
878+ readonly=True,
879+ ondelete='cascade',
880+ ),
881+ 'prodlot_name': fields.related(
882+ 'prodlot_id',
883+ 'name',
884+ string='BN',
885+ type='char',
886+ size=64,
887+ readonly=True,
888+ store=True,
889+ ),
890+ 'expiry_date': fields.related(
891+ 'prodlot_id',
892+ 'life_date',
893+ type='date',
894+ string='ED',
895+ readonly=True,
896+ store=True,
897+ ),
898+ 'quantity': fields.float(
899+ digits=(16,2),
900+ string='Qty',
901+ readonly=True,
902+ ),
903+ 'location_id': fields.many2one(
904+ 'stock.location',
905+ string='Location',
906+ readonly=True,
907+ ondelete='cascade',
908+ ),
909+ 'location_name': fields.related(
910+ 'location_id',
911+ 'name',
912+ type='char',
913+ size=128,
914+ string='Location',
915+ readonly=True,
916+ store=True,
917+ ),
918+ 'document_number': fields.char(
919+ size=128,
920+ string='Document name',
921+ readonly=True,
922+ )
923+ }
924+
925+unconsistent_stock_report_line()
926
927=== added file 'specific_rules/unconsistent_stock_report_view.xml'
928--- specific_rules/unconsistent_stock_report_view.xml 1970-01-01 00:00:00 +0000
929+++ specific_rules/unconsistent_stock_report_view.xml 2016-01-21 21:12:42 +0000
930@@ -0,0 +1,57 @@
931+<?xml version="1.0" encoding="utf-8"?>
932+<openerp>
933+ <data>
934+
935+ <!--<record id="unconsistent_stock_report_tree_view" model="ir.ui.view">-->
936+ <!--<field name="name">unconsistent.stock.report.tree.view</field>-->
937+ <!--<field name="model">unconsistent.stock.report</field>-->
938+ <!--<field name="type">tree</field>-->
939+ <!--<field name="arch" type="xml">-->
940+ <!--<tree string="Stock reports">-->
941+ <!--<field name="name" />-->
942+ <!--</tree>-->
943+ <!--</field>-->
944+ <!--</record>-->
945+
946+ <record id="unconsistent_stock_report_form_view" model="ir.ui.view">
947+ <field name="name">unconsistent.stock.report.form.view</field>
948+ <field name="model">unconsistent.stock.report</field>
949+ <field name="type">form</field>
950+ <field name="arch" type="xml">
951+ <form string="Product Inconsistencies Report generation">
952+ <field name="name" invisible="1" />
953+ <button name="generate_report" string="Generate report" icon="gtk-execute" type="object" colspan="4" />
954+ </form>
955+ </field>
956+ </record>
957+
958+ <record id="action_unconsistent_stock_report" model="ir.actions.act_window">
959+ <field name="name">Product Inconsistencies Report</field>
960+ <field name="res_model">unconsistent.stock.report</field>
961+ <field name="view_type">form</field>
962+ <field name="view_mode">form</field>
963+ <field name="target">new</field>
964+ </record>
965+
966+ <menuitem
967+ id="menu_unconsistent_stock_report"
968+ parent="object_query.menu_preferences"
969+ sequence="50"
970+ action="action_unconsistent_stock_report" />
971+
972+ <!-- Make a cron to remove lines from old reports -->
973+ <record forcecreate="True" id="ir_cron_remove_unconsistent_line" model="ir.cron">
974+ <field name="name">Delete Unconsistent report lines</field>
975+ <field name="active" eval="True" />
976+ <field name="user_id" ref="base.user_root" />
977+ <field name="interval_number">12</field>
978+ <field name="interval_type">hours</field>
979+ <field name="numbercall">-1</field>
980+ <field name="doall" eval="False" />
981+ <field name="model" eval="'unconsistent.stock.report'" />
982+ <field name="function" eval="'delete_unused_lines'" />
983+ <field name="args" eval="'(False,)'" />
984+ </record>
985+
986+ </data>
987+</openerp>

Subscribers

People subscribed via source and target branches