[MODULE] +v1.1.0 from https://www.odoo.com/apps/7.0/account_financial_report_webkit/
[burette/account_financial_report_webkit.git] / wizard / balance_common.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 # Copyright (c) 2011 Camptocamp SA (http://www.camptocamp.com)
5 #
6 # Author: Guewen Baconnier (Camptocamp)
7 #
8 # WARNING: This program as such is intended to be used by professional
9 # programmers who take the whole responsability of assessing all potential
10 # consequences resulting from its eventual inadequacies and bugs
11 # End users who are looking for a ready-to-use solution with commercial
12 # garantees and support are strongly adviced to contract a Free Software
13 # Service Company
14 #
15 # This program is Free Software; you can redistribute it and/or
16 # modify it under the terms of the GNU General Public License
17 # as published by the Free Software Foundation; either version 2
18 # of the License, or (at your option) any later version.
19 #
20 # This program is distributed in the hope that it will be useful,
21 # but WITHOUT ANY WARRANTY; without even the implied warranty of
22 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 # GNU General Public License for more details.
24 #
25 # You should have received a copy of the GNU General Public License
26 # along with this program; if not, write to the Free Software
27 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #
29 ##############################################################################
30
31 import time
32
33 from lxml import etree
34 from datetime import datetime
35 from openerp.osv import fields, orm
36 from openerp.tools.translate import _
37
38
39 def previous_year_date(date, nb_prev=1):
40 if not date:
41 return False
42 parsed_date = datetime.strptime(date, '%Y-%m-%d')
43 previous_date = datetime(year=parsed_date.year - nb_prev,
44 month=parsed_date.month,
45 day=parsed_date.day)
46 return previous_date
47
48
49 class AccountBalanceCommonWizard(orm.TransientModel):
50 """Will launch trial balance report and pass required args"""
51
52 _inherit = "account.common.account.report"
53 _name = "account.common.balance.report"
54 _description = "Common Balance Report"
55
56 # an update module should be done if changed
57 # in order to create fields in db
58 COMPARISON_LEVEL = 3
59
60 COMPARE_SELECTION = [('filter_no', 'No Comparison'),
61 ('filter_year', 'Fiscal Year'),
62 ('filter_date', 'Date'),
63 ('filter_period', 'Periods'),
64 ('filter_opening', 'Opening Only')]
65
66 M2O_DYNAMIC_FIELDS = [f % index for f in ["comp%s_fiscalyear_id",
67 "comp%s_period_from",
68 "comp%s_period_to"]
69 for index in range(COMPARISON_LEVEL)]
70 SIMPLE_DYNAMIC_FIELDS = [f % index for f in ["comp%s_filter",
71 "comp%s_date_from",
72 "comp%s_date_to"]
73 for index in range(COMPARISON_LEVEL)]
74 DYNAMIC_FIELDS = M2O_DYNAMIC_FIELDS + SIMPLE_DYNAMIC_FIELDS
75
76 def _get_account_ids(self, cr, uid, context=None):
77 res = False
78 if context.get('active_model', False) == 'account.account' and context.get('active_ids', False):
79 res = context['active_ids']
80 return res
81
82 _columns = {
83 'account_ids': fields.many2many('account.account', string='Filter on accounts',
84 help="Only selected accounts will be printed. Leave empty to print all accounts."),
85 'filter': fields.selection([('filter_no', 'No Filters'),
86 ('filter_date', 'Date'),
87 ('filter_period', 'Periods'),
88 ('filter_opening', 'Opening Only')],
89 "Filter by",
90 required=True,
91 help='Filter by date: no opening balance will be displayed. '
92 '(opening balance can only be computed based on period to be correct).'),
93 }
94
95 for index in range(COMPARISON_LEVEL):
96 _columns.update(
97 {"comp%s_filter" % index: fields.selection(COMPARE_SELECTION, string='Compare By', required=True),
98 "comp%s_fiscalyear_id" % index: fields.many2one('account.fiscalyear', 'Fiscal Year'),
99 "comp%s_period_from" % index: fields.many2one('account.period', 'Start Period'),
100 "comp%s_period_to" % index: fields.many2one('account.period', 'End Period'),
101 "comp%s_date_from" % index: fields.date("Start Date"),
102 "comp%s_date_to" % index: fields.date("End Date")})
103
104 _defaults = {
105 'account_ids': _get_account_ids,
106 }
107
108 def _check_fiscalyear(self, cr, uid, ids, context=None):
109 obj = self.read(cr, uid, ids[0], ['fiscalyear_id', 'filter'], context=context)
110 if not obj['fiscalyear_id'] and obj['filter'] == 'filter_no':
111 return False
112 return True
113
114 _constraints = [
115 (_check_fiscalyear, 'When no Fiscal year is selected, you must choose to filter by periods or by date.', ['filter']),
116 ]
117
118 def default_get(self, cr, uid, fields, context=None):
119 """
120 To get default values for the object.
121
122 @param self: The object pointer.
123 @param cr: A database cursor
124 @param uid: ID of the user currently logged in
125 @param fields: List of fields for which we want default values
126 @param context: A standard dictionary
127
128 @return: A dictionary which of fields with values.
129
130 """
131 res = super(AccountBalanceCommonWizard, self).default_get(cr, uid, fields, context=context)
132 for index in range(self.COMPARISON_LEVEL):
133 field = "comp%s_filter" % (index,)
134 if not res.get(field, False):
135 res[field] = 'filter_no'
136 return res
137
138 def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
139 res = super(AccountBalanceCommonWizard, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
140
141 res['fields'].update(self.fields_get(cr, uid,
142 allfields=self.DYNAMIC_FIELDS,
143 context=context, write_access=True))
144
145 eview = etree.fromstring(res['arch'])
146 placeholder = eview.xpath("//page[@name='placeholder']")
147 if placeholder:
148 placeholder = placeholder[0]
149 for index in range(self.COMPARISON_LEVEL):
150 page = etree.Element(
151 'page',
152 {'name': "comp%s" % index,
153 'string': _("Comparison %s") % (index + 1, )})
154 group = etree.Element('group')
155 page.append(group)
156
157 def modifiers_and_append(elem):
158 orm.setup_modifiers(elem)
159 group.append(elem)
160
161 modifiers_and_append(etree.Element(
162 'field',
163 {'name': "comp%s_filter" % index,
164 'on_change': "onchange_comp_filter(%(index)s, filter, comp%(index)s_filter, fiscalyear_id, date_from, date_to)" % {'index': index}}))
165 modifiers_and_append(etree.Element(
166 'field',
167 {'name': "comp%s_fiscalyear_id" % index,
168 'attrs':
169 "{'required': [('comp%(index)s_filter','in',('filter_year','filter_opening'))]," \
170 " 'invisible': [('comp%(index)s_filter','not in',('filter_year','filter_opening'))]}" % {'index': index}}))
171
172 dates_attrs = "{'required': [('comp%(index)s_filter','=','filter_date')], " \
173 " 'invisible': [('comp%(index)s_filter','!=','filter_date')]}" % {'index': index}
174 modifiers_and_append(etree.Element(
175 'separator',
176 {'string': _('Dates'),
177 'colspan': '4',
178 'attrs': dates_attrs}))
179 modifiers_and_append(etree.Element(
180 'field',
181 {'name': "comp%s_date_from" % index,
182 'attrs': dates_attrs}))
183 modifiers_and_append(etree.Element(
184 'field',
185 {'name': "comp%s_date_to" % index,
186 'attrs': dates_attrs}))
187
188 periods_attrs = "{'required': [('comp%(index)s_filter','=','filter_period')]," \
189 " 'invisible': [('comp%(index)s_filter','!=','filter_period')]}" % {'index': index}
190 periods_domain = "[('special', '=', False)]"
191 modifiers_and_append(etree.Element(
192 'separator',
193 {'string': _('Periods'),
194 'colspan': '4',
195 'attrs': periods_attrs}))
196 modifiers_and_append(etree.Element(
197 'field',
198 {'name': "comp%s_period_from" % index,
199 'attrs': periods_attrs,
200 'domain': periods_domain}))
201 modifiers_and_append(etree.Element(
202 'field',
203 {'name': "comp%s_period_to" % index,
204 'attrs': periods_attrs,
205 'domain': periods_domain}))
206
207 placeholder.addprevious(page)
208 placeholder.getparent().remove(placeholder)
209 res['arch'] = etree.tostring(eview)
210 return res
211
212 def onchange_filter(self, cr, uid, ids, filter='filter_no', fiscalyear_id=False, context=None):
213 res = {}
214 if filter == 'filter_no':
215 res['value'] = {'period_from': False, 'period_to': False, 'date_from': False, 'date_to': False}
216 if filter == 'filter_date':
217 if fiscalyear_id:
218 fyear = self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_id, context=context)
219 date_from = fyear.date_start
220 date_to = fyear.date_stop > time.strftime('%Y-%m-%d') and time.strftime('%Y-%m-%d') or fyear.date_stop
221 else:
222 date_from, date_to = time.strftime('%Y-01-01'), time.strftime('%Y-%m-%d')
223 res['value'] = {'period_from': False, 'period_to': False, 'date_from': date_from, 'date_to': date_to}
224 if filter == 'filter_period' and fiscalyear_id:
225 start_period = end_period = False
226 cr.execute('''
227 SELECT * FROM (SELECT p.id
228 FROM account_period p
229 LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
230 WHERE f.id = %s
231 AND COALESCE(p.special, FALSE) = FALSE
232 ORDER BY p.date_start ASC
233 LIMIT 1) AS period_start
234 UNION ALL
235 SELECT * FROM (SELECT p.id
236 FROM account_period p
237 LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
238 WHERE f.id = %s
239 AND p.date_start < NOW()
240 AND COALESCE(p.special, FALSE) = FALSE
241 ORDER BY p.date_stop DESC
242 LIMIT 1) AS period_stop''', (fiscalyear_id, fiscalyear_id))
243 periods = [i[0] for i in cr.fetchall()]
244 if periods:
245 start_period = end_period = periods[0]
246 if len(periods) > 1:
247 end_period = periods[1]
248 res['value'] = {'period_from': start_period, 'period_to': end_period, 'date_from': False, 'date_to': False}
249 return res
250
251 def onchange_comp_filter(self, cr, uid, ids, index, main_filter='filter_no', comp_filter='filter_no', fiscalyear_id=False, start_date=False, stop_date=False, context=None):
252 res = {}
253 fy_obj = self.pool.get('account.fiscalyear')
254 last_fiscalyear_id = False
255 if fiscalyear_id:
256 fiscalyear = fy_obj.browse(cr, uid, fiscalyear_id, context=context)
257 last_fiscalyear_ids = fy_obj.search(cr, uid, [('date_stop', '<', fiscalyear.date_start)],
258 limit=self.COMPARISON_LEVEL, order='date_start desc', context=context)
259 if last_fiscalyear_ids:
260 if len(last_fiscalyear_ids) > index:
261 last_fiscalyear_id = last_fiscalyear_ids[index] # first element for the comparison 1, second element for the comparison 2
262
263 fy_id_field = "comp%s_fiscalyear_id" % (index,)
264 period_from_field = "comp%s_period_from" % (index,)
265 period_to_field = "comp%s_period_to" % (index,)
266 date_from_field = "comp%s_date_from" % (index,)
267 date_to_field = "comp%s_date_to" % (index,)
268
269 if comp_filter == 'filter_no':
270 res['value'] = {
271 fy_id_field: False,
272 period_from_field: False,
273 period_to_field: False,
274 date_from_field: False,
275 date_to_field: False
276 }
277 if comp_filter in ('filter_year', 'filter_opening'):
278 res['value'] = {
279 fy_id_field: last_fiscalyear_id,
280 period_from_field: False,
281 period_to_field: False,
282 date_from_field: False,
283 date_to_field: False
284 }
285 if comp_filter == 'filter_date':
286 dates = {}
287 if main_filter == 'filter_date':
288 dates = {
289 'date_start': previous_year_date(start_date, index + 1).strftime('%Y-%m-%d'),
290 'date_stop': previous_year_date(stop_date, index + 1).strftime('%Y-%m-%d'),
291 }
292 elif last_fiscalyear_id:
293 dates = fy_obj.read(cr, uid, last_fiscalyear_id, ['date_start', 'date_stop'], context=context)
294
295 res['value'] = {fy_id_field: False, period_from_field: False, period_to_field: False, date_from_field: dates.get('date_start', False), date_to_field: dates.get('date_stop', False)}
296 if comp_filter == 'filter_period' and last_fiscalyear_id:
297 start_period = end_period = False
298 cr.execute('''
299 SELECT * FROM (SELECT p.id
300 FROM account_period p
301 LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
302 WHERE f.id = %(fiscalyear)s
303 AND COALESCE(p.special, FALSE) = FALSE
304 ORDER BY p.date_start ASC
305 LIMIT 1) AS period_start
306 UNION ALL
307 SELECT * FROM (SELECT p.id
308 FROM account_period p
309 LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
310 WHERE f.id = %(fiscalyear)s
311 AND p.date_start < NOW()
312 AND COALESCE(p.special, FALSE) = FALSE
313 ORDER BY p.date_stop DESC
314 LIMIT 1) AS period_stop''', {'fiscalyear': last_fiscalyear_id})
315 periods = [i[0] for i in cr.fetchall()]
316 if periods and len(periods) > 1:
317 start_period = end_period = periods[0]
318 if len(periods) > 1:
319 end_period = periods[1]
320 res['value'] = {fy_id_field: False,
321 period_from_field: start_period,
322 period_to_field: end_period,
323 date_from_field: False,
324 date_to_field: False}
325 return res
326
327 def pre_print_report(self, cr, uid, ids, data, context=None):
328 data = super(AccountBalanceCommonWizard, self).pre_print_report(
329 cr, uid, ids, data, context)
330 if context is None:
331 context = {}
332
333 # will be used to attach the report on the main account
334 data['ids'] = [data['form']['chart_account_id']]
335
336 fields_to_read = ['account_ids', ]
337 fields_to_read += self.DYNAMIC_FIELDS
338 vals = self.read(cr, uid, ids, fields_to_read, context=context)[0]
339
340 # extract the id from the m2o tuple (id, name)
341 for field in self.M2O_DYNAMIC_FIELDS:
342 if isinstance(vals[field], tuple):
343 vals[field] = vals[field][0]
344
345 vals['max_comparison'] = self.COMPARISON_LEVEL
346 data['form'].update(vals)
347 return data