[IMP]:Survey
[odoo/odoo.git] / addons / survey / report / survey_analysis_report.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
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 published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (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 import pooler
24 from report.interface import report_rml
25 from tools import to_xml
26 import tools
27 import time
28 from report import report_sxw
29
30 class survey_analysis(report_rml):
31     def create(self, cr, uid, ids, datas, context):
32         surv_obj = pooler.get_pool(cr.dbname).get('survey')
33         user_obj = pooler.get_pool(cr.dbname).get('res.users')
34         rml_obj=report_sxw.rml_parse(cr, uid, surv_obj._name,context)
35         company=user_obj.browse(cr,uid,[uid],context)[0].company_id
36
37         rml ="""<document filename="Survey Analysis Report.pdf">
38                 <template pageSize="(595.0,842.0)" title="Survey Analysis" author="OpenERP S.A.(sales@openerp.com)" allowSplitting="20">
39                         <pageTemplate>
40                         <frame id="first" x1="1.3cm" y1="1.5cm" width="18.4cm" height="26.5cm"/>
41                         <pageGraphics>
42                         <fill color="black"/>
43                         <stroke color="black"/>
44                         <setFont name="DejaVu Sans" size="8"/>
45                         <drawString x="1.3cm" y="28.3cm"> """+to_xml(rml_obj.formatLang(time.strftime("%Y-%m-%d %H:%M:%S"),date_time=True))+"""</drawString>
46                         <setFont name="DejaVu Sans Bold" size="10"/>
47                         <drawString x="9.8cm" y="28.3cm">"""+ to_xml(company.name) +"""</drawString>
48                         <stroke color="#000000"/>
49                         <lines>1.3cm 28.1cm 20cm 28.1cm</lines>
50                         </pageGraphics>
51                         </pageTemplate>
52                   </template>
53                   <stylesheet>
54                     <blockTableStyle id="Table1">
55                       <blockAlignment value="LEFT"/>
56                       <blockValign value="TOP"/>
57                       <lineStyle kind="LINEBELOW" colorName="#e6e6e6"/>
58                     </blockTableStyle>
59                     <blockTableStyle id="Table2">
60                       <blockAlignment value="LEFT"/>
61                       <blockValign value="TOP"/>
62                     </blockTableStyle>
63                     <blockTableStyle id="Table3">
64                       <blockAlignment value="LEFT"/>
65                       <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="1,0" stop="2,-1"/>
66                       <blockValign value="TOP"/>
67                     </blockTableStyle>
68                     <blockTableStyle id="Table4">
69                       <blockAlignment value="LEFT"/>
70                       <blockValign value="TOP"/>
71                       <lineStyle kind="LINEBELOW" colorName="#000000" start="0,-1" stop="1,-1"/>
72                     </blockTableStyle>
73                     <blockTableStyle id="Table5">
74                       <blockAlignment value="LEFT"/>
75                       <blockValign value="TOP"/>
76                       <lineStyle kind="LINEBELOW" colorName="#8f8f8f" start="0,-1" stop="1,-1"/>
77                     </blockTableStyle>
78                     <blockTableStyle id="Table_heading">
79                       <blockAlignment value="LEFT"/>
80                       <blockValign value="TOP"/>
81                       <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
82                       <lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
83                       <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
84                       <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
85                     </blockTableStyle>
86                     <blockTableStyle id="Table_head_2">
87                       <blockAlignment value="LEFT"/>
88                       <blockValign value="TOP"/>
89                       <lineStyle kind="LINEBEFORE" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
90                       <lineStyle kind="LINEAFTER" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
91                       <lineStyle kind="LINEBELOW" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
92                       <lineStyle kind="LINEABOVE" colorName="#e6e6e6" start="0,0" stop="-1,-1"/>
93                     </blockTableStyle>
94                     <initialize>
95                       <paraStyle name="all" alignment="justify"/>
96                     </initialize>
97                     <paraStyle name="answer_right" alignment="RIGHT" fontName="helvetica" fontSize="09.0" leftIndent="2.0"/>
98                     <paraStyle name="Standard1" fontName="helvetica-bold" alignment="RIGHT" fontSize="09.0"/>
99                     <paraStyle name="Standard" alignment="LEFT" fontName="Helvetica-Bold" fontSize="11.0"/>
100                     <paraStyle name="header1" fontName="Helvetica" fontSize="11.0"/>
101                     <paraStyle name="response" fontName="Helvetica-oblique" fontSize="9.5"/>
102                     <paraStyle name="response-bold" fontName="Helvetica-bold" fontSize="9" alignment="RIGHT" />
103                     <paraStyle name="page" fontName="helvetica" fontSize="11.0" leftIndent="0.0"/>
104                     <paraStyle name="question" fontName="helvetica-boldoblique" fontSize="10.0" leftIndent="3.0"/>
105                     <paraStyle name="answer_bold" fontName="Helvetica-Bold" fontSize="09.0" leftIndent="2.0"/>
106                     <paraStyle name="answer" fontName="helvetica" fontSize="09.0" leftIndent="2.0"/>
107                     <paraStyle name="Title" fontName="helvetica" fontSize="20.0" leading="15" spaceBefore="6.0" spaceAfter="6.0" alignment="CENTER"/>
108                     <paraStyle name="terp_tblheader_General_Centre" fontName="Helvetica-Bold" fontSize="9.0" leading="10" alignment="CENTER" spaceBefore="6.0" spaceAfter="6.0"/>
109                     <paraStyle name="terp_default_Centre_8" fontName="Helvetica" fontSize="9.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
110                     <paraStyle name="terp_default_Center_heading" fontName="Helvetica-bold" fontSize="9.0" leading="10" alignment="CENTER" spaceBefore="0.0" spaceAfter="0.0"/>
111                     <paraStyle name="P2" fontName="Helvetica" fontSize="14.0" leading="15" spaceBefore="6.0" spaceAfter="6.0"/>
112                   </stylesheet>
113                   <images/>
114                   """
115
116         if datas.has_key('form') and datas['form']['survey_ids']:
117            ids =  datas['form']['survey_ids']
118
119         for survey in surv_obj.browse(cr, uid, ids):
120             rml += """<story>
121                     <para style="Title">Answers Summary</para>
122                     <para style="Standard"><font></font></para>
123                     <para style="P2">
124                       <font color="white"> </font>
125                     </para>
126                     <blockTable colWidths="280.0,100.0,120.0" style="Table_heading">
127                       <tr>
128                         <td>
129                           <para style="terp_tblheader_General_Centre">Survey Title </para>
130                         </td>
131                         <td>
132                           <para style="terp_tblheader_General_Centre">Total Started Survey </para>
133                         </td>
134                         <td>
135                           <para style="terp_tblheader_General_Centre">Total Completed Survey </para>
136                         </td>
137                       </tr>
138                       </blockTable>
139                       <blockTable colWidths="280.0,100.0,120.0" style="Table_head_2">
140                       <tr>
141                         <td>
142                           <para style="terp_default_Centre_8">""" + to_xml(tools.ustr(survey.title)) + """</para>
143                         </td>
144                         <td>
145                           <para style="terp_default_Centre_8">""" + str(survey.tot_start_survey) + """</para>
146                         </td>
147                         <td>
148                           <para style="terp_default_Centre_8">""" + str(survey.tot_comp_survey) + """</para>
149                         </td>
150                       </tr>
151                     </blockTable>
152                     <para style="P2">
153                       <font color="white"> </font>
154                     </para>"""
155             for page in survey.page_ids:
156                 rml += """ <blockTable colWidths="500" style="Table4">
157                               <tr>
158                                 <td><para style="page">Page :- """ + to_xml(tools.ustr(page.title)) + """</para></td>
159                               </tr>
160                            </blockTable>"""
161                 for que in page.question_ids:
162                     rml +="""<blockTable colWidths="500" style="Table5">
163                               <tr>
164                                 <td><para style="question">"""  + to_xml(tools.ustr(que.question)) + """</para></td>
165                               </tr>
166                              </blockTable>"""
167                     cols_widhts = []
168
169                     if que.type in ['matrix_of_choices_only_one_ans','matrix_of_choices_only_multi_ans']:
170                         cols_widhts.append(200)
171                         for col in range(0, len(que.column_heading_ids) + 1):
172                             cols_widhts.append(float(300 / (len(que.column_heading_ids) + 1)))
173                         colWidths = ",".join(map(tools.ustr, cols_widhts))
174                         matrix_ans = [(0,'')]
175
176                         for col in que.column_heading_ids:
177                             if col.title not in matrix_ans:
178                                 matrix_ans.append((col.id,col.title))
179                         rml += """<blockTable colWidths=" """ + colWidths + """ " style="Table1"><tr>"""
180                         for mat_col in range(0, len(matrix_ans)):
181                             rml+="""<td><para style="response">""" + to_xml(tools.ustr(matrix_ans[mat_col][1])) + """</para></td>"""
182                         rml += """<td><para style="response-bold">Answer Count</para></td>
183                                 </tr>"""
184                         last_col = cols_widhts[-1]
185
186                         for ans in que.answer_choice_ids:
187                             rml += """<tr><td><para style="answer">""" + to_xml(tools.ustr(ans.answer)) + """</para></td>"""
188                             cr.execute("select count(id) from survey_response_answer sra where sra.answer_id = %s", (ans.id,))
189                             tot_res = cr.fetchone()[0]
190                             cr.execute("select count(id) ,sra.column_id from survey_response_answer sra where sra.answer_id=%s group by sra.column_id", (ans.id,))
191                             calc_res = cr.dictfetchall()
192                             for mat_col in range(1, len(matrix_ans)):
193                                 percantage = 0.0
194                                 cal_count = 0
195                                 for cal in calc_res:
196                                     if cal['column_id'] == matrix_ans[mat_col][0]:
197                                         cal_count = cal['count']
198                                 if tot_res:
199                                     percantage = round(float(cal_count)*100 / tot_res,2)
200                                 if percantage:
201                                     rml += """<td color="#FFF435"><para style="answer_bold">""" + tools.ustr(percantage) +"% (" + tools.ustr(cal_count) + """)</para></td>"""
202                                 else:
203                                     rml += """<td color="#FFF435"><para style="answer">""" + tools.ustr(percantage) +"% (" + tools.ustr(cal_count) + """)</para></td>"""
204                             rml += """<td><para style="answer_right">""" + tools.ustr(tot_res) + """</para></td>
205                                 </tr>"""
206                         rml += """</blockTable>"""
207
208                         if que.is_comment_require:
209                             cr.execute("select count(id) from survey_response_line where question_id = %s and comment != ''",(que.id,))
210                             tot_res = cr.fetchone()[0]
211                             rml += """<blockTable colWidths=" """+ str(500 - last_col) +"," + str(last_col) + """ " style="Table1"><tr><td><para style="answer_right">""" + to_xml(tools.ustr(que.comment_label)) + """</para></td>
212                                     <td><para style="answer">""" + tools.ustr(tot_res) + """</para></td></tr></blockTable>"""
213
214                     elif que.type in['multiple_choice_only_one_ans', 'multiple_choice_multiple_ans', 'multiple_textboxes','date_and_time','date','multiple_textboxes_diff_type']:
215                         rml += """<blockTable colWidths="240.0,210,50.0" style="Table1">"""
216                         rml += """ <tr>
217                              <td> <para style="Standard"> </para></td>
218                              <td> <para style="terp_default_Center_heading">Answer Percentage</para></td>
219                              <td> <para style="response-bold">Answer Count</para></td>
220                          </tr>"""
221
222                         for ans in que.answer_choice_ids:
223                             progress = ans.average * 7 / 100
224                             rml += """<tr><td><para style="answer">""" + to_xml(tools.ustr(ans.answer)) + """</para></td>
225                                     <td>
226                                     <illustration>
227                                     <stroke color="lightslategray"/>
228                                        <rect x="0.1cm" y="-0.45cm" width="7.2 cm" height="0.5cm" fill="no" stroke="yes"  round="0.1cm"/>
229                                        """
230                             if progress:
231                                 rml += """<fill color="lightsteelblue"/>
232                                        <rect x="0.2cm" y="-0.35cm"  width='""" + tools.ustr(str(float(progress)) +'cm') + """' height="0.3cm" fill="yes" stroke="no"  round="0.1cm"/>"""
233                             rml += """
234                                 <fill color="black"/>
235                                 <setFont name="Helvetica" size="9"/>
236                                 <drawString x="3.2cm" y="-0.30cm">"""  + tools.ustr(ans.average) + """%</drawString></illustration>
237                                     </td>
238                                     <td><para style="answer_right">""" + tools.ustr(ans.response) + """</para></td></tr>"""
239                         rml += """</blockTable>"""
240
241                         if que.is_comment_require:
242 #                            if que.make_comment_field:
243 #                                cr.execute("select count(id) from survey_response_line where question_id = %s and comment != ''", (que.id,))
244 #                                tot_res = cr.fetchone()[0]
245 #                                tot_avg = 0.00
246 #                                if que.tot_resp:
247 #                                    tot_avg = round(float(tot_res * 100)/ que.tot_resp,2)
248 #                                rml+="""<blockTable colWidths="280.0,120,100.0" style="Table1"><tr><td><para style="answer">""" +to_xml(tools.ustr(que.comment_label)) + """</para></td>
249 #                                        <td><para style="answer">""" + str(tot_avg) + """%</para></td>
250 #                                        <td><para style="answer">""" + tools.ustr(tot_res) + """</para></td></tr></blockTable>"""
251 #                            else:
252                             cr.execute("select count(id) from survey_response_line where question_id = %s and comment != ''", (que.id,))
253                             tot_res = cr.fetchone()[0]
254                             rml += """<blockTable colWidths="450.0,50.0" style="Table1"><tr><td><para style="answer_right">""" + to_xml(tools.ustr(que.comment_label)) + """</para></td>
255                                     <td><para style="answer_right">""" + tools.ustr(tot_res) + """</para></td></tr></blockTable>"""
256
257                     elif que.type in['single_textbox']:
258                         cr.execute("select count(id) from survey_response_line where question_id = %s and single_text!=''",(que.id,))
259                         rml += """<blockTable colWidths="400.0,100.0" style="Table1">
260                              <tr>
261                                  <td> <para style="Standard"> </para></td>
262                                  <td> <para style="response-bold">Answer Count</para></td>
263                              </tr>
264                             <tr><td><para style="answer"></para></td>
265                                 <td><para style="answer_right">""" + tools.ustr(cr.fetchone()[0]) + """ </para></td></tr>
266                             </blockTable>"""
267
268                     elif que.type in['comment']:
269                         cr.execute("select count(id) from survey_response_line where question_id = %s and comment !=''", (que.id,))
270                         rml += """<blockTable colWidths="400.0,100.0" style="Table1">
271                              <tr>
272                                  <td> <para style="Standard"> </para></td>
273                                  <td> <para style="response-bold">Answer Count</para></td>
274                              </tr>
275                             <tr><td><para style="answer"></para></td>
276                                 <td><para style="answer_right">""" + tools.ustr(cr.fetchone()[0]) + """ </para></td></tr>
277                             </blockTable>"""
278
279                     elif que.type in['rating_scale']:
280                         cols_widhts.append(200)
281                         for col in range(0,len(que.column_heading_ids) + 2):
282                             cols_widhts.append(float(300 / (len(que.column_heading_ids) + 2)))
283                         colWidths = ",".join(map(tools.ustr, cols_widhts))
284                         matrix_ans = [(0,'')]
285
286                         for col in que.column_heading_ids:
287                             if col.title not in matrix_ans:
288                                 matrix_ans.append((col.id,col.title))
289                         rml += """<blockTable colWidths=" """ + colWidths + """ " style="Table1"><tr>"""
290                         for mat_col in range(0,len(matrix_ans)):
291                             rml += """<td><para style="response">""" + to_xml(tools.ustr(matrix_ans[mat_col][1])) + """</para></td>"""
292                         rml += """<td><para style="response-bold">Rating Average</para></td>
293                                 <td><para style="response-bold">Answer Count</para></td>
294                                 </tr>"""
295
296                         for ans in que.answer_choice_ids:
297                             rml += """<tr><td><para style="answer">""" + to_xml(tools.ustr(ans.answer)) + """</para></td>"""
298                             res_count = 0
299                             rating_weight_sum = 0
300                             for mat_col in range(1, len(matrix_ans)):
301                                 cr.execute("select count(sra.answer_id) from survey_response_line sr, survey_response_answer sra\
302                                      where sr.id = sra.response_id and  sra.answer_id = %s and sra.column_id ='%s'", (ans.id,matrix_ans[mat_col][0]))
303                                 tot_res = cr.fetchone()[0]
304                                 cr.execute("select count(sra.answer_id),sqc.rating_weight from survey_response_line sr, survey_response_answer sra ,\
305                                         survey_question_column_heading sqc where sr.id = sra.response_id and \
306                                         sqc.question_id = sr.question_id  and sra.answer_id = %s and sqc.title ='%s'\
307 +                                       group by sra.answer_id,sqc.rating_weight", (ans.id,matrix_ans[mat_col][1]))
308                                 col_weight =  cr.fetchone()
309
310                                 if not col_weight:
311                                     col_weight= (0,0)
312                                 elif not col_weight[1]:
313                                     col_weight = (col_weight[0],0)
314                                 res_count = col_weight[0]
315
316                                 if tot_res and res_count:
317                                     rating_weight_sum += int(col_weight[1]) * tot_res
318                                     tot_per = round((float(tot_res) * 100) / int(res_count), 2)
319                                 else:
320                                     tor_res = 0
321                                     tot_per = 0.0
322                                 if tot_res:
323                                     rml += """<td><para style="answer_bold">""" + tools.ustr(tot_per) + "%(" + tools.ustr(tot_res) + """)</para></td>"""
324                                 else:
325                                     rml += """<td><para style="answer">""" + tools.ustr(tot_per)+"%(" + tools.ustr(tot_res) + """)</para></td>"""
326
327                             percantage = 0.00
328                             if res_count:
329                                 percantage = round((float(rating_weight_sum)/res_count), 2)
330                             rml += """<td><para style="answer_right">""" + tools.ustr(percantage) + """</para></td>
331                                 <td><para style="answer_right">""" + tools.ustr(res_count) + """</para></td></tr>"""
332                         rml += """</blockTable>"""
333
334                     elif que.type in['matrix_of_drop_down_menus']:
335                         for column in que.column_heading_ids:
336                             rml += """<blockTable colWidths="500" style="Table1"><tr>
337                                 <td><para style="answer">""" + to_xml(tools.ustr(column.title)) + """</para></td></tr></blockTable>"""
338                             menu_choices = column.menu_choice.split('\n')
339                             cols_widhts = []
340                             cols_widhts.append(200)
341                             for col in range(0, len(menu_choices) + 1):
342                                 cols_widhts.append(float(300 / (len(menu_choices) + 1)))
343                             colWidths = ",".join(map(tools.ustr, cols_widhts))
344                             rml += """<blockTable colWidths=" """ + colWidths + """ " style="Table1"><tr>
345                                 <td><para style="response"></para></td>"""
346
347                             for menu in menu_choices:
348                                 rml += """<td><para style="response">""" + to_xml(tools.ustr(menu)) + """</para></td>"""
349                             rml += """<td><para style="response-bold">Answer Count</para></td></tr>"""
350                             cr.execute("select count(id), sra.answer_id from survey_response_answer sra \
351                                      where sra.column_id='%s' group by sra.answer_id ", (column.id,))
352                             res_count = cr.dictfetchall()
353                             cr.execute("select count(sra.id),sra.value_choice, sra.answer_id, sra.column_id from survey_response_answer sra \
354                                  where sra.column_id='%s' group by sra.value_choice ,sra.answer_id, sra.column_id", (column.id,))
355                             calc_percantage = cr.dictfetchall()
356
357                             for ans in que.answer_choice_ids:
358                                 rml += """<tr><td><para style="answer_right">""" + to_xml(tools.ustr(ans.answer)) + """</para></td>"""
359                                 for mat_col in range(0, len(menu_choices)):
360                                     calc = 0
361                                     response = 0
362                                     for res in res_count:
363                                         if res['answer_id'] == ans.id: response = res['count']
364                                     for per in calc_percantage:
365                                         if ans.id == per['answer_id'] and menu_choices[mat_col] == per['value_choice']:
366                                             calc = per['count']
367                                     percantage = 0.00
368
369                                     if calc and response:
370                                         percantage = round((float(calc)* 100) / response,2)
371                                     if calc:
372                                         rml += """<td><para style="answer_bold">""" +tools.ustr(percantage)+"% (" +  tools.ustr(calc) + """)</para></td>"""
373                                     else:
374                                         rml += """<td><para style="answer">""" +tools.ustr(percantage)+"% (" +  tools.ustr(calc) + """)</para></td>"""
375
376                                 response = 0
377                                 for res in res_count:
378                                     if res['answer_id'] == ans.id: response = res['count']
379                                 rml += """<td><para style="answer_right">""" + tools.ustr(response) + """</para></td></tr>"""
380                             rml += """</blockTable>"""
381
382                     elif que.type in['numerical_textboxes']:
383                         rml += """<blockTable colWidths="240.0,20,100.0,70,70.0" style="Table1">
384                              <tr>
385                              <td> <para style="Standard"> </para></td>
386                              <td> <para style="Standard"> </para></td>
387                              <td> <para style="response">Answer Average</para></td>
388                              <td> <para style="response">Answer Total</para></td>
389                              <td> <para style="response-bold">Answer Count</para></td>
390                          </tr>"""
391                         for ans in que.answer_choice_ids:
392                             cr.execute("select answer from survey_response_answer where answer_id=%s group by answer", (ans.id,))
393                             tot_res = cr.dictfetchall()
394                             total = 0
395                             for  tot in tot_res:
396                                 total += int(tot['answer'])
397                             per = 0.00
398
399                             if len(tot_res):
400                                 per = round((float(total) / len(tot_res)),2)
401                             rml+="""<tr><td><para style="answer">""" + to_xml(tools.ustr(ans.answer)) + """</para></td>
402                                     <td> <para style="Standard"> </para></td>
403                                     <td> <para style="answer">""" + tools.ustr(per) +"""</para></td>
404                                     <td><para style="answer">""" + tools.ustr(total) + """</para></td>
405                                     <td><para style="answer_right">""" + tools.ustr(len(tot_res)) + """</para></td></tr>"""
406                         rml+="""</blockTable>"""
407
408                     rml +="""<blockTable colWidths="300,100,100.0" style="Table3">
409                         <tr>
410                               <td><para style="Standard1"></para></td>
411                               <td><para style="Standard1">Answered Question</para></td>
412                               <td><para style="Standard1">""" + tools.ustr(que.tot_resp) + """</para></td>
413                         </tr>
414                         <tr>
415                             <td><para style="Standard1"></para></td>
416                             <td><para style="Standard1">Skipped Question</para></td>
417                             <td><para style="Standard1">""" + tools.ustr(survey.tot_start_survey - que.tot_resp) + """</para></td>
418                         </tr>
419                         </blockTable>"""
420             rml += """</story>"""
421
422         rml += """</document>"""
423         report_type = datas.get('report_type', 'pdf')
424         create_doc = self.generators[report_type]
425         self.internal_header=True
426         pdf = create_doc(rml, title=self.title)
427
428         return (pdf, report_type)
429
430 survey_analysis('report.survey.analysis', 'survey','','')
431
432 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: