Merge lp:~openerp-dev/openobject-addons/addons-training-report-ysa into lp:~openobject-training/openobject-addons/training
- addons-training-report-ysa
- Merge into training
Proposed by
Yogesh (SerpentCS)
Status: | Merged |
---|---|
Merged at revision: | 2154 |
Proposed branch: | lp:~openerp-dev/openobject-addons/addons-training-report-ysa |
Merge into: | lp:~openobject-training/openobject-addons/training |
Diff against target: |
1822 lines (+704/-699) 13 files modified
training_report/__init__.py (+1/-1) training_report/__openerp__.py (+5/-1) training_report/report/analytic_balance_year.py (+58/-90) training_report/report_training_view.xml (+1/-8) training_report/training_report.py (+100/-101) training_report/training_report.xml (+1/-14) training_report/wizard/__init__.py (+3/-3) training_report/wizard/training_report_account_analytic_balance_year.py (+29/-31) training_report/wizard/training_report_account_analytic_balance_year_view.xml (+35/-0) training_report/wizard/training_report_course_profitability.py (+32/-35) training_report/wizard/training_report_course_profitability_view.xml (+37/-0) training_report/wizard/training_report_session_volume.py (+365/-415) training_report/wizard/training_report_session_volume_view.xml (+37/-0) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-addons/addons-training-report-ysa |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Bhumika Shrimali | Pending | ||
Review via email: mp+53779@code.launchpad.net |
Commit message
Description of the change
training_report:- convert v5 to v6 and fix problem.
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'training_report/__init__.py' |
2 | --- training_report/__init__.py 2009-08-24 08:58:54 +0000 |
3 | +++ training_report/__init__.py 2011-03-17 10:37:29 +0000 |
4 | @@ -23,5 +23,5 @@ |
5 | import training_report |
6 | import report |
7 | import wizard |
8 | + |
9 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
10 | - |
11 | |
12 | === renamed file 'training_report/__terp__.py' => 'training_report/__openerp__.py' |
13 | --- training_report/__terp__.py 2011-02-25 12:33:02 +0000 |
14 | +++ training_report/__openerp__.py 2011-03-17 10:37:29 +0000 |
15 | @@ -20,7 +20,6 @@ |
16 | # |
17 | ############################################################################## |
18 | |
19 | - |
20 | { |
21 | 'name': 'Training Management - Reporting', |
22 | 'version': '1.0', |
23 | @@ -36,6 +35,7 @@ |
24 | 'depends': [ |
25 | 'training', |
26 | 'training_intra', |
27 | + 'training_exam', |
28 | ], |
29 | 'init_xml': [], |
30 | 'update_xml': [ |
31 | @@ -43,9 +43,13 @@ |
32 | 'security/ir.model.access.csv', |
33 | 'report_training_view.xml', |
34 | 'training_report.xml', |
35 | + 'wizard/training_report_account_analytic_balance_year_view.xml', |
36 | + 'wizard/training_report_course_profitability_view.xml', |
37 | + 'wizard/training_report_session_volume_view.xml', |
38 | ], |
39 | 'demo_xml': [], |
40 | 'installable': True, |
41 | 'active': False, |
42 | } |
43 | + |
44 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
45 | |
46 | === modified file 'training_report/report/analytic_balance_year.py' |
47 | --- training_report/report/analytic_balance_year.py 2009-11-25 16:36:08 +0000 |
48 | +++ training_report/report/analytic_balance_year.py 2011-03-17 10:37:29 +0000 |
49 | @@ -20,10 +20,8 @@ |
50 | # |
51 | ############################################################################## |
52 | |
53 | -import pooler |
54 | import time |
55 | from report import report_sxw |
56 | -import datetime |
57 | |
58 | class account_analytic_balance_year(report_sxw.rml_parse): |
59 | def __init__(self, cr, uid, name, context): |
60 | @@ -43,12 +41,9 @@ |
61 | }) |
62 | |
63 | def _lines_g(self, account_id, date1, date2): |
64 | - year=[] |
65 | - year.append(int(date1[0:4])-1) |
66 | - year.append(int(date1[0:4])) |
67 | account_analytic_obj = self.pool.get('account.analytic.account') |
68 | - ids = account_analytic_obj.search(self.cr, self.uid, |
69 | - [('parent_id', 'child_of', [account_id])]) |
70 | + year = [int(date1[0:4]) - 1, int(date1[0:4])] |
71 | + ids = account_analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', [account_id])]) |
72 | self.cr.execute("SELECT aa.name AS name, aa.code AS code, \ |
73 | sum(aal.amount) AS balance, sum(aal.unit_amount) AS quantity \ |
74 | FROM account_analytic_line AS aal, account_account AS aa \ |
75 | @@ -58,49 +53,46 @@ |
76 | And date_part('year',date) in ("+ ','.join(map(str, year)) +") \ |
77 | GROUP BY aal.general_account_id, aa.name, aa.code, aal.code ,date_part('year',date)\ |
78 | ORDER BY aal.code", (date1[5:10], date2[5:10])) |
79 | - res = self.cr.dictfetchall() |
80 | + result = self.cr.dictfetchall() |
81 | |
82 | - for r in res: |
83 | - if r['balance'] > 0: |
84 | - r['debit'] = r['balance'] |
85 | - r['credit'] = 0.0 |
86 | - elif r['balance'] < 0: |
87 | - r['debit'] = 0.0 |
88 | - r['credit'] = -r['balance'] |
89 | + for res in result: |
90 | + if res.get('balance') > 0: |
91 | + res.update({ |
92 | + 'debit' : res.get('balance',0), |
93 | + 'credit' : 0.0 |
94 | + }) |
95 | + elif res.get('balance') < 0: |
96 | + res.update({ |
97 | + 'debit' : 0.0, |
98 | + 'credit' : -res.get('balance',0) |
99 | + }) |
100 | else: |
101 | - r['balance'] == 0 |
102 | - r['debit'] = 0.0 |
103 | - r['credit'] = 0.0 |
104 | - return res |
105 | + res.update({ |
106 | + 'balance' : 0.0, |
107 | + 'debit' : 0.0, |
108 | + 'credit' : -res.get('balance',0) |
109 | + }) |
110 | + return result |
111 | |
112 | def _get_year(self,date1,date2): |
113 | - year=[] |
114 | - year.append(str(int(date1[0:4])-1)) |
115 | - year.append(str(int(date1[0:4]))) |
116 | - return year |
117 | + return [str(int(date1[0:4])-1), str(int(date1[0:4]))] |
118 | + |
119 | def _get_data(self, account_id, date1, date2): |
120 | - res=[] |
121 | - r={} |
122 | - year=[] |
123 | - year.append(str(int(date1[0:4])-1)) |
124 | - year.append(str(int(date1[0:4]))) |
125 | + year = [str(int(date1[0:4])-1), str(int(date1[0:4]))] |
126 | debit = self._move_sum_debit(account_id, date1, date2) |
127 | credit = self._move_sum_credit(account_id, date1, date2) |
128 | - amount=self._move_sum_balance(account_id, date1, date2) |
129 | - r['debit']=debit |
130 | - r['credit']=credit |
131 | - r['amount']=amount |
132 | - r['year']=year |
133 | - return r |
134 | + amount = self._move_sum_balance(account_id, date1, date2) |
135 | + return { |
136 | + 'debit' : debit, |
137 | + 'credit' : credit, |
138 | + 'amount' : amount, |
139 | + 'year' : year |
140 | + } |
141 | |
142 | def _move_sum_debit(self, account_id, date1, date2): |
143 | - res=[] |
144 | - year=[] |
145 | - year.append(int(date1[0:4])-1) |
146 | - year.append(int(date1[0:4])) |
147 | account_analytic_obj = self.pool.get('account.analytic.account') |
148 | - ids = account_analytic_obj.search(self.cr, self.uid, |
149 | - [('parent_id', 'child_of', [account_id])]) |
150 | + year [int(date1[0:4])-1, int(date1[0:4])] |
151 | + ids = account_analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', [account_id])]) |
152 | self.cr.execute("SELECT sum(amount)\ |
153 | FROM account_analytic_line \ |
154 | WHERE account_id in ("+ ','.join(map(str, ids)) +") \ |
155 | @@ -108,66 +100,49 @@ |
156 | and date_part('year',date) in ("+ ','.join(map(str, year)) +") \ |
157 | group by date_part('year',date)",(date1[5:10], date2[5:10])) |
158 | |
159 | - res =self.cr.dictfetchall() |
160 | - return res |
161 | + return self.cr.dictfetchall() |
162 | |
163 | def _move_sum_credit(self, account_id, date1, date2): |
164 | - year=[] |
165 | - res=[] |
166 | - year.append(int(date1[0:4])-1) |
167 | - year.append(int(date1[0:4])) |
168 | account_analytic_obj = self.pool.get('account.analytic.account') |
169 | - ids = account_analytic_obj.search(self.cr, self.uid, |
170 | - [('parent_id', 'child_of', [account_id])]) |
171 | + year = [int(date1[0:4])-1, int(date1[0:4])] |
172 | + ids = account_analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', [account_id])]) |
173 | self.cr.execute("SELECT -sum(amount) as sum \ |
174 | FROM account_analytic_line \ |
175 | WHERE account_id in ("+ ','.join(map(str, ids)) +") \ |
176 | AND to_char(date, 'MM-DD')>=%s AND to_char(date, 'MM-DD')<=%s AND amount>0 \ |
177 | and date_part('year',date) in ("+ ','.join(map(str, year)) +") \ |
178 | group by date_part('year',date)",(date1[5:10], date2[5:10])) |
179 | - res= self.cr.dictfetchall() |
180 | - return res |
181 | + return self.cr.dictfetchall() |
182 | |
183 | def _move_sum_balance(self, account_id, date1, date2): |
184 | - res=[] |
185 | - account_analytic_obj = self.pool.get('account.analytic.account') |
186 | - ids = account_analytic_obj.search(self.cr, self.uid, |
187 | - [('parent_id', 'child_of', [account_id])]) |
188 | + result = [] |
189 | debit = self._move_sum_debit(account_id, date1, date2) |
190 | - temp =len(debit) |
191 | credit = self._move_sum_credit(account_id, date1, date2) |
192 | - for i in range(temp): |
193 | - res.append(debit[i]['sum']-credit[i]['sum']) |
194 | - return res |
195 | + for index in range(len(debit)): |
196 | + result.append(debit[index]['sum'] - credit[index]['sum']) |
197 | + return result |
198 | |
199 | def _move_sum_quantity(self, account_id, date1, date2): |
200 | - year=[] |
201 | - year.append(int(date1[0:4])-1) |
202 | - year.append(int(date1[0:4])) |
203 | account_analytic_obj = self.pool.get('account.analytic.account') |
204 | - ids = account_analytic_obj.search(self.cr, self.uid, |
205 | - [('parent_id', 'child_of', [account_id])]) |
206 | + year = [int(date1[0:4])-1, int(date1[0:4])] |
207 | + ids = account_analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', [account_id])]) |
208 | self.cr.execute("SELECT sum(unit_amount) as sum,date_part('year',date) as year \ |
209 | FROM account_analytic_line \ |
210 | WHERE account_id in ("+ ','.join(map(str, ids)) +") \ |
211 | AND to_char(date, 'MM-DD')>=%s AND to_char(date, 'MM-DD')<=%s AND amount<0 \ |
212 | and date_part('year',date) in ("+ ','.join(map(str, year)) +") \ |
213 | group by date_part('year',date)",(date1[5:10], date2[5:10])) |
214 | + |
215 | return self.cr.dictfetchall() or [] |
216 | |
217 | - |
218 | def _sum_debit(self, accounts, date1, date2): |
219 | - |
220 | - year=[] |
221 | - res=[] |
222 | - year.append(int(date1[0:4])-1) |
223 | - year.append(int(date1[0:4])) |
224 | + account_analytic_obj = self.pool.get('account.analytic.account') |
225 | + year = [int(date1[0:4])-1, int(date1[0:4])] |
226 | ids = map(lambda x: x.id, accounts) |
227 | if not len(ids): |
228 | return 0.0 |
229 | - account_analytic_obj = self.pool.get('account.analytic.account') |
230 | - ids2 = account_analytic_obj.search(self.cr, self.uid, |
231 | - [('parent_id', 'child_of', ids)]) |
232 | + |
233 | + ids2 = account_analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', ids)]) |
234 | self.cr.execute("SELECT sum(amount) as sum \ |
235 | FROM account_analytic_line \ |
236 | WHERE account_id in ("+ ','.join(map(str, ids2)) + " ) \ |
237 | @@ -175,20 +150,16 @@ |
238 | and date_part('year',date) in ("+ ','.join(map(str, year)) + " ) \ |
239 | group by date_part('year',date) ", |
240 | (date1[5:10], date2[5:10])) |
241 | - res= self.cr.dictfetchall() |
242 | - return res |
243 | + |
244 | + return self.cr.dictfetchall() |
245 | |
246 | def _sum_credit(self, accounts, date1, date2): |
247 | - year=[] |
248 | - year.append(int(date1[0:4])-1) |
249 | - year.append(int(date1[0:4])) |
250 | + account_analytic_obj = self.pool.get('account.analytic.account') |
251 | + year = [int(date1[0:4])-1, int(date1[0:4])] |
252 | ids = map(lambda x: x.id, accounts) |
253 | if not len(ids): |
254 | return 0.0 |
255 | - ids = map(lambda x: x.id, accounts) |
256 | - account_analytic_obj = self.pool.get('account.analytic.account') |
257 | - ids2 = account_analytic_obj.search(self.cr, self.uid, |
258 | - [('parent_id', 'child_of', ids)]) |
259 | + ids2 = account_analytic_obj.search(self.cr, self.uid, [('parent_id', 'child_of', ids)]) |
260 | self.cr.execute("SELECT -sum(amount) as sum \ |
261 | FROM account_analytic_line \ |
262 | WHERE account_id in ("+ ','.join(map(str, ids2)) +") \ |
263 | @@ -196,21 +167,18 @@ |
264 | and date_part('year',date) in ("+ ','.join(map(str, year)) +") \ |
265 | group by date_part('year',date) ", |
266 | (date1[5:10], date2[5:10])) |
267 | - res= self.cr.dictfetchall() |
268 | - return res |
269 | + return self.cr.dictfetchall() |
270 | + |
271 | def _sum_balance(self, accounts, date1, date2): |
272 | debit = self._sum_debit(accounts, date1, date2) or 0.0 |
273 | credit = self._sum_credit(accounts, date1, date2) or 0.0 |
274 | - res=[] |
275 | - temp=len(debit) |
276 | - for i in range(temp): |
277 | - res.append(debit[i]['sum']-credit[i]['sum']) |
278 | - return res |
279 | - |
280 | + result = [] |
281 | + for index in range(len(debit)): |
282 | + result.append(debit[index]['sum'] - credit[index]['sum']) |
283 | + return result |
284 | |
285 | report_sxw.report_sxw('report.account.analytic.account.balance.year', |
286 | 'account.analytic.account','addons/training_report/report/analytic_balance_year.rml', |
287 | parser=account_analytic_balance_year, header=False) |
288 | |
289 | - |
290 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
291 | |
292 | === modified file 'training_report/report_training_view.xml' |
293 | --- training_report/report_training_view.xml 2010-10-05 14:48:03 +0000 |
294 | +++ training_report/report_training_view.xml 2011-03-17 10:37:29 +0000 |
295 | @@ -3,14 +3,6 @@ |
296 | <data> |
297 | <menuitem id="menu_training_report" name="Reporting" parent="training.training_mi" sequence="100"/> |
298 | |
299 | - <wizard id="training_session_volume_report_wizard" |
300 | - model="training.session" |
301 | - menu="False" |
302 | - name="training.session.volume.report" |
303 | - string="Report Volume"/> |
304 | - |
305 | - <menuitem id="training_report_volume_mi" parent="menu_training_report" type="wizard" action="training_session_volume_report_wizard"/> |
306 | - |
307 | <record model="ir.ui.view" id="training_report_wizard_form"> |
308 | <field name="name">training_report_wizard</field> |
309 | <field name="model">training.report.wizard</field> |
310 | @@ -84,5 +76,6 @@ |
311 | </graph> |
312 | </field> |
313 | </record> |
314 | + |
315 | </data> |
316 | </openerp> |
317 | |
318 | === modified file 'training_report/training_report.py' |
319 | --- training_report/training_report.py 2011-02-09 15:47:36 +0000 |
320 | +++ training_report/training_report.py 2011-03-17 10:37:29 +0000 |
321 | @@ -20,10 +20,9 @@ |
322 | # |
323 | ############################################################################## |
324 | |
325 | +from osv import osv |
326 | +from osv import fields |
327 | import time |
328 | -import datetime |
329 | -from osv import fields,osv |
330 | -import tools |
331 | from tools.sql import drop_view_if_exists |
332 | import xlwt |
333 | import base64 |
334 | @@ -36,14 +35,14 @@ |
335 | from training.training import training_course_kind_compute |
336 | |
337 | # http://code.activestate.com/recipes/476197-first-last-day-of-the-month/#c1 |
338 | -def get_first_day(dt, d_years=0, d_months=0): |
339 | - # d_years, d_months are "deltas" to apply to dt |
340 | - y, m = dt.year + d_years, dt.month + d_months |
341 | - a, m = divmod(m-1, 12) |
342 | - return date(y+a, m+1, 1) |
343 | +def get_first_day(date, date_years=0, date_months=0): |
344 | + # date_years, date_months are "deltas" to apply to date |
345 | + year, month = date.year + date_years, datet.month + date_months |
346 | + avg, month = divmod(month - 1, 12) |
347 | + return date(year + avg, month + 1, 1) |
348 | |
349 | -def get_last_day(dt): |
350 | - return get_first_day(dt, 0, 1) + timedelta(-1) |
351 | +def get_last_day(date): |
352 | + return get_first_day(date, 0, 1) + timedelta(-1) |
353 | |
354 | |
355 | class subscription_line(osv.osv): |
356 | @@ -129,21 +128,11 @@ |
357 | class training_report_wizard(osv.osv): |
358 | _name = 'training.report.wizard' |
359 | |
360 | - |
361 | _columns = { |
362 | 'date_start' : fields.date('Date Start', required=True), |
363 | 'date_stop' : fields.date('Date Stop', required=True), |
364 | - |
365 | - 'state' : fields.selection([('init', 'Init'), |
366 | - ('result', 'Result')], |
367 | - 'State', |
368 | - required=True, |
369 | - readonly=True), |
370 | - |
371 | - 'report' : fields.selection([(report_name, report['title']) for report_name, report in REPORTS.iteritems()], |
372 | - 'Report', |
373 | - required=True), |
374 | - |
375 | + 'state' : fields.selection([('init', 'Init'),('result', 'Result')], 'State', required=True, readonly=True), |
376 | + 'report' : fields.selection([(report_name, report['title']) for report_name, report in REPORTS.iteritems()], 'Report', required=True), |
377 | 'filename' : fields.char('Filename', size=128, readonly=True), |
378 | 'file_data' : fields.binary('File', readonly=True), |
379 | } |
380 | @@ -155,11 +144,14 @@ |
381 | 'state' : lambda *a: 'init', |
382 | } |
383 | |
384 | - |
385 | def action_close(self, cr, uid, ids, context=None): |
386 | return {'type' : 'ir.actions.act_window_close'} |
387 | |
388 | def action_generate_report(self, cr, uid, ids, context=None): |
389 | + if not ids: |
390 | + return False |
391 | + if context is None: |
392 | + context = {} |
393 | def execute_query(group_column, column_name): |
394 | cr.execute(""" |
395 | SELECT l.%(gc)s as %(cn)s, |
396 | @@ -225,6 +217,7 @@ |
397 | """ % {'gc': group_column, 'cn': column_name} |
398 | , (this.date_start, this.date_stop)) |
399 | return cr.fetchall() |
400 | + |
401 | def stream_write_row(row_id, values): |
402 | row = stream.row(row_id) |
403 | for idx, value in enumerate(values): |
404 | @@ -277,14 +270,14 @@ |
405 | |
406 | |
407 | if this.report == 'sale.partner': |
408 | - for x in execute_query_invoice('partner_id', 'partner_id'): |
409 | - row_id = write_to_xls(row_id, x) |
410 | + for temp in execute_query_invoice('partner_id', 'partner_id'): |
411 | + row_id = write_to_xls(row_id, temp) |
412 | elif this.report == 'sale.supplier': |
413 | - for x in execute_query_invoice_supplier('partner_id', 'partner_id'): |
414 | - row_id = write_to_xls(row_id, x) |
415 | + for temp in execute_query_invoice_supplier('partner_id', 'partner_id'): |
416 | + row_id = write_to_xls(row_id, temp) |
417 | elif this.report == 'sale.user': |
418 | - for x in execute_query('create_uid', 'user_id'): |
419 | - row_id = write_to_xls(row_id, x) |
420 | + for temp in execute_query('create_uid', 'user_id'): |
421 | + row_id = write_to_xls(row_id, temp) |
422 | elif this.report == 'sale.offer': |
423 | cr.execute(""" |
424 | SELECT l.offer_id as offer_id, |
425 | @@ -303,11 +296,11 @@ |
426 | GROUP BY l.offer_id |
427 | """, (this.date_start, this.date_stop)) |
428 | |
429 | - for x in cr.fetchall(): |
430 | - row_id = write_to_xls(row_id, x) |
431 | + for temp in cr.fetchall(): |
432 | + row_id = write_to_xls(row_id, temp) |
433 | elif this.report == 'sale.product': |
434 | - for x in execute_query('product_id', 'product_id'): |
435 | - row_id = write_to_xls(row_id, x) |
436 | + for temp in execute_query('product_id', 'product_id'): |
437 | + row_id = write_to_xls(row_id, temp) |
438 | elif this.report == 'subscription.offer': |
439 | cr.execute(""" |
440 | SELECT toff.id AS offer_id, |
441 | @@ -328,8 +321,8 @@ |
442 | GROUP BY toff.id, toff.kind |
443 | ORDER BY turnover DESC |
444 | """, (this.date_start, this.date_stop)) |
445 | - for x in cr.fetchall(): |
446 | - row_id = write_to_xls(row_id, x) |
447 | + for temp in cr.fetchall(): |
448 | + row_id = write_to_xls(row_id, temp) |
449 | |
450 | wb.save(strIO) |
451 | |
452 | @@ -383,6 +376,7 @@ |
453 | 'offer_kind': fields.char('Offer Kind', size=16, readonly=True,), |
454 | 'analytic_account_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True,), |
455 | } |
456 | + |
457 | training_report_intra_session_seance_view() |
458 | |
459 | class training_report_session_stats_view(osv.osv): |
460 | @@ -444,45 +438,47 @@ |
461 | } |
462 | |
463 | def init(self, cr): |
464 | - drop_view_if_exists(cr, 'training_report_seance_stats_view', cascade=True) |
465 | + drop_view_if_exists(cr, 'training_report_seance_purchase_stats_view') |
466 | + drop_view_if_exists(cr, 'training_report_seance_stats_view') |
467 | cr.execute("""CREATE OR REPLACE VIEW training_report_seance_stats_view AS ( |
468 | |
469 | -select |
470 | - tsea.id AS seance_id, |
471 | - tsea.kind, |
472 | - tsea.duration, |
473 | - tsea.course_id, |
474 | - tg.name AS group_name, |
475 | - COALESCE(CASE WHEN (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END ) <= 0 THEN 1 ELSE (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END) END, 0) AS participant_count, |
476 | - CASE WHEN tsea.kind = 'exam' THEN pp.id ELSE tct.product_id END AS product_id, |
477 | - CASE WHEN tsea.kind = 'exam' THEN pt.standard_price ELSE pt2.standard_price END AS product_price, |
478 | - COALESCE(tsea.duration * (CASE WHEN tsea.kind = 'exam' THEN pt.standard_price ELSE pt2.standard_price END) / (CASE WHEN (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END ) <= 0 THEN 1 ELSE (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END) END), 0.0) AS one_trainer_cost, |
479 | - |
480 | - COALESCE((tsea.duration * (CASE WHEN tsea.kind = 'exam' THEN pt.standard_price ELSE pt2.standard_price END) / (CASE WHEN (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END ) <= 0 THEN 1 ELSE (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END) END)) * (CASE WHEN tsea.kind = 'exam' AND tsea.course_id IS NULL THEN 2.0 ELSE 1.0 END), 0.0) AS trainer_cost |
481 | - |
482 | - |
483 | -FROM |
484 | - training_seance tsea |
485 | -LEFT JOIN |
486 | - training_participation tp ON (tp.group_id = tsea.group_id AND tp.seance_id = tsea.id) |
487 | -INNER JOIN |
488 | - product_product pp ON (pp.default_code = 'R50H') |
489 | -LEFT JOIN |
490 | - training_course tc ON (tsea.kind != 'exam' AND tsea.course_id = tc.id) |
491 | -LEFT JOIN |
492 | - training_course_type tct ON (tc.course_type_id = tct.id) |
493 | -LEFT JOIN |
494 | - training_group tg ON (tsea.group_id = tg.id) |
495 | -LEFT JOIN |
496 | - product_product pp2 ON (tct.product_id = pp2.id) |
497 | -LEFT JOIN |
498 | - product_template pt ON (pp.product_tmpl_id = pt.id) |
499 | -LEFT JOIN |
500 | - product_template pt2 ON (pp2.product_tmpl_id = pt2.id) |
501 | -GROUP BY |
502 | - tsea.id, tsea.kind, tsea.duration, tsea.course_id, tg.name, tsea.manual, tsea.participant_count_manual, pp.id, tct.product_id, pt.standard_price, pt2.standard_price |
503 | - |
504 | - )""") |
505 | + select |
506 | + tsea.id AS seance_id, |
507 | + tsea.kind, |
508 | + tsea.duration, |
509 | + tsea.course_id, |
510 | + tg.name AS group_name, |
511 | + COALESCE(CASE WHEN (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END ) <= 0 THEN 1 ELSE (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END) END, 0) AS participant_count, |
512 | + CASE WHEN tsea.kind = 'exam' THEN pp.id ELSE tct.product_id END AS product_id, |
513 | + CASE WHEN tsea.kind = 'exam' THEN pt.standard_price ELSE pt2.standard_price END AS product_price, |
514 | + COALESCE(tsea.duration * (CASE WHEN tsea.kind = 'exam' THEN pt.standard_price ELSE pt2.standard_price END) / (CASE WHEN (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END ) <= 0 THEN 1 ELSE (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END) END), 0.0) AS one_trainer_cost, |
515 | + |
516 | + COALESCE((tsea.duration * (CASE WHEN tsea.kind = 'exam' THEN pt.standard_price ELSE pt2.standard_price END) / (CASE WHEN (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END ) <= 0 THEN 1 ELSE (CASE WHEN tsea.manual THEN tsea.participant_count_manual ELSE count(tp.id) END) END)) * (CASE WHEN tsea.kind = 'exam' AND tsea.course_id IS NULL THEN 2.0 ELSE 1.0 END), 0.0) AS trainer_cost |
517 | + |
518 | + |
519 | + FROM |
520 | + training_seance tsea |
521 | + LEFT JOIN |
522 | + training_participation tp ON (tp.group_id = tsea.group_id AND tp.seance_id = tsea.id) |
523 | + INNER JOIN |
524 | + product_product pp ON (pp.default_code = 'R50H') |
525 | + LEFT JOIN |
526 | + training_course tc ON (tsea.kind != 'exam' AND tsea.course_id = tc.id) |
527 | + LEFT JOIN |
528 | + training_course_type tct ON (tc.course_type_id = tct.id) |
529 | + LEFT JOIN |
530 | + training_group tg ON (tsea.group_id = tg.id) |
531 | + LEFT JOIN |
532 | + product_product pp2 ON (tct.product_id = pp2.id) |
533 | + LEFT JOIN |
534 | + product_template pt ON (pp.product_tmpl_id = pt.id) |
535 | + LEFT JOIN |
536 | + product_template pt2 ON (pp2.product_tmpl_id = pt2.id) |
537 | + GROUP BY |
538 | + tsea.id, tsea.kind, tsea.duration, tsea.course_id, tg.name, tsea.manual, tsea.participant_count_manual, pp.id, tct.product_id, pt.standard_price, pt2.standard_price |
539 | + |
540 | + )""") |
541 | + |
542 | training_report_seance_stats_view() |
543 | |
544 | class training_report_seance_purchase_stats_view(osv.osv): |
545 | @@ -507,16 +503,17 @@ |
546 | )""") |
547 | |
548 | _columns = { |
549 | - 'seance_id': fields.many2one('training.seance', 'Seance', readonly=True,), |
550 | - 'product_id': fields.many2one('product.product', 'Product', readonly=True,), |
551 | - 'total_qty': fields.integer('Total Product Quantity', readonly=True,), |
552 | - 'attachment_id': fields.many2one('ir.attachment', 'Attachment', readonly=True,), |
553 | - 'standard_price': fields.float('Product Standard Price', readonly=True,), |
554 | + 'seance_id': fields.many2one('training.seance', 'Seance', readonly=True), |
555 | + 'product_id': fields.many2one('product.product', 'Product', readonly=True), |
556 | + 'total_qty': fields.integer('Total Product Quantity', readonly=True), |
557 | + 'attachment_id': fields.many2one('ir.attachment', 'Attachment', readonly=True), |
558 | + 'standard_price': fields.float('Product Standard Price', readonly=True), |
559 | 'attachment_price': fields.float('Attachment Price', readonly=True), |
560 | 'price': fields.float('Purchase Line Price', readonly=True), |
561 | 'procurement_method': fields.char('Procurement Method', size=16, readonly=True), |
562 | 'procurement_price': fields.char('Procurement Price', size=16, readonly=True), |
563 | } |
564 | + |
565 | training_report_seance_purchase_stats_view() |
566 | |
567 | class training_report_costs_view(osv.osv): |
568 | @@ -525,16 +522,16 @@ |
569 | _auto = False |
570 | |
571 | _columns = { |
572 | - 'session_id': fields.many2one('training.session', 'Session', ), |
573 | - 'session_date': fields.datetime('Session Date'), |
574 | - 'seance_id': fields.many2one('training.seance', 'Seance', ), |
575 | - 'seance_kind': fields.selection(training_course_kind_compute, 'Seance Kind', ), |
576 | - 'seance_date': fields.datetime('Seance Date'), |
577 | - 'offer_kind': fields.selection(training_offer_kind_compute, 'Offer Kind', ), |
578 | - 'offer_id': fields.many2one('training.offer', 'Offer'), |
579 | - 'computed_course_id': fields.many2one('training.course', 'Course', ), |
580 | - 'computed_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account', ), |
581 | - 'product_line_id': fields.many2one('training.course_category', 'Product Line', ), |
582 | + 'session_id': fields.many2one('training.session', 'Session', readonly=True), |
583 | + 'session_date': fields.datetime('Session Date', readonly=True), |
584 | + 'seance_id': fields.many2one('training.seance', 'Seance', readonly=True), |
585 | + 'seance_kind': fields.selection(training_course_kind_compute, 'Seance Kind', readonly=True), |
586 | + 'seance_date': fields.datetime('Seance Date', readonly=True), |
587 | + 'offer_kind': fields.selection(training_offer_kind_compute, 'Offer Kind', readonly=True), |
588 | + 'offer_id': fields.many2one('training.offer', 'Offer', readonly=True), |
589 | + 'computed_course_id': fields.many2one('training.course', 'Course', readonly=True), |
590 | + 'computed_analytic_id': fields.many2one('account.analytic.account', 'Analytic Account', readonly=True), |
591 | + 'product_line_id': fields.many2one('training.course_category', 'Product Line', readonly=True), |
592 | } |
593 | |
594 | def init(self, cr): |
595 | @@ -577,20 +574,19 @@ |
596 | for sess_stats in cr.dictfetchall(): |
597 | sess_stats['duration'] = sess_stats['seances_duration'] |
598 | cache_session[sess_stats['session_id']] = sess_stats |
599 | + return True |
600 | |
601 | def docache_seance_populate(self, cr, uid, cache_seance, seance_ids): |
602 | if not seance_ids: |
603 | return |
604 | - |
605 | query_seance_ids = ','.join(map(str, seance_ids)) |
606 | - |
607 | # pre-compute procurement price |
608 | seance_procs_cache = {} |
609 | for seance_id in seance_ids: |
610 | seance_procs_cache[seance_id] = { |
611 | - 'proc_fix': 0.0, |
612 | - 'proc_sub': 0.0, |
613 | - } |
614 | + 'proc_fix': 0.0, |
615 | + 'proc_sub': 0.0, |
616 | + } |
617 | cr.execute("SELECT * FROM training_report_seance_purchase_stats_view trspsv WHERE seance_id IN (%s)" % (query_seance_ids)) |
618 | for purch_stat in cr.dictfetchall(): |
619 | price = purch_stat['price'] |
620 | @@ -610,6 +606,7 @@ |
621 | seance_stats['sessions_ratio'] = {} |
622 | |
623 | cache_seance[seance_stats['seance_id']] = seance_stats |
624 | + return True |
625 | |
626 | def docache_session(self, cache_session, session): |
627 | if session.id not in cache_session: |
628 | @@ -618,6 +615,7 @@ |
629 | 'subscription_count': session.confirmed_subscriptions, |
630 | 'duration': (sum([ seance.duration for seance in session.seance_ids]) or 1.0) / (float(len(session.group_ids)) or 1.0) |
631 | } |
632 | + return True |
633 | |
634 | def docache_seance(self, cr, uid, cache_seance, seance, context=None): |
635 | if seance.id not in cache_seance: |
636 | @@ -662,6 +660,7 @@ |
637 | 'group': seance.group_id.name, |
638 | 'sessions_ratio': {}, |
639 | } |
640 | + return True |
641 | |
642 | # print(" group class : %s" % (cache_seance[seance.id]['group'])) |
643 | # print(" trainer cost : %s" % (cache_seance[seance.id]['trainer_cost'])) |
644 | @@ -669,16 +668,18 @@ |
645 | # print(" participant cnt : %s" % (cache_seance[seance.id]['participants'])) |
646 | |
647 | def get_sale_price(self, cr, uid, theor_cost, context=None): |
648 | + if context is None: |
649 | + context = {} |
650 | offer_pool = self.pool.get('training.offer') |
651 | subl_pool = self.pool.get('training.subscription.line') |
652 | price = 0.0 |
653 | - if theor_cost['offer_kind'] == 'intra': |
654 | - o = offer_pool.browse(cr, uid, theor_cost['offer_id']) |
655 | - pcount = o.number_of_participants or 12 |
656 | - price = (o.sale_order_id and o.sale_order_id.amount_untaxed or 0.0) / pcount |
657 | + if theor_cost.get('offer_kind',False) == 'intra': |
658 | + offer_data = offer_pool.browse(cr, uid, theor_cost['offer_id']) |
659 | + participant_count = offer_data.number_of_participants or 12 |
660 | + price = (offer_data.sale_order_id and offer_data.sale_order_id.amount_untaxed or 0.0) / participant_count |
661 | else: |
662 | #price = subl_pool.read(cr, uid, theor_cost['id'], ['price'])['price'] |
663 | - price = theor_cost['subl_price'] |
664 | + price = theor_cost.get('subl_price') |
665 | return price |
666 | |
667 | training_report_costs_view() |
668 | @@ -716,7 +717,7 @@ |
669 | } |
670 | |
671 | def search(self, cr, uid, args, offset=0, limit=None, order=None, context=None, count=False): |
672 | - if not context: |
673 | + if context is None: |
674 | context = {} |
675 | if context.get('date_filter', '') == 'current_year': |
676 | args.extend([('date','>=',time.strftime('%Y-01-01')),('date','<=',time.strftime('%Y-12-31'))]) |
677 | @@ -725,10 +726,8 @@ |
678 | # month_start_dt = datetime.datetime(map(int, month_start.split('-'))) |
679 | # month_end = get_last_day(month_start_dt, d_month=1).strftime('%Y-%m-%d') |
680 | # args.extend |
681 | - r = super(training_report_confirmed_subscription_count, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) |
682 | - return r |
683 | + return super(training_report_confirmed_subscription_count, self).search(cr, uid, args, offset=offset, limit=limit, order=order, context=context, count=count) |
684 | |
685 | training_report_confirmed_subscription_count() |
686 | |
687 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
688 | - |
689 | |
690 | === modified file 'training_report/training_report.xml' |
691 | --- training_report/training_report.xml 2009-11-25 16:36:08 +0000 |
692 | +++ training_report/training_report.xml 2011-03-17 10:37:29 +0000 |
693 | @@ -1,6 +1,7 @@ |
694 | <?xml version="1.0" encoding="UTF-8"?> |
695 | <openerp> |
696 | <data> |
697 | + |
698 | <report auto="False" |
699 | id="account_analytic_account_balance" |
700 | menu="False" |
701 | @@ -9,12 +10,6 @@ |
702 | rml="/training_report/report/analytic_balance_year.rml" |
703 | string="Analytic Balance Year"/> |
704 | |
705 | - <wizard id="account_analytic_account_balance_report_year" |
706 | - keyword="client_print_multi" |
707 | - model="account.analytic.account" |
708 | - name="account.analytic.account.balance.year.report" |
709 | - string="Analytic Balance Year"/> |
710 | - |
711 | <report auto="False" |
712 | id="course_profitability" |
713 | menu="False" |
714 | @@ -24,13 +19,5 @@ |
715 | rml="training_report/report/course_profitability.rml" |
716 | /> |
717 | |
718 | - <wizard id="course_profitability_report" |
719 | - keyword="client_print_multi" |
720 | - model="training.course" |
721 | - name="training.course.profitability.report" |
722 | - string="Course Profitablility"/> |
723 | - |
724 | - |
725 | - |
726 | </data> |
727 | </openerp> |
728 | |
729 | === modified file 'training_report/wizard/__init__.py' |
730 | --- training_report/wizard/__init__.py 2010-03-10 20:55:08 +0000 |
731 | +++ training_report/wizard/__init__.py 2011-03-17 10:37:29 +0000 |
732 | @@ -21,9 +21,9 @@ |
733 | ############################################################################## |
734 | |
735 | |
736 | -import wizard_account_analytic_balance_report_year_to_date |
737 | -import wizard_course_profitability |
738 | -import wizard_session_volume |
739 | +import training_report_account_analytic_balance_year |
740 | +import training_report_course_profitability |
741 | +import training_report_session_volume |
742 | |
743 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
744 | |
745 | |
746 | === renamed file 'training_report/wizard/wizard_account_analytic_balance_report_year_to_date.py' => 'training_report/wizard/training_report_account_analytic_balance_year.py' |
747 | --- training_report/wizard/wizard_account_analytic_balance_report_year_to_date.py 2009-11-25 16:36:08 +0000 |
748 | +++ training_report/wizard/training_report_account_analytic_balance_year.py 2011-03-17 10:37:29 +0000 |
749 | @@ -20,38 +20,36 @@ |
750 | # |
751 | ############################################################################## |
752 | |
753 | + |
754 | +from osv import osv |
755 | +from osv import fields |
756 | import time |
757 | -import wizard |
758 | -import datetime |
759 | - |
760 | -dates_form = '''<?xml version="1.0"?> |
761 | -<form string="Select period"> |
762 | - <field name="date1"/> |
763 | - <field name="date2"/> |
764 | -</form>''' |
765 | - |
766 | -dates_fields = { |
767 | - 'date1': {'string':'Start of period', 'type':'date', 'required':True, 'default': lambda *a: time.strftime('%Y-01-01')}, |
768 | - 'date2': {'string':'End of period', 'type':'date', 'required':True, 'default': lambda *a: time.strftime('%Y-%m-%d')}, |
769 | -} |
770 | - |
771 | - |
772 | -class wizard_report(wizard.interface): |
773 | - |
774 | - |
775 | - states = { |
776 | - 'init': { |
777 | - 'actions': [], |
778 | - 'result': {'type':'form', 'arch':dates_form, 'fields':dates_fields, 'state':[('end','Cancel'), ('report','Print')]} |
779 | - }, |
780 | - 'report': { |
781 | - 'actions': [], |
782 | - 'result': {'type':'print', 'report':'account.analytic.account.balance.year', 'state':'end'} |
783 | + |
784 | +class training_report_account_analytic_balance_year(osv.osv_memory): |
785 | + _name = 'training.report.account.analytic.balance.year' |
786 | + _columns = { |
787 | + 'date1' : fields.date('Start of period', required=True), |
788 | + 'date2' : fields.date('End of period', required=True), |
789 | + } |
790 | + |
791 | + _defaults = { |
792 | + 'date1': lambda *a: time.strftime('%Y-01-01'), |
793 | + 'date2': lambda *a: time.strftime('%Y-%m-%d'), |
794 | + } |
795 | + |
796 | + def action_report(self, cr, uid, ids, context=None): |
797 | + if context is None: |
798 | + context = {} |
799 | + datas = {'form':{}, 'ids': context.get('active_ids', [])} |
800 | + res = self.read(cr, uid, ids, ['date1', 'date2'], context) |
801 | + res = res and res[0] or {} |
802 | + datas['form'].update(res) |
803 | + return { |
804 | + 'type': 'ir.actions.report.xml', |
805 | + 'report_name': 'account.analytic.account.balance.year', |
806 | + 'datas': datas, |
807 | } |
808 | - } |
809 | -wizard_report('account.analytic.account.balance.year.report') |
810 | - |
811 | - |
812 | + |
813 | +training_report_account_analytic_balance_year() |
814 | |
815 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
816 | - |
817 | |
818 | === added file 'training_report/wizard/training_report_account_analytic_balance_year_view.xml' |
819 | --- training_report/wizard/training_report_account_analytic_balance_year_view.xml 1970-01-01 00:00:00 +0000 |
820 | +++ training_report/wizard/training_report_account_analytic_balance_year_view.xml 2011-03-17 10:37:29 +0000 |
821 | @@ -0,0 +1,35 @@ |
822 | +<openerp> |
823 | + <data> |
824 | + |
825 | + <record model="ir.ui.view" id="training_report_account_analytic_balance_year_form"> |
826 | + <field name="name">training.report.account.analytic.balance.year.form</field> |
827 | + <field name="model">training.report.account.analytic.balance.year</field> |
828 | + <field name="type">form</field> |
829 | + <field name="arch" type="xml"> |
830 | + <form string="Analytic Balance Year"> |
831 | + <field name="date1"/> |
832 | + <field name="date2"/> |
833 | + <separator colspan="4" /> |
834 | + <group colspan="4" col="2"> |
835 | + <button string="Cancel" special="cancel" type="object" icon="gtk-cancel"/> |
836 | + <button name="action_report" string="Print" type="object" icon="gtk-print"/> |
837 | + </group> |
838 | + </form> |
839 | + </field> |
840 | + </record> |
841 | + |
842 | + <record model="ir.actions.act_window" id="training_report_account_analytic_balance_year_form_act"> |
843 | + <field name="name">Analytic Balance Year</field> |
844 | + <field name="res_model">training.report.account.analytic.balance.year</field> |
845 | + <field name="view_type">form</field> |
846 | + <field name="view_mode">form</field> |
847 | + <field name="target">new</field> |
848 | + </record> |
849 | + |
850 | + <act_window id="action_act_training_report_account_analytic_balance_year" |
851 | + key2="client_action_multi" name="Analytic Balance Year" |
852 | + res_model="training.report.account.analytic.balance.year" src_model="account.analytic.account" |
853 | + view_mode="form" target="new" view_type="form"/> |
854 | + |
855 | + </data> |
856 | +</openerp> |
857 | |
858 | === renamed file 'training_report/wizard/wizard_course_profitability.py' => 'training_report/wizard/training_report_course_profitability.py' |
859 | --- training_report/wizard/wizard_course_profitability.py 2009-11-25 16:36:08 +0000 |
860 | +++ training_report/wizard/training_report_course_profitability.py 2011-03-17 10:37:29 +0000 |
861 | @@ -20,42 +20,39 @@ |
862 | # |
863 | ############################################################################## |
864 | |
865 | + |
866 | +from osv import osv |
867 | +from osv import fields |
868 | import time |
869 | -import wizard |
870 | -import datetime |
871 | - |
872 | -dates_form = '''<?xml version="1.0"?> |
873 | -<form string="Select period"> |
874 | - <field name="date1"/> |
875 | - <field name="date2"/> |
876 | - <field name="analytic_account"/> |
877 | - <field name="analytic_fix_cost"/> |
878 | -</form>''' |
879 | - |
880 | -dates_fields = { |
881 | - 'date1': {'string':'Start of period', 'type':'date', 'required':True, 'default': lambda *a: time.strftime('%Y-01-01')}, |
882 | - 'date2': {'string':'End of period', 'type':'date', 'required':True, 'default': lambda *a: time.strftime('%Y-%m-%d')}, |
883 | - 'analytic_account':{'string':'Analytic Account', 'type':'many2one','relation': 'account.analytic.account', 'required':True}, |
884 | - 'analytic_fix_cost':{'string':'Analytic Fix Cost', 'type':'float'}, |
885 | -} |
886 | - |
887 | - |
888 | -class wizard_report(wizard.interface): |
889 | - |
890 | - |
891 | - states = { |
892 | - 'init': { |
893 | - 'actions': [], |
894 | - 'result': {'type':'form', 'arch':dates_form, 'fields':dates_fields, 'state':[('end','Cancel'), ('report','Print')]} |
895 | - }, |
896 | - 'report': { |
897 | - 'actions': [], |
898 | - 'result': {'type':'print', 'report':'training.course.profitability', 'state':'end'} |
899 | + |
900 | +class training_report_course_profitability(osv.osv_memory): |
901 | + _name = 'training.report.course.profitability' |
902 | + _columns = { |
903 | + 'date1' : fields.date('Start of period', required=True), |
904 | + 'date2' : fields.date('End of period', required=True), |
905 | + 'analytic_account' : fields.many2one('account.analytic.account', 'Analytic Account', required=True), |
906 | + 'analytic_fix_cost' : fields.float('Analytic Fix Cost'), |
907 | + } |
908 | + |
909 | + |
910 | + _defaults = { |
911 | + 'date1': lambda *a: time.strftime('%Y-01-01'), |
912 | + 'date2': lambda *a: time.strftime('%Y-%m-%d'), |
913 | + } |
914 | + |
915 | + def action_report(self, cr, uid, ids, context=None): |
916 | + if context is None: |
917 | + context = {} |
918 | + datas = {'form':{}, 'ids': context.get('active_ids', [])} |
919 | + res = self.read(cr, uid, ids, ['date1', 'date2', 'analytic_account', 'analytic_fix_cost'], context) |
920 | + res = res and res[0] or {} |
921 | + datas['form'].update(res) |
922 | + return { |
923 | + 'type': 'ir.actions.report.xml', |
924 | + 'report_name': 'training.course.profitability', |
925 | + 'datas': datas, |
926 | } |
927 | - } |
928 | -wizard_report('training.course.profitability.report') |
929 | - |
930 | - |
931 | + |
932 | +training_report_course_profitability() |
933 | |
934 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
935 | - |
936 | |
937 | === added file 'training_report/wizard/training_report_course_profitability_view.xml' |
938 | --- training_report/wizard/training_report_course_profitability_view.xml 1970-01-01 00:00:00 +0000 |
939 | +++ training_report/wizard/training_report_course_profitability_view.xml 2011-03-17 10:37:29 +0000 |
940 | @@ -0,0 +1,37 @@ |
941 | +<openerp> |
942 | + <data> |
943 | + |
944 | + <record model="ir.ui.view" id="view_training_report_course_profitability_form"> |
945 | + <field name="name">training.report.course.profitability.form</field> |
946 | + <field name="model">training.report.course.profitability</field> |
947 | + <field name="type">form</field> |
948 | + <field name="arch" type="xml"> |
949 | + <form string="Course Profitablility"> |
950 | + <field name="date1"/> |
951 | + <field name="date2"/> |
952 | + <field name="analytic_account"/> |
953 | + <field name="analytic_fix_cost"/> |
954 | + <separator colspan="4" /> |
955 | + <group colspan="4" col="2"> |
956 | + <button string="Cancel" special="cancel" type="object" icon="gtk-cancel"/> |
957 | + <button name="action_report" string="Print" type="object" icon="gtk-print"/> |
958 | + </group> |
959 | + </form> |
960 | + </field> |
961 | + </record> |
962 | + |
963 | + <record model="ir.actions.act_window" id="training_report_course_profitability_form_act"> |
964 | + <field name="name">Course Profitablility</field> |
965 | + <field name="res_model">training.report.course.profitability</field> |
966 | + <field name="view_type">form</field> |
967 | + <field name="view_mode">form</field> |
968 | + <field name="target">new</field> |
969 | + </record> |
970 | + |
971 | + <act_window id="action_act_training_report_course_profitability" |
972 | + key2="client_action_multi" name="Course Profitablility" |
973 | + res_model="training.report.course.profitability" src_model="training.course" |
974 | + view_mode="form" target="new" view_type="form"/> |
975 | + |
976 | + </data> |
977 | +</openerp> |
978 | |
979 | === renamed file 'training_report/wizard/wizard_session_volume.py' => 'training_report/wizard/training_report_session_volume.py' |
980 | --- training_report/wizard/wizard_session_volume.py 2010-09-22 10:00:18 +0000 |
981 | +++ training_report/wizard/training_report_session_volume.py 2011-03-17 10:37:29 +0000 |
982 | @@ -20,433 +20,383 @@ |
983 | # |
984 | ############################################################################## |
985 | |
986 | -import wizard |
987 | +from osv import osv |
988 | +from osv import fields |
989 | import time |
990 | -import datetime |
991 | -import pooler |
992 | import tools |
993 | |
994 | from tools.translate import _ |
995 | import mx.DateTime as dt |
996 | |
997 | -_aged_trial_form = """<?xml version="1.0"?> |
998 | -<form string="Session Volume Report"> |
999 | - <separator string="Period" colspan="4" /> |
1000 | - <field name="date_start"/> |
1001 | - <field name="date_stop"/> |
1002 | - <separator string="Year" colspan="4" /> |
1003 | - <field name="year" /> |
1004 | - <separator string="Report" colspan="4" /> |
1005 | - <field name="kind" /> |
1006 | -</form>""" |
1007 | - |
1008 | -def first_day_of_previous_month(): |
1009 | - return dt.strptime((dt.today() - dt.RelativeDate(months=1)).strftime('%Y-%m-01'), '%Y-%m-%d') |
1010 | - |
1011 | -def last_day_of_previous_month(): |
1012 | - return first_day_of_previous_month() + dt.RelativeDate(months=1, seconds=-1) |
1013 | - |
1014 | -_aged_trial_fields = { |
1015 | - 'date_start': {'string':'Start of period', 'type':'date', 'required':True, 'default': lambda *a: first_day_of_previous_month().strftime('%Y-%m-%d')}, |
1016 | - 'date_stop': {'string':'Stop of period', 'type':'date', 'required':True, 'default': lambda *a: last_day_of_previous_month().strftime('%Y-%m-%d')}, |
1017 | - 'year': {'string':'Year', 'type':'integer', 'required':True, 'default': lambda *a: -1}, |
1018 | - 'kind' : {'string' : 'Kind', |
1019 | - 'type' : 'selection', |
1020 | - 'selection' : [ |
1021 | +class training_report_session_volume(osv.osv_memory): |
1022 | + _name = 'training.report.session.volume' |
1023 | + _columns = { |
1024 | + 'date_start' : fields.date('Start of period', required=True), |
1025 | + 'date_stop' : fields.date('End of period', required=True), |
1026 | + 'year' : fields.integer('Year', required=True), |
1027 | + 'kind' : fields.selection([ |
1028 | ('product_lines', 'Statistics by Product Lines'), |
1029 | ('theoretical_product_lines', 'Theoretical Statistics by Product Lines'), |
1030 | ('sessions', 'Sessions volume by State'), |
1031 | ('count_subscriptions_offer', 'Subscription Volume by State'), |
1032 | #('subscriptions_partner', 'Partner Amount of Subscriptions'), |
1033 | - ], |
1034 | - 'default' : lambda *a: 'product_lines'} |
1035 | -} |
1036 | - |
1037 | -def previous_date(date, year): |
1038 | - return dt.strptime(date, '%Y-%m-%d') + dt.RelativeDate(years=year) |
1039 | - |
1040 | -def previous_period(date_start, date_stop, year): |
1041 | - return (previous_date(date_start, year), previous_date(date_stop, year)) |
1042 | - |
1043 | -def compute_theoretical_product_lines(cr, uid, ids, context, date_start, date_stop, kind): |
1044 | -# print(">>> --== Compute Theoretical Product Lines ==--") |
1045 | - pool = pooler.get_pool(cr.dbname) |
1046 | - session_pool = pool.get('training.session') |
1047 | - subl_pool = pool.get('training.subscription.line') |
1048 | - prodline_pool = pool.get('training.course_category') |
1049 | - offer_pool = pool.get('training.offer') |
1050 | - trcv_pool = pool.get('training.report.costs.view') |
1051 | - |
1052 | - cache_seance = {} |
1053 | - cache_session = {} |
1054 | - product_line = {} # dict containing cost + revenue per product lines |
1055 | - |
1056 | - query_base = "SELECT * FROM training_report_costs_view " |
1057 | - query = "WHERE seance_date BETWEEN %s AND %s AND offer_kind = %s" |
1058 | - query_args = (date_start, date_stop, kind) |
1059 | - |
1060 | - if kind == 'intra': |
1061 | - cr.execute("SELECT DISTINCT(session_id) FROM training_report_intra_session_seance_view " + query, query_args) |
1062 | - else: |
1063 | - cr.execute("SELECT DISTINCT(session_id) FROM training_report_costs_view " + query, query_args) |
1064 | - session_ids = [ x[0] for x in cr.fetchall() ] |
1065 | - trcv_pool.docache_session_populate(cr, uid, cache_session, session_ids) |
1066 | - |
1067 | - if kind == 'intra': |
1068 | - cr.execute("SELECT DISTINCT(seance_id) FROM training_report_intra_session_seance_view " + query, query_args) |
1069 | - else: |
1070 | - cr.execute("SELECT DISTINCT(seance_id) FROM training_report_costs_view " + query, query_args) |
1071 | - seance_ids = [ x[0] for x in cr.fetchall() ] |
1072 | - trcv_pool.docache_seance_populate(cr, uid, cache_seance, seance_ids) |
1073 | - |
1074 | - if kind != 'intra': |
1075 | - cr.execute(query_base + query, query_args) |
1076 | - for theor_cost in cr.dictfetchall(): |
1077 | - c_session_id = theor_cost['session_id'] |
1078 | - c_seance_id = theor_cost['seance_id'] |
1079 | - |
1080 | - if c_session_id not in cache_seance[c_seance_id]['sessions_ratio']: |
1081 | - # seance already cached, but we still need to update the session ratio |
1082 | - session_total_duration = cache_session[theor_cost['session_id']]['duration'] |
1083 | - cache_seance[c_seance_id]['sessions_ratio'][c_session_id] = cache_seance[c_seance_id]['duration'] / session_total_duration |
1084 | - |
1085 | - # all things are cached now |
1086 | - c_seance = cache_seance[theor_cost['seance_id']] |
1087 | - c_prodline_id = theor_cost['product_line_id'] |
1088 | - if c_prodline_id not in product_line: |
1089 | - plo = prodline_pool.browse(cr, uid, c_prodline_id) |
1090 | - product_line[c_prodline_id] = { |
1091 | - 'id': c_prodline_id, |
1092 | - 'name': plo.name, |
1093 | - 'costs': 0.0, |
1094 | - 'revenues': 0.0, |
1095 | - 'subscriptions': set(), |
1096 | - } |
1097 | - pl = product_line[c_prodline_id] |
1098 | - pl['costs'] += c_seance['trainer_cost'] + c_seance['proc_cost'] |
1099 | - pl['revenues'] += c_seance['sessions_ratio'][theor_cost['session_id']] * trcv_pool.get_sale_price(cr, uid, theor_cost, context=context) |
1100 | - pl['subscriptions'].add(theor_cost['id']) |
1101 | - else: # kind == 'intra' |
1102 | - cr.execute("SELECT * FROM training_report_intra_session_seance_view " + query, query_args) |
1103 | - for theor_intra in cr.dictfetchall(): |
1104 | - c_session_id = theor_intra['session_id'] |
1105 | - c_seance_id = theor_intra['seance_id'] |
1106 | - |
1107 | - if c_session_id not in cache_seance[c_seance_id]['sessions_ratio']: |
1108 | - # seance already cached, but we still need to update the session ratio |
1109 | - session_total_duration = cache_session[theor_intra['session_id']]['duration'] |
1110 | - cache_seance[c_seance_id]['sessions_ratio'][c_session_id] = cache_seance[c_seance_id]['duration'] / session_total_duration |
1111 | - |
1112 | - c_seance = cache_seance[theor_intra['seance_id']] |
1113 | - c_session = cache_session[theor_intra['session_id']] |
1114 | - |
1115 | - c_session_ratio = cache_seance[c_seance_id]['sessions_ratio'][c_session_id] |
1116 | - |
1117 | - c_prodline_id = theor_intra['product_line_id'] |
1118 | - if c_prodline_id not in product_line: |
1119 | - plo = prodline_pool.browse(cr, uid, c_prodline_id) |
1120 | - product_line[c_prodline_id] = { |
1121 | - 'id': c_prodline_id, |
1122 | - 'name': plo.name, |
1123 | - 'costs': 0.0, |
1124 | - 'revenues': 0.0, |
1125 | - 'subscriptions': set(), |
1126 | - } |
1127 | - pl = product_line[c_prodline_id] |
1128 | - pl['costs'] += c_session_ratio * theor_intra['session_cost'] |
1129 | - pl['revenues'] += c_session_ratio * theor_intra['session_revenue'] |
1130 | - for x in xrange(1, theor_intra['number_of_participants'] + 1): |
1131 | - pl['subscriptions'].add(x) |
1132 | - |
1133 | - res = [] |
1134 | - total = { 'revenues': 0.0, 'costs': 0.0 } |
1135 | - for p, v in product_line.iteritems(): |
1136 | - res.append(v) |
1137 | - v['subscriptions'] = len(v['subscriptions']) |
1138 | - v['margin'] = (v['revenues'] / (v['costs'] or 1.0)) * 100 |
1139 | - v['balance'] = (v['revenues'] - v['costs']) |
1140 | - total['revenues'] += v['revenues'] |
1141 | - total['costs'] += v['costs'] |
1142 | - |
1143 | - total['balance'] = total['revenues'] - total['costs'] |
1144 | - total['margin'] = (total['revenues'] / (total['costs'] or 1.0)) * 100 |
1145 | - |
1146 | - return { |
1147 | - 'product_lines': res, |
1148 | - 'total': total, |
1149 | - 'date_start': date_start, |
1150 | - 'date_stop': date_stop, |
1151 | - 'kind': kind, |
1152 | - } |
1153 | - |
1154 | -def compute_product_lines_exam(cr, uid, ids, context, date_start, date_stop): |
1155 | - res = [] |
1156 | - |
1157 | - |
1158 | - pool = pooler.get_pool(cr.dbname) |
1159 | - |
1160 | - tsl_proxy = pool.get('training.subscription.line') |
1161 | - |
1162 | - tsl_ids = tsl_proxy.search(cr, uid, |
1163 | - [ |
1164 | - ('state', 'not in', ('draft', 'cancelled')), |
1165 | - ('date', '>=', "%s 00:00:00" % (date_start)), |
1166 | - ('date', '<=', "%s 23:59:59" % (date_stop)), |
1167 | - ('kind', '=', 'exam'), |
1168 | - ], |
1169 | - context=context) |
1170 | - |
1171 | - product_lines = {} |
1172 | - |
1173 | - for sl in tsl_proxy.browse(cr, uid, tsl_ids, context=context): |
1174 | - |
1175 | - if not (sl.course_id and sl.course_id.category_id): |
1176 | - continue |
1177 | - |
1178 | - product_line_id = sl.course_id.category_id |
1179 | - |
1180 | - product_lines.setdefaults(product_line_id, []) |
1181 | - |
1182 | - if sl.invoice_line_id and sl.invoice_id: |
1183 | - product_lines[product_line_id].append(sl) |
1184 | - |
1185 | - |
1186 | -def compute_product_lines(cr, uid, ids, context, date_start, date_stop, kind): |
1187 | - res = [] |
1188 | - |
1189 | - pool = pooler.get_pool(cr.dbname) |
1190 | - tsl_proxy = pool.get('training.subscription.line') |
1191 | - |
1192 | - tsl_ids = tsl_proxy.search(cr, uid, |
1193 | - [ |
1194 | - ('state', 'not in', ('draft', 'cancelled')), |
1195 | - ('date', '>=', "%s 00:00:00" % (date_start)), |
1196 | - ('date', '<=', "%s 23:59:59" % (date_stop)), |
1197 | - ('kind', '=', kind), |
1198 | - ], |
1199 | - context=context) |
1200 | - |
1201 | - product_lines = {} |
1202 | - |
1203 | - for sl in tsl_proxy.browse(cr, uid, tsl_ids, context=context): |
1204 | - |
1205 | - session_id = sl.session_id |
1206 | - invoice_id = sl.invoice_id |
1207 | - |
1208 | - product_line_id = sl.session_id.offer_id.product_line_id |
1209 | - |
1210 | - product_lines.setdefault(product_line_id, |
1211 | - { |
1212 | - 'invoices' : set(), |
1213 | - 'sessions' : {}, |
1214 | - 'subscription_count' : 0, |
1215 | - 'exams' : {}, |
1216 | - } |
1217 | - ) |
1218 | - |
1219 | - product_lines[product_line_id]['subscription_count'] += 1 |
1220 | - |
1221 | - if invoice_id and sl.invoice_line_id: |
1222 | - product_lines[product_line_id]['invoices'].add(invoice_id) |
1223 | - |
1224 | - if sl.session_id not in product_lines[product_line_id]['sessions']: |
1225 | - |
1226 | - po_pool = pool.get('purchase.order') |
1227 | - sl_sess_seance_ids = [ seance.id for seance in session_id.seance_ids ] |
1228 | - sl_sess_po = po_pool.search(cr, uid, [('seance_id','in',sl_sess_seance_ids)], context=context) |
1229 | - value = sum(po.invoice_id and po.invoice_id.amount_untaxed or po.amount_untaxed |
1230 | - for po in po_pool.browse(cr, uid, sl_sess_po, context=context)) |
1231 | - #value = sum(po.procurement_id.purchase_id.amount_total |
1232 | - # for seance in session_id.seance_ids |
1233 | - # for po in seance.purchase_line_ids |
1234 | - # if po.procurement_id and po.procurement_id.purchase_id) |
1235 | - |
1236 | - value += sum(request.purchase_order_id.amount_untaxed |
1237 | - for request in session_id.request_ids |
1238 | - if request.purchase_order_id and request.state in ('accepted', 'done')) |
1239 | - |
1240 | - product_lines[product_line_id]['sessions'][sl.session_id] = value |
1241 | - |
1242 | - if sl.kind == 'exam' and sl.course_id and sl.course_id.category_id: |
1243 | - product_lines[product_line_id]['exams'].setdefault(sl.course_id.category_id, {'subscription_count' : 0, |
1244 | - 'price' : 0.0, |
1245 | - } |
1246 | - ) |
1247 | - product_line = product_lines[product_line_id]['exams'][sl.course_id.category_id] |
1248 | - product_line['subscription_count'] += 1 |
1249 | - product_line['price'] += sl.price |
1250 | - |
1251 | - for pl, data in product_lines.iteritems(): |
1252 | - subscription_count = data['subscription_count'] |
1253 | - |
1254 | - pl_input = sum(invoice_id.amount_untaxed for invoice_id in data['invoices']) |
1255 | - pl_output = sum( data['sessions'].values() or [0.0]) |
1256 | - |
1257 | - pl_balance = pl_input - pl_output |
1258 | - |
1259 | - pl_margin = (pl_input / (pl_output or 1.0)) * 100 |
1260 | - |
1261 | - pl_average_price = subscription_count > 0 and (pl_input / subscription_count) or 0 |
1262 | - pl_yield = subscription_count > 0 and (pl_balance / subscription_count) or 0 |
1263 | - |
1264 | - if ((-0.00001 < pl_input < 0.00001) or (-0.00001 < pl_output < 0.00001)): |
1265 | - pl_margin = _('N/A') |
1266 | + ], 'Kind', required=True) |
1267 | + } |
1268 | + |
1269 | + _defaults = { |
1270 | + 'date_start': lambda self, cr, uid, context: self.first_day_of_previous_month(cr, uid, context).strftime('%Y-%m-%d'), |
1271 | + 'date_stop': lambda self, cr, uid, context: self.last_day_of_previous_month(cr, uid, context).strftime('%Y-%m-%d'), |
1272 | + 'year': lambda *a: -1, |
1273 | + 'kind': lambda *a: 'product_lines', |
1274 | + } |
1275 | + |
1276 | + |
1277 | + def first_day_of_previous_month(self, cr, uid, context=None): |
1278 | + return dt.strptime((dt.today() - dt.RelativeDate(months=1)).strftime('%Y-%m-01'), '%Y-%m-%d') |
1279 | + |
1280 | + def last_day_of_previous_month(self, cr, uid, context=None): |
1281 | + return self.first_day_of_previous_month(cr, uid, context) + dt.RelativeDate(months=1, seconds=-1) |
1282 | + |
1283 | + def previous_date(self, cr, uid, date, year, context=None): |
1284 | + return dt.strptime(date, '%Y-%m-%d') + dt.RelativeDate(years=year) |
1285 | + |
1286 | + def previous_period(self, cr, uid, date_start, date_stop, year, context=None): |
1287 | + return (self.previous_date(cr, uid, date_start, year,context), self.previous_date(cr, uid, date_stop, year, context)) |
1288 | + |
1289 | + def compute_theoretical_product_lines(self, cr, uid, ids, date_start, date_stop, kind, context=None): |
1290 | + if context is None: |
1291 | + context = {} |
1292 | + session_pool = self.pool.get('training.session') |
1293 | + subl_pool = self.pool.get('training.subscription.line') |
1294 | + prodline_pool = self.pool.get('training.course_category') |
1295 | + offer_pool = self.pool.get('training.offer') |
1296 | + trcv_pool = self.pool.get('training.report.costs.view') |
1297 | + |
1298 | + cache_seance = {} |
1299 | + cache_session = {} |
1300 | + product_line = {} # dict containing cost + revenue per product lines |
1301 | + |
1302 | + query_base = "SELECT * FROM training_report_costs_view " |
1303 | + query = "WHERE seance_date BETWEEN %s AND %s AND offer_kind = %s" |
1304 | + query_args = (date_start, date_stop, kind) |
1305 | + |
1306 | + if kind == 'intra': |
1307 | + cr.execute("SELECT DISTINCT(session_id) FROM training_report_intra_session_seance_view " + query, query_args) |
1308 | + else: |
1309 | + cr.execute("SELECT DISTINCT(session_id) FROM training_report_costs_view " + query, query_args) |
1310 | + session_ids = [ x[0] for x in cr.fetchall() ] |
1311 | + trcv_pool.docache_session_populate(cr, uid, cache_session, session_ids) |
1312 | + |
1313 | + if kind == 'intra': |
1314 | + cr.execute("SELECT DISTINCT(seance_id) FROM training_report_intra_session_seance_view " + query, query_args) |
1315 | + else: |
1316 | + cr.execute("SELECT DISTINCT(seance_id) FROM training_report_costs_view " + query, query_args) |
1317 | + seance_ids = [ x[0] for x in cr.fetchall() ] |
1318 | + trcv_pool.docache_seance_populate(cr, uid, cache_seance, seance_ids) |
1319 | + |
1320 | + if kind != 'intra': |
1321 | + cr.execute(query_base + query, query_args) |
1322 | + for theor_cost in cr.dictfetchall(): |
1323 | + c_session_id = theor_cost['session_id'] |
1324 | + c_seance_id = theor_cost['seance_id'] |
1325 | + |
1326 | + if c_session_id not in cache_seance[c_seance_id]['sessions_ratio']: |
1327 | + # seance already cached, but we still need to update the session ratio |
1328 | + session_total_duration = cache_session[theor_cost['session_id']]['duration'] |
1329 | + cache_seance[c_seance_id]['sessions_ratio'][c_session_id] = cache_seance[c_seance_id]['duration'] / session_total_duration |
1330 | + |
1331 | + # all things are cached now |
1332 | + c_seance = cache_seance[theor_cost['seance_id']] |
1333 | + c_prodline_id = theor_cost['product_line_id'] |
1334 | + if c_prodline_id not in product_line: |
1335 | + plo = prodline_pool.browse(cr, uid, c_prodline_id) |
1336 | + product_line[c_prodline_id] = { |
1337 | + 'id': c_prodline_id, |
1338 | + 'name': plo.name, |
1339 | + 'costs': 0.0, |
1340 | + 'revenues': 0.0, |
1341 | + 'subscriptions': set(), |
1342 | + } |
1343 | + pl = product_line[c_prodline_id] |
1344 | + pl['costs'] += c_seance['trainer_cost'] + c_seance['proc_cost'] |
1345 | + pl['revenues'] += c_seance['sessions_ratio'][theor_cost['session_id']] * trcv_pool.get_sale_price(cr, uid, theor_cost, context=context) |
1346 | + pl['subscriptions'].add(theor_cost['id']) |
1347 | + else: # kind == 'intra' |
1348 | + cr.execute("SELECT * FROM training_report_intra_session_seance_view " + query, query_args) |
1349 | + for theor_intra in cr.dictfetchall(): |
1350 | + c_session_id = theor_intra['session_id'] |
1351 | + c_seance_id = theor_intra['seance_id'] |
1352 | + |
1353 | + if c_session_id not in cache_seance[c_seance_id]['sessions_ratio']: |
1354 | + # seance already cached, but we still need to update the session ratio |
1355 | + session_total_duration = cache_session[theor_intra['session_id']]['duration'] |
1356 | + cache_seance[c_seance_id]['sessions_ratio'][c_session_id] = cache_seance[c_seance_id]['duration'] / session_total_duration |
1357 | + |
1358 | + c_seance = cache_seance[theor_intra['seance_id']] |
1359 | + c_session = cache_session[theor_intra['session_id']] |
1360 | + |
1361 | + c_session_ratio = cache_seance[c_seance_id]['sessions_ratio'][c_session_id] |
1362 | + |
1363 | + c_prodline_id = theor_intra['product_line_id'] |
1364 | + if c_prodline_id not in product_line: |
1365 | + plo = prodline_pool.browse(cr, uid, c_prodline_id) |
1366 | + product_line[c_prodline_id] = { |
1367 | + 'id': c_prodline_id, |
1368 | + 'name': plo.name, |
1369 | + 'costs': 0.0, |
1370 | + 'revenues': 0.0, |
1371 | + 'subscriptions': set(), |
1372 | + } |
1373 | + pl = product_line[c_prodline_id] |
1374 | + pl['costs'] += c_session_ratio * theor_intra['session_cost'] |
1375 | + pl['revenues'] += c_session_ratio * theor_intra['session_revenue'] |
1376 | + for x in xrange(1, theor_intra['number_of_participants'] + 1): |
1377 | + pl['subscriptions'].add(x) |
1378 | + |
1379 | + res = [] |
1380 | + total = { 'revenues': 0.0, 'costs': 0.0 } |
1381 | + for p, v in product_line.iteritems(): |
1382 | + res.append(v) |
1383 | + v['subscriptions'] = len(v['subscriptions']) |
1384 | + v['margin'] = (v['revenues'] / (v['costs'] or 1.0)) * 100 |
1385 | + v['balance'] = (v['revenues'] - v['costs']) |
1386 | + total['revenues'] += v['revenues'] |
1387 | + total['costs'] += v['costs'] |
1388 | + |
1389 | + total['balance'] = total['revenues'] - total['costs'] |
1390 | + total['margin'] = (total['revenues'] / (total['costs'] or 1.0)) * 100 |
1391 | + |
1392 | + return { |
1393 | + 'product_lines': res, |
1394 | + 'total': total, |
1395 | + 'date_start': date_start, |
1396 | + 'date_stop': date_stop, |
1397 | + 'kind': kind, |
1398 | + } |
1399 | + |
1400 | +# def compute_product_lines_exam(self, cr, uid, ids, date_start, date_stop, context=None): |
1401 | +# if context is None: |
1402 | +# context = {} |
1403 | +# tsl_proxy = self.pool.get('training.subscription.line') |
1404 | +# tsl_ids = tsl_proxy.search(cr, uid, |
1405 | +# [ |
1406 | +# ('state', 'not in', ('draft', 'cancelled')), |
1407 | +# ('date', '>=', "%s 00:00:00" % (date_start)), |
1408 | +# ('date', '<=', "%s 23:59:59" % (date_stop)), |
1409 | +# ('kind', '=', 'exam'), |
1410 | +# ], |
1411 | +# context=context) |
1412 | +# |
1413 | +# product_lines = {} |
1414 | +# for sl in tsl_proxy.browse(cr, uid, tsl_ids, context=context): |
1415 | +# if not (sl.course_id and sl.course_id.category_id): |
1416 | +# continue |
1417 | +# product_line_id = sl.course_id.category_id |
1418 | +# product_lines.setdefaults(product_line_id, []) |
1419 | +# if sl.invoice_line_id and sl.invoice_id: |
1420 | +# product_lines[product_line_id].append(sl) |
1421 | +# return True |
1422 | + |
1423 | + def compute_product_lines(self, cr, uid, ids, date_start, date_stop, kind, context=None): |
1424 | + if context is None: |
1425 | + context = {} |
1426 | + res = [] |
1427 | + tsl_proxy = self.pool.get('training.subscription.line') |
1428 | + tsl_ids = tsl_proxy.search(cr, uid, |
1429 | + [ |
1430 | + ('state', 'not in', ('draft', 'cancelled')), |
1431 | + ('date', '>=', "%s 00:00:00" % (date_start)), |
1432 | + ('date', '<=', "%s 23:59:59" % (date_stop)), |
1433 | + ('kind', '=', kind), |
1434 | + ], |
1435 | + context=context) |
1436 | + product_lines = {} |
1437 | + for sl in tsl_proxy.browse(cr, uid, tsl_ids, context=context): |
1438 | + session_id = sl.session_id |
1439 | + invoice_id = sl.invoice_id |
1440 | + product_line_id = sl.session_id.offer_id.product_line_id |
1441 | + product_lines.setdefault(product_line_id, |
1442 | + { |
1443 | + 'invoices' : set(), |
1444 | + 'sessions' : {}, |
1445 | + 'subscription_count' : 0, |
1446 | + 'exams' : {}, |
1447 | + }) |
1448 | + product_lines[product_line_id]['subscription_count'] += 1 |
1449 | + |
1450 | + if invoice_id and sl.invoice_line_id: |
1451 | + product_lines[product_line_id]['invoices'].add(invoice_id) |
1452 | + |
1453 | + if sl.session_id not in product_lines[product_line_id]['sessions']: |
1454 | + |
1455 | + po_pool = self.pool.get('purchase.order') |
1456 | + sl_sess_seance_ids = [ seance.id for seance in session_id.seance_ids ] |
1457 | + sl_sess_po = po_pool.search(cr, uid, [('seance_id','in',sl_sess_seance_ids)], context=context) |
1458 | + value = sum(po.invoice_id and po.invoice_id.amount_untaxed or po.amount_untaxed |
1459 | + for po in po_pool.browse(cr, uid, sl_sess_po, context=context)) |
1460 | + #value = sum(po.procurement_id.purchase_id.amount_total |
1461 | + # for seance in session_id.seance_ids |
1462 | + # for po in seance.purchase_line_ids |
1463 | + # if po.procurement_id and po.procurement_id.purchase_id) |
1464 | + |
1465 | + value += sum(request.purchase_order_id.amount_untaxed |
1466 | + for request in session_id.request_ids |
1467 | + if request.purchase_order_id and request.state in ('accepted', 'done')) |
1468 | + |
1469 | + product_lines[product_line_id]['sessions'][sl.session_id] = value |
1470 | + |
1471 | + if sl.kind == 'exam' and sl.course_id and sl.course_id.category_id: |
1472 | + product_lines[product_line_id]['exams'].setdefault(sl.course_id.category_id, {'subscription_count' : 0, |
1473 | + 'price' : 0.0, |
1474 | + }) |
1475 | + product_line = product_lines[product_line_id]['exams'][sl.course_id.category_id] |
1476 | + product_line['subscription_count'] += 1 |
1477 | + product_line['price'] += sl.price |
1478 | + |
1479 | + for pl, data in product_lines.iteritems(): |
1480 | + subscription_count = data['subscription_count'] |
1481 | + pl_input = sum(invoice_id.amount_untaxed for invoice_id in data['invoices']) |
1482 | + pl_output = sum( data['sessions'].values() or [0.0]) |
1483 | + pl_balance = pl_input - pl_output |
1484 | + pl_margin = (pl_input / (pl_output or 1.0)) * 100 |
1485 | + pl_average_price = subscription_count > 0 and (pl_input / subscription_count) or 0 |
1486 | + pl_yield = subscription_count > 0 and (pl_balance / subscription_count) or 0 |
1487 | + |
1488 | + if ((-0.00001 < pl_input < 0.00001) or (-0.00001 < pl_output < 0.00001)): |
1489 | + pl_margin = _('N/A') |
1490 | + |
1491 | + values = { |
1492 | + 'id' : pl.id, |
1493 | + 'name' : pl.name, |
1494 | + 'input' : pl_input, |
1495 | + 'output' : pl_output, |
1496 | + 'balance' : pl_balance, |
1497 | + 'subscription_count' : subscription_count, |
1498 | + 'margin' : pl_margin, |
1499 | + 'average_price' : pl_average_price, |
1500 | + 'yield' : pl_yield, |
1501 | + 'exams' : [(category.name, vals['subscription_count'], vals['price']) for category, vals in data['exams'].iteritems()] |
1502 | + } |
1503 | + |
1504 | + res.append(values) |
1505 | |
1506 | values = { |
1507 | - 'id' : pl.id, |
1508 | - 'name' : pl.name, |
1509 | - 'input' : pl_input, |
1510 | - 'output' : pl_output, |
1511 | - 'balance' : pl_balance, |
1512 | - 'subscription_count' : subscription_count, |
1513 | - 'margin' : pl_margin, |
1514 | - 'average_price' : pl_average_price, |
1515 | - 'yield' : pl_yield, |
1516 | - 'exams' : [(category.name, vals['subscription_count'], vals['price']) for category, vals in data['exams'].iteritems()] |
1517 | - } |
1518 | - |
1519 | - res.append(values) |
1520 | - |
1521 | - values = { |
1522 | - 'subscription' : sum(line['subscription_count'] for line in res), |
1523 | - 'input' : sum(line['input'] for line in res), |
1524 | - 'output' : sum(line['output'] for line in res), |
1525 | - } |
1526 | - |
1527 | - values['balance'] = values['input'] - values['output'] |
1528 | - if (-0.00001 < values['input'] < 0.00001) or (-0.00001 < values['output'] < 0.00001): |
1529 | - values['margin'] = _('N/A') |
1530 | - else: |
1531 | - values['margin'] = (values['input'] / (values['output'] or 1.0)) * 100.0 |
1532 | - values['average_price'] = values['subscription'] > 0 and (values['input'] / values['subscription']) or 0 |
1533 | - values['yield'] = values['subscription'] > 0 and (values['balance'] / values['subscription']) or 0 |
1534 | - |
1535 | - return { |
1536 | - 'product_lines' : res, |
1537 | - 'total' : values, |
1538 | - 'date_start' : date_start, |
1539 | - 'date_stop' : date_stop, |
1540 | - 'kind' : kind, |
1541 | - } |
1542 | - |
1543 | -def compute_sessions(cr, uid, ids, context, date_start, date_stop): |
1544 | - return { |
1545 | - 'lines' : [], |
1546 | - 'date_start' : date_start, |
1547 | - 'date_stop' : date_stop, |
1548 | - } |
1549 | - |
1550 | -def compute_subscrtiption_partner(cr, uid, ids, context, date_start, date_stop): |
1551 | - cr.execute(""" |
1552 | - SELECT res.name, coalesce(sum(tsl.price), 0.0) as total_price |
1553 | - FROM training_subscription_line tsl, |
1554 | - res_partner res, |
1555 | - training_session s |
1556 | - WHERE res.id = tsl.partner_id |
1557 | - AND tsl.session_id = s.id |
1558 | - AND tsl.state IN ('confirmed', 'done') |
1559 | - AND s.date BETWEEN %s AND %s |
1560 | - GROUP BY tsl.partner_id,res.name |
1561 | - ORDER BY total_price DESC |
1562 | - """, (date_start, date_stop)) |
1563 | - |
1564 | - return { |
1565 | - 'lines' : [{'name' : name, 'price' : price} for name, price in cr.fetchall()], |
1566 | - 'date_start' : date_start, |
1567 | - 'date_stop' : date_stop, |
1568 | - } |
1569 | - |
1570 | -def compute_count_subscriptions_offer(cr, uid, ids, context, date_start, date_stop): |
1571 | - return { |
1572 | - 'lines' : [], |
1573 | - 'date_start' : date_start, |
1574 | - 'date_stop' : date_stop, |
1575 | - } |
1576 | - |
1577 | -def _select(self, cr, uid, data, context=None): |
1578 | - functions = { |
1579 | - 'sessions' : compute_sessions, |
1580 | - 'count_subscriptions_offer' : compute_count_subscriptions_offer, |
1581 | - 'subscriptions_partner' : compute_subscrtiption_partner, |
1582 | - } |
1583 | - |
1584 | - date_start = data['form']['date_start'] |
1585 | - date_stop = data['form']['date_stop'] |
1586 | - |
1587 | - old_date_start, old_date_stop = previous_period(date_start, date_stop, data['form']['year']) |
1588 | - |
1589 | - old_date_start = old_date_start.strftime('%Y-%m-%d') |
1590 | - old_date_stop = old_date_stop.strftime('%Y-%m-%d') |
1591 | - |
1592 | - if data['form']['kind'] == 'product_lines': |
1593 | - for kind in ('standard', 'exam', 'intra'): |
1594 | - data['form']['selected_period_%s' % kind] = compute_product_lines(cr, uid, data, context, date_start, date_stop, kind) |
1595 | - data['form']['old_period_%s' % kind] = compute_product_lines(cr, uid, data, context, old_date_start, old_date_stop, kind) |
1596 | - elif data['form']['kind'] == 'theoretical_product_lines': |
1597 | - for kind in ('standard', 'exam', 'intra'): |
1598 | - data['form']['selected_period_%s' % kind] = compute_theoretical_product_lines(cr, uid, data, context, date_start, date_stop, kind) |
1599 | - else: |
1600 | - function = functions[data['form']['kind']] |
1601 | - data['form']['selected_period'] = function(cr, uid, data, context, date_start, date_stop) |
1602 | - data['form']['old_period'] = function(cr, uid, data, context, old_date_start, old_date_stop) |
1603 | - |
1604 | - print(">>> _select :: got dataz" % (data)) |
1605 | - return data['form'] |
1606 | - |
1607 | -class wizard_report(wizard.interface): |
1608 | - def _select_report(self, cr, uid, data, context=None): |
1609 | - return "report_%s" % (data['form']['kind'],) |
1610 | - |
1611 | - states = { |
1612 | - 'init': { |
1613 | - 'result': {'type':'form', |
1614 | - 'arch':_aged_trial_form, |
1615 | - 'fields':_aged_trial_fields, |
1616 | - 'state':[('end','Cancel'),('choice','Print')]}, |
1617 | - }, |
1618 | - 'choice' : { |
1619 | - 'actions' : [], |
1620 | - 'result' : { 'type' : 'choice', 'next_state' : _select_report }, |
1621 | - }, |
1622 | - 'report_product_lines': { |
1623 | - 'actions': [_select], |
1624 | - 'result': {'type' : 'print', |
1625 | - 'report' : 'training.session.volume', |
1626 | - 'state' : 'end'}, |
1627 | - }, |
1628 | - 'report_theoretical_product_lines': { |
1629 | - 'actions': [_select], |
1630 | - 'result': { |
1631 | - 'type': 'print', |
1632 | - 'report': 'training.session.volume.theoretical', |
1633 | - 'state': 'end', |
1634 | - }, |
1635 | - }, |
1636 | - 'report_sessions' : { |
1637 | - 'actions' : [_select], |
1638 | - 'result' : { |
1639 | - 'type' : 'print', |
1640 | - 'report' : 'training.session.report', |
1641 | - 'state' : 'end', |
1642 | - }, |
1643 | - }, |
1644 | - 'report_count_subscriptions_offer' : { |
1645 | - 'actions' : [_select], |
1646 | - 'result' : { |
1647 | - 'type' : 'print', |
1648 | - 'report' : 'training.count.subscriptions.offer', |
1649 | - 'state' : 'end', |
1650 | - }, |
1651 | - }, |
1652 | - 'report_subscriptions_partner' : { |
1653 | - 'actions' : [_select], |
1654 | - 'result' : { |
1655 | - 'type' : 'print', |
1656 | - 'report' : 'training.subscriptions.partner', |
1657 | - 'state' : 'end', |
1658 | - }} |
1659 | - } |
1660 | - |
1661 | -wizard_report('training.session.volume.report') |
1662 | + 'subscription' : sum(line['subscription_count'] for line in res), |
1663 | + 'input' : sum(line['input'] for line in res), |
1664 | + 'output' : sum(line['output'] for line in res), |
1665 | + } |
1666 | + |
1667 | + values['balance'] = values['input'] - values['output'] |
1668 | + if (-0.00001 < values['input'] < 0.00001) or (-0.00001 < values['output'] < 0.00001): |
1669 | + values['margin'] = _('N/A') |
1670 | + else: |
1671 | + values['margin'] = (values['input'] / (values['output'] or 1.0)) * 100.0 |
1672 | + values['average_price'] = values['subscription'] > 0 and (values['input'] / values['subscription']) or 0 |
1673 | + values['yield'] = values['subscription'] > 0 and (values['balance'] / values['subscription']) or 0 |
1674 | + |
1675 | + return { |
1676 | + 'product_lines' : res, |
1677 | + 'total' : values, |
1678 | + 'date_start' : date_start, |
1679 | + 'date_stop' : date_stop, |
1680 | + 'kind' : kind, |
1681 | + } |
1682 | + |
1683 | + def compute_sessions(self, cr, uid, ids, date_start, date_stop, context): |
1684 | + return { |
1685 | + 'lines' : [], |
1686 | + 'date_start' : date_start, |
1687 | + 'date_stop' : date_stop, |
1688 | + } |
1689 | + |
1690 | + def compute_subscrtiption_partner(self, cr, uid, ids, date_start, date_stop, context): |
1691 | + cr.execute(""" |
1692 | + SELECT res.name, coalesce(sum(tsl.price), 0.0) as total_price |
1693 | + FROM training_subscription_line tsl, |
1694 | + res_partner res, |
1695 | + training_session s |
1696 | + WHERE res.id = tsl.partner_id |
1697 | + AND tsl.session_id = s.id |
1698 | + AND tsl.state IN ('confirmed', 'done') |
1699 | + AND s.date BETWEEN %s AND %s |
1700 | + GROUP BY tsl.partner_id,res.name |
1701 | + ORDER BY total_price DESC |
1702 | + """, (date_start, date_stop)) |
1703 | + |
1704 | + return { |
1705 | + 'lines' : [{'name' : name, 'price' : price} for name, price in cr.fetchall()], |
1706 | + 'date_start' : date_start, |
1707 | + 'date_stop' : date_stop, |
1708 | + } |
1709 | + |
1710 | + def compute_count_subscriptions_offer(self, cr, uid, ids, date_start, date_stop, context): |
1711 | + return { |
1712 | + 'lines' : [], |
1713 | + 'date_start' : date_start, |
1714 | + 'date_stop' : date_stop, |
1715 | + } |
1716 | + |
1717 | + def _select(self, cr, uid, data, context=None): |
1718 | + if context is None: |
1719 | + context = {} |
1720 | + functions = { |
1721 | + 'sessions' : self.compute_sessions, |
1722 | + 'count_subscriptions_offer' : self.compute_count_subscriptions_offer, |
1723 | + 'subscriptions_partner' : self.compute_subscrtiption_partner, |
1724 | + } |
1725 | + |
1726 | + date_start = data['form']['date_start'] |
1727 | + date_stop = data['form']['date_stop'] |
1728 | + |
1729 | + old_date_start, old_date_stop = self.previous_period(cr, uid, date_start, date_stop, data['form']['year'], context) |
1730 | + |
1731 | + old_date_start = old_date_start.strftime('%Y-%m-%d') |
1732 | + old_date_stop = old_date_stop.strftime('%Y-%m-%d') |
1733 | + |
1734 | + if data['form']['kind'] == 'product_lines': |
1735 | + for kind in ('standard', 'exam', 'intra'): |
1736 | + data['form']['selected_period_%s' % kind] = self.compute_product_lines(cr, uid, data, date_start, date_stop, kind, context) |
1737 | + data['form']['old_period_%s' % kind] = self.compute_product_lines(cr, uid, data, old_date_start, old_date_stop, kind, context) |
1738 | + elif data['form']['kind'] == 'theoretical_product_lines': |
1739 | + for kind in ('standard', 'exam', 'intra'): |
1740 | + data['form']['selected_period_%s' % kind] = self.compute_theoretical_product_lines(cr, uid, data, date_start, date_stop, kind, context) |
1741 | + else: |
1742 | + function = functions[data['form']['kind']] |
1743 | + data['form']['selected_period'] = function(cr, uid, data, date_start, date_stop, context) |
1744 | + data['form']['old_period'] = function(cr, uid, data, old_date_start, old_date_stop, context) |
1745 | + |
1746 | + return data['form'] |
1747 | + |
1748 | + def action_print(self, cr, uid, ids, context=None): |
1749 | + if context is None: |
1750 | + context = {} |
1751 | + datas = {'form':{}, 'ids': context.get('active_ids', [])} |
1752 | + res = self.read(cr, uid, ids, ['date_start', 'date_stop', 'year', 'kind'], context) |
1753 | + res = res and res[0] or {} |
1754 | + datas['form'].update(res) |
1755 | + |
1756 | + report_name = False |
1757 | + if res.get('kind',False) == 'product_lines': |
1758 | + report_name = 'training.session.volume' |
1759 | + elif res.get('kind',False) == 'theoretical_product_lines': |
1760 | + report_name = 'training.session.volume.theoretical' |
1761 | + elif res.get('kind',False) == 'sessions': |
1762 | + report_name = 'training.session.report' |
1763 | + elif res.get('kind',False) == 'count_subscriptions_offer': |
1764 | + report_name = 'training.count.subscriptions.offer' |
1765 | + elif res.get('kind',False) == 'subscriptions_partner': |
1766 | + report_name = 'training.subscriptions.partner' |
1767 | + if not report_name: |
1768 | + return {} |
1769 | + |
1770 | + new_datas = self._select(cr, uid, datas, context) |
1771 | + datas['form'].update(new_datas) |
1772 | + return { |
1773 | + 'type': 'ir.actions.report.xml', |
1774 | + 'report_name': report_name, |
1775 | + 'datas': datas, |
1776 | + } |
1777 | + |
1778 | +training_report_session_volume() |
1779 | |
1780 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
1781 | |
1782 | === added file 'training_report/wizard/training_report_session_volume_view.xml' |
1783 | --- training_report/wizard/training_report_session_volume_view.xml 1970-01-01 00:00:00 +0000 |
1784 | +++ training_report/wizard/training_report_session_volume_view.xml 2011-03-17 10:37:29 +0000 |
1785 | @@ -0,0 +1,37 @@ |
1786 | +<openerp> |
1787 | + <data> |
1788 | + |
1789 | + <record model="ir.ui.view" id="view_training_report_session_volume_form"> |
1790 | + <field name="name">training.report.session.volume.form</field> |
1791 | + <field name="model">training.report.session.volume</field> |
1792 | + <field name="type">form</field> |
1793 | + <field name="arch" type="xml"> |
1794 | + <form string="Session Volume Report"> |
1795 | + <separator string="Period" colspan="4" /> |
1796 | + <field name="date_start"/> |
1797 | + <field name="date_stop"/> |
1798 | + <separator string="Year" colspan="4" /> |
1799 | + <field name="year" /> |
1800 | + <separator string="Report" colspan="4" /> |
1801 | + <field name="kind" /> |
1802 | + <separator colspan="4" /> |
1803 | + <group colspan="4" col="2"> |
1804 | + <button string="Cancel" special="cancel" type="object" icon="gtk-cancel"/> |
1805 | + <button name="action_print" string="Print" type="object" icon="gtk-print"/> |
1806 | + </group> |
1807 | + </form> |
1808 | + </field> |
1809 | + </record> |
1810 | + |
1811 | + <record model="ir.actions.act_window" id="action_training_report_session_volume_form_act"> |
1812 | + <field name="name">Report Volume</field> |
1813 | + <field name="res_model">training.report.session.volume</field> |
1814 | + <field name="view_type">form</field> |
1815 | + <field name="view_mode">form</field> |
1816 | + <field name="target">new</field> |
1817 | + </record> |
1818 | + |
1819 | + <menuitem id="training_report_volume_mi" parent="menu_training_report" action="action_training_report_session_volume_form_act"/> |
1820 | + |
1821 | + </data> |
1822 | +</openerp> |