42cb750751930a8efa9b90f3c92e52df3f4a967a
[odoo/odoo.git] / addons / mrp / report / workcenter_load.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 from report.render import render
23 from report.interface import report_int
24 from pychart import *
25 import time
26 from datetime import date, datetime, timedelta
27 from dateutil.relativedelta import relativedelta
28
29 from report.misc import choice_colors
30
31 import random
32 import StringIO
33
34
35 theme.use_color = 1
36 random.seed(0)
37
38 #
39 # TODO: Bad code, seems buggy, TO CHECK !
40 #
41
42 class external_pdf(render):
43     def __init__(self, pdf):
44         render.__init__(self)
45         self.pdf = pdf
46         self.output_type='pdf'
47
48     def _render(self):
49         return self.pdf
50
51 class report_custom(report_int):
52     def _compute_dates(self, time_unit, start, stop):
53         if not stop:
54             stop = start
55         if time_unit == 'month':
56             dates = {}
57             a = int(start.split("-")[0])*12 + int(start.split("-")[1])
58             z = int(stop.split("-")[0])*12 + int(stop.split("-")[1]) + 1
59             for i in range(a,z):
60                 year = i/12
61                 month = i%12
62                 if month == 0:
63                     year -= 1
64                     month = 12
65                 months = {1:"January",2:"February",3:"March",4:"April",5:"May",6:"June",7:"July",8:"August",9:"September",10:"October",11:"November",12:"December"}
66                 dates[i] = {
67                     'name' :months[month],
68                     'start':(datetime(year, month, 2) + relativedelta(day=1)).strftime('%Y-%m-%d'),
69                     'stop' :(datetime(year, month, 2) + relativedelta(day=31)).strftime('%Y-%m-%d'),
70                 }
71             return dates
72         elif time_unit == 'week':
73             dates = {}
74             start_week = date(int(start.split("-")[0]),int(start.split("-")[1]),int(start.split("-")[2])).isocalendar()
75             end_week = date(int(stop.split("-")[0]),int(stop.split("-")[1]),int(stop.split("-")[2])).isocalendar()
76             a = int(start.split("-")[0])*52 + start_week[1]
77             z = int(stop.split("-")[0])*52 + end_week[1]
78             for i in range(a,z+1):
79                 year = i/52
80                 week = i%52
81                 d = date(year, 1, 1)
82
83                 dates[i] = {
84                     'name' :"Week #%d" % week,
85                     'start':(d + timedelta(days=-d.weekday(), weeks=week)).strftime('%Y-%m-%d'),
86                     'stop' :(d + timedelta(days=6-d.weekday(), weeks=week)).strftime('%Y-%m-%d'),
87                 }
88             return dates
89         else: # time_unit = day
90             dates = {}
91             a = datetime(int(start.split("-")[0]),int(start.split("-")[1]),int(start.split("-")[2]))
92             z = datetime(int(stop.split("-")[0]),int(stop.split("-")[1]),int(stop.split("-")[2]))
93             i = a
94             while i <= z:
95                 dates[map(int,i.strftime('%Y%m%d').split())[0]] = {
96                     'name' :i.strftime('%Y-%m-%d'),
97                     'start':i.strftime('%Y-%m-%d'),
98                     'stop' :i.strftime('%Y-%m-%d'),
99                 }
100                 i = i + relativedelta(days=+1)
101             return dates
102         return {}
103
104     def create(self, cr, uid, ids, datas, context={}):
105         assert len(ids), 'You should provide some ids!'
106         colors = choice_colors(len(ids))
107         cr.execute(
108             "SELECT MAX(mrp_production.date_planned) AS stop,MIN(mrp_production.date_planned) AS start "\
109             "FROM mrp_workcenter, mrp_production, mrp_production_workcenter_line "\
110             "WHERE mrp_production_workcenter_line.production_id=mrp_production.id "\
111             "AND mrp_production_workcenter_line.workcenter_id=mrp_workcenter.id "\
112             "AND mrp_production.state NOT IN ('cancel','done') "\
113             "AND mrp_workcenter.id IN %s",(tuple(ids),))
114         res = cr.dictfetchone()
115         if not res['stop']:
116             res['stop'] = time.strftime('%Y-%m-%d %H:%M:%S')
117         if not res['start']:
118             res['start'] = time.strftime('%Y-%m-%d %H:%M:%S')
119         dates = self._compute_dates(datas['form']['time_unit'], res['start'][:10], res['stop'][:10])
120         dates_list = dates.keys()
121         dates_list.sort()
122         x_index = []
123         for date in dates_list:
124             x_index.append((dates[date]['name'], date))
125         pdf_string = StringIO.StringIO()
126         can = canvas.init(fname=pdf_string, format='pdf')
127         can.set_title("Work Centers Load")
128         chart_object.set_defaults(line_plot.T, line_style=None)
129         if datas['form']['measure_unit'] == 'cycles':
130             y_label = "Load (Cycles)"
131         else:
132             y_label = "Load (Hours)"
133
134
135         # For add the report header on the top of the report.
136         tb = text_box.T(loc=(300, 500), text="/hL/15/bWork Centers Load", line_style=None)
137         tb.draw()
138
139         ar = area.T(legend = legend.T(),
140                     x_grid_style = line_style.gray70_dash1,
141                     x_axis = axis.X(label="Periods", format="/a90/hC%s"),
142                     x_coord = category_coord.T(x_index, 0),
143                     y_axis = axis.Y(label=y_label),
144                     y_range = (0, None),
145                     size = (640,480))
146         bar_plot.fill_styles.reset();
147         # select workcenters
148         cr.execute(
149             "SELECT mw.id, rs.name FROM mrp_workcenter mw, resource_resource rs " \
150             "WHERE mw.id IN %s and mw.resource_id=rs.id " \
151             "ORDER BY mw.id" ,(tuple(ids),))
152         workcenters = cr.dictfetchall()
153
154         data = []
155         for date in dates_list:
156             vals = []
157             for workcenter in workcenters:
158                 cr.execute("SELECT SUM(mrp_production_workcenter_line.hour) AS hours, SUM(mrp_production_workcenter_line.cycle) AS cycles, \
159                                 resource_resource.name AS name, mrp_workcenter.id AS id \
160                             FROM mrp_production_workcenter_line, mrp_production, mrp_workcenter, resource_resource \
161                             WHERE (mrp_production_workcenter_line.production_id=mrp_production.id) \
162                                 AND (mrp_production_workcenter_line.workcenter_id=mrp_workcenter.id) \
163                                 AND (mrp_workcenter.resource_id=resource_resource.id) \
164                                 AND (mrp_workcenter.id=%s) \
165                                 AND (mrp_production.date_planned BETWEEN %s AND %s) \
166                             GROUP BY mrp_production_workcenter_line.workcenter_id, resource_resource.name, mrp_workcenter.id \
167                             ORDER BY mrp_workcenter.id", (workcenter['id'], dates[date]['start'] + ' 00:00:00', dates[date]['stop'] + ' 23:59:59'))
168                 res = cr.dictfetchall()
169                 if not res:
170                     vals.append(0.0)
171                 else:
172                     if datas['form']['measure_unit'] == 'cycles':
173                         vals.append(res[0]['cycles'] or 0.0)
174                     else:
175                         vals.append(res[0]['hours'] or 0.0)
176
177             toto = [dates[date]['name']]
178             for val in vals:
179                 toto.append(val)
180             data.append(toto)
181
182         workcenter_num = 0
183         for workcenter in workcenters:
184             f = fill_style.Plain()
185             f.bgcolor = colors[workcenter_num]
186             ar.add_plot(bar_plot.T(label=workcenter['name'], data=data, fill_style=f, hcol=workcenter_num+1, cluster=(workcenter_num, len(res))))
187             workcenter_num += 1
188
189         if (not data) or (len(data[0]) <= 1):
190             ar = self._empty_graph(time.strftime('%Y-%m-%d'))
191         ar.draw(can)
192         # close canvas so that the file is written to "disk"
193         can.close()
194         self.obj = external_pdf(pdf_string.getvalue())
195         self.obj.render()
196         pdf_string.close()
197         return (self.obj.pdf, 'pdf')
198
199     def _empty_graph(self, date):
200         data = [[date, 0]]
201         ar = area.T(x_coord = category_coord.T(data, 0), y_range = (0, None),
202                     x_axis = axis.X(label="Periods"),
203                     y_axis = axis.Y(label="Load"))
204         ar.add_plot(bar_plot.T(data = data, label="No production order"))
205         return ar
206
207 report_custom('report.mrp.workcenter.load')
208
209
210 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
211