a65a51d03f7c95841b824121ab05c517f739dcb4
[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 from mx.DateTime import *
26 from report.misc import choice_colors
27 import time, mx
28 import random
29 import StringIO
30
31
32 theme.use_color = 1
33 #theme.scale = 2
34 random.seed(0)
35
36 #
37 # TODO: Bad code, seems buggy, TO CHECK !
38 #
39
40 class external_pdf(render):
41     def __init__(self, pdf):
42         render.__init__(self)
43         self.pdf = pdf
44         self.output_type='pdf'
45
46     def _render(self):
47         return self.pdf
48
49 class report_custom(report_int):
50     def _compute_dates(self, time_unit, start, stop):
51         if not stop:
52             stop = start
53         if time_unit == 'month':
54             dates = {}
55             a = Date(*map(int, start.split("-"))).year*12+Date(*map(int, start.split("-"))).month
56             z = Date(*map(int,  stop.split("-"))).year*12+Date(*map(int,  stop.split("-"))).month+1
57             for i in range(a,z):
58                 year = i/12
59                 month = i%12
60                 if month == 0:
61                     year -= 1
62                     month = 12
63                 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"}
64                 dates[i] = {
65                     'name' :months[month],
66                     'start':(Date(year, month, 2) + RelativeDateTime(day=1)).strftime('%Y-%m-%d'),
67                     'stop' :(Date(year, month, 2) + RelativeDateTime(day=-1)).strftime('%Y-%m-%d'),
68                 }
69             return dates
70         elif time_unit == 'week':
71             dates = {}
72             a = Date(*map(int, start.split("-"))).iso_week[0]*52+Date(*map(int, start.split("-"))).iso_week[1]
73             z = Date(*map(int,  stop.split("-"))).iso_week[0]*52+Date(*map(int,  stop.split("-"))).iso_week[1]
74             for i in range(a,z+1):
75                 year = i/52
76                 week = i%52
77                 dates[i] = {
78                     'name' :"Week #%d" % week,
79                     'start':ISO.WeekTime(year, week, 1).strftime('%Y-%m-%d'),
80                     'stop' :ISO.WeekTime(year, week, 7).strftime('%Y-%m-%d'),
81                 }
82             return dates
83         else: # time_unit = day
84             dates = {}
85             a = Date(*map(int, start.split("-")))
86             z = Date(*map(int, stop.split("-")))
87             i = a
88             while i <= z:
89                 dates[map(int,i.strftime('%Y%m%d').split())[0]] = {
90                     'name' :i.strftime('%Y-%m-%d'),
91                     'start':i.strftime('%Y-%m-%d'),
92                     'stop' :i.strftime('%Y-%m-%d'),
93                 }
94                 i = i + RelativeDateTime(days=+1)
95             return dates
96         return {}
97
98     def create(self, cr, uid, ids, datas, context={}):
99         assert len(ids), 'You should provide some ids!'
100         colors = choice_colors(len(ids))
101         cr.execute(
102             "SELECT MAX(mrp_production.date_planned) AS stop,MIN(mrp_production.date_planned) AS start "\
103             "FROM mrp_workcenter, mrp_production, mrp_production_workcenter_line "\
104             "WHERE mrp_production_workcenter_line.production_id=mrp_production.id "\
105             "AND mrp_production_workcenter_line.workcenter_id=mrp_workcenter.id "\
106             "AND mrp_production.state NOT IN ('cancel','done') "\
107             "AND mrp_workcenter.id =ANY(%s)",(ids,))
108         res = cr.dictfetchone()
109         if not res['stop']:
110             res['stop'] = time.strftime('%Y-%m-%d %H:%M:%S')
111         if not res['start']:
112             res['start'] = time.strftime('%Y-%m-%d %H:%M:%S')
113         dates = self._compute_dates(datas['form']['time_unit'], res['start'][:10], res['stop'][:10])
114         dates_list = dates.keys()
115         dates_list.sort()
116         x_index = []
117         for date in dates_list:
118             x_index.append((dates[date]['name'], date))
119         pdf_string = StringIO.StringIO()
120         can = canvas.init(fname=pdf_string, format='pdf')
121         chart_object.set_defaults(line_plot.T, line_style=None)
122         if datas['form']['measure_unit'] == 'cycles':
123             y_label = "Load (Cycles)"
124         else:
125             y_label = "Load (Hours)"
126         ar = area.T(legend = legend.T(),
127                     x_grid_style = line_style.gray70_dash1,
128                     x_axis = axis.X(label="Periods", format="/a90/hC%s"),
129                     x_coord = category_coord.T(x_index, 0),
130                     y_axis = axis.Y(label=y_label),
131                     y_range = (0, None),
132                     size = (640,480))
133         bar_plot.fill_styles.reset();
134
135         # select workcenters
136         cr.execute(
137             "SELECT id, name FROM mrp_workcenter " \
138             "WHERE id=ANY(%s)" \
139             "ORDER BY mrp_workcenter.id" ,(ids,))
140         workcenters = cr.dictfetchall()
141
142         data = []
143         for date in dates_list:
144             vals = []
145             for workcenter in workcenters:
146                 cr.execute("SELECT SUM(mrp_production_workcenter_line.hour) AS hours, SUM(mrp_production_workcenter_line.cycle) AS cycles, \
147                                 mrp_workcenter.name AS name, mrp_workcenter.id AS id \
148                             FROM mrp_production_workcenter_line, mrp_production, mrp_workcenter \
149                             WHERE (mrp_production_workcenter_line.production_id=mrp_production.id) \
150                                 AND (mrp_production_workcenter_line.workcenter_id=mrp_workcenter.id) \
151                                 AND (mrp_workcenter.id=%s) \
152                                 AND (mrp_production.date_planned BETWEEN %s AND %s) \
153                             GROUP BY mrp_production_workcenter_line.workcenter_id, mrp_workcenter.name, mrp_workcenter.id \
154                             ORDER BY mrp_workcenter.id", (workcenter['id'], dates[date]['start'] + ' 00:00:00', dates[date]['stop'] + ' 23:59:59'))
155                 res = cr.dictfetchall()
156                 if not res:
157                     vals.append(0.0)
158                 else:
159                     if datas['form']['measure_unit'] == 'cycles':
160                         vals.append(res[0]['cycles'] or 0.0)
161                     else:
162                         vals.append(res[0]['hours'] or 0.0)
163
164             toto = [dates[date]['name']]
165             for val in vals:
166                 toto.append(val)
167             data.append(toto)
168
169         workcenter_num = 0
170         for workcenter in workcenters:
171             f = fill_style.Plain()
172             f.bgcolor = colors[workcenter_num]
173             ar.add_plot(bar_plot.T(label=workcenter['name'], data=data, fill_style=f, hcol=workcenter_num+1, cluster=(workcenter_num, len(res))))
174             workcenter_num += 1
175
176         #plot = bar_plot.T(label=workcenter['name'], data=data, hcol=1, fill_style=fill_style.white, cluster=(color_index,len(ids)))
177         if (not data) or (len(data[0]) <= 1):
178             ar = self._empty_graph(time.strftime('%Y-%m-%d'))
179         ar.draw(can)
180         # close canvas so that the file is written to "disk"
181         can.close()
182         self.obj = external_pdf(pdf_string.getvalue())
183         self.obj.render()
184         pdf_string.close()
185         return (self.obj.pdf, 'pdf')
186
187     def _empty_graph(self, date):
188         data = [[date, 0]]
189         ar = area.T(x_coord = category_coord.T(data, 0), y_range = (0, None),
190                     x_axis = axis.X(label="Periods"),
191                     y_axis = axis.Y(label="Load"))
192         ar.add_plot(bar_plot.T(data = data, label="No production order"))
193         return ar
194
195 report_custom('report.mrp.workcenter.load')
196
197
198 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
199