You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

295 lines
16 KiB

  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. import time
  31. from osv import fields, osv
  32. from lxml import etree
  33. from tools.translate import _
  34. from datetime import datetime
  35. def previous_year_date(date, nb_prev=1):
  36. if not date:
  37. return False
  38. parsed_date = datetime.strptime(date, '%Y-%m-%d')
  39. previous_date = datetime(year=parsed_date.year - nb_prev,
  40. month=parsed_date.month,
  41. day=parsed_date.day)
  42. return previous_date
  43. class AccountBalanceCommonWizard(osv.osv_memory):
  44. """Will launch trial balance report and pass required args"""
  45. _inherit = "account.common.account.report"
  46. _name = "account.common.balance.report"
  47. _description = "Common Balance Report"
  48. # an update module should be done if changed
  49. # in order to create fields in db
  50. COMPARISON_LEVEL = 3
  51. COMPARE_SELECTION = [('filter_no', 'No Comparison'),
  52. ('filter_year', 'Fiscal Year'),
  53. ('filter_date', 'Date'),
  54. ('filter_period', 'Periods'),
  55. ('filter_opening', 'Opening Only')]
  56. M2O_DYNAMIC_FIELDS = [f % index for f in ["comp%s_fiscalyear_id",
  57. "comp%s_period_from",
  58. "comp%s_period_to",]
  59. for index in range(COMPARISON_LEVEL)]
  60. SIMPLE_DYNAMIC_FIELDS = [f % index for f in ["comp%s_filter",
  61. "comp%s_date_from",
  62. "comp%s_date_to"]
  63. for index in range(COMPARISON_LEVEL)]
  64. DYNAMIC_FIELDS = M2O_DYNAMIC_FIELDS + SIMPLE_DYNAMIC_FIELDS
  65. def _get_account_ids(self, cr, uid, context=None):
  66. res = False
  67. if context.get('active_model', False) == 'account.account' and context.get('active_ids', False):
  68. res = context['active_ids']
  69. return res
  70. _columns = {
  71. 'account_ids': fields.many2many('account.account', string='Filter on accounts',
  72. help="Only selected accounts will be printed. Leave empty to print all accounts."),
  73. 'filter': fields.selection([('filter_no', 'No Filters'),
  74. ('filter_date', 'Date'),
  75. ('filter_period', 'Periods'),
  76. ('filter_opening', 'Opening Only')], "Filter by", required=True, help='Filter by date : no opening balance will be displayed. (opening balance can only be calculated based on period to be correct).'),
  77. }
  78. for index in range(COMPARISON_LEVEL):
  79. _columns.update(
  80. {"comp%s_filter" % (index,): fields.selection(COMPARE_SELECTION, string='Compare By', required=True),
  81. "comp%s_fiscalyear_id" % (index,): fields.many2one('account.fiscalyear', 'Fiscal Year'),
  82. "comp%s_period_from" % (index,): fields.many2one('account.period', 'Start Period'),
  83. "comp%s_period_to" % (index,): fields.many2one('account.period', 'End Period'),
  84. "comp%s_date_from" % (index,): fields.date("Start Date"),
  85. "comp%s_date_to" % (index,): fields.date("End Date"),})
  86. _defaults = {
  87. 'account_ids': _get_account_ids,
  88. }
  89. def _check_fiscalyear(self, cr, uid, ids, context=None):
  90. obj = self.read(cr, uid, ids[0], ['fiscalyear_id', 'filter'], context=context)
  91. if not obj['fiscalyear_id'] and obj['filter'] == 'filter_no':
  92. return False
  93. return True
  94. _constraints = [
  95. (_check_fiscalyear, 'When no Fiscal year is selected, you must choose to filter by periods or by date.', ['filter']),
  96. ]
  97. def default_get(self, cr, uid, fields, context=None):
  98. """
  99. To get default values for the object.
  100. @param self: The object pointer.
  101. @param cr: A database cursor
  102. @param uid: ID of the user currently logged in
  103. @param fields: List of fields for which we want default values
  104. @param context: A standard dictionary
  105. @return: A dictionary which of fields with values.
  106. """
  107. res = super(AccountBalanceCommonWizard, self).default_get(cr, uid, fields, context=context)
  108. for index in range(self.COMPARISON_LEVEL):
  109. field = "comp%s_filter" % (index,)
  110. if not res.get(field, False):
  111. res[field] = 'filter_no'
  112. return res
  113. def fields_view_get(self, cr, uid, view_id=None, view_type='form', context=None, toolbar=False, submenu=False):
  114. res = super(AccountBalanceCommonWizard, self).fields_view_get(cr, uid, view_id, view_type, context=context, toolbar=toolbar, submenu=submenu)
  115. res['fields'].update(self.fields_get(cr, uid,
  116. allfields=self.DYNAMIC_FIELDS,
  117. context=context, write_access=True))
  118. eview = etree.fromstring(res['arch'])
  119. placeholder = eview.xpath("//page[@name='placeholder']")
  120. if placeholder:
  121. placeholder = placeholder[0]
  122. for index in range(self.COMPARISON_LEVEL):
  123. page = etree.Element('page', {'name': "comp%s" % (index,), 'string': _("Comparison %s") % (index+1,)})
  124. page.append(etree.Element('field', {'name': "comp%s_filter" % (index,),
  125. 'colspan': '4',
  126. 'on_change': "onchange_comp_filter(%(index)s, filter, comp%(index)s_filter, fiscalyear_id, date_from, date_to)" % {'index': index}}))
  127. page.append(etree.Element('field', {'name': "comp%s_fiscalyear_id" % (index,),
  128. 'colspan': '4',
  129. 'attrs': "{'required': [('comp%(index)s_filter','in',('filter_year','filter_opening'))], 'readonly':[('comp%(index)s_filter','not in',('filter_year','filter_opening'))]}" % {'index': index}}))
  130. page.append(etree.Element('separator', {'string': _('Dates'), 'colspan':'4'}))
  131. page.append(etree.Element('field', {'name': "comp%s_date_from" % (index,), 'colspan':'4',
  132. 'attrs': "{'required': [('comp%(index)s_filter','=','filter_date')], 'readonly':[('comp%(index)s_filter','!=','filter_date')]}" % {'index': index}}))
  133. page.append(etree.Element('field', {'name': "comp%s_date_to" % (index,), 'colspan':'4',
  134. 'attrs': "{'required': [('comp%(index)s_filter','=','filter_date')], 'readonly':[('comp%(index)s_filter','!=','filter_date')]}" % {'index': index}}))
  135. page.append(etree.Element('separator', {'string': _('Periods'), 'colspan':'4'}))
  136. page.append(etree.Element('field', {'name': "comp%s_period_from" % (index,),
  137. 'colspan': '4',
  138. 'attrs': "{'required': [('comp%(index)s_filter','=','filter_period')], 'readonly':[('comp%(index)s_filter','!=','filter_period')]}" % {'index': index},
  139. 'domain': "[('special', '=', False)]"}))
  140. page.append(etree.Element('field', {'name': "comp%s_period_to" % (index,),
  141. 'colspan': '4',
  142. 'attrs': "{'required': [('comp%(index)s_filter','=','filter_period')], 'readonly':[('comp%(index)s_filter','!=','filter_period')]}" % {'index': index},
  143. 'domain': "[('special', '=', False)]"}))
  144. placeholder.addprevious(page)
  145. placeholder.getparent().remove(placeholder)
  146. res['arch'] = etree.tostring(eview)
  147. return res
  148. def onchange_filter(self, cr, uid, ids, filter='filter_no', fiscalyear_id=False, context=None):
  149. res = {}
  150. if filter == 'filter_no':
  151. res['value'] = {'period_from': False, 'period_to': False, 'date_from': False ,'date_to': False}
  152. if filter == 'filter_date':
  153. if fiscalyear_id:
  154. fyear = self.pool.get('account.fiscalyear').browse(cr, uid, fiscalyear_id, context=context)
  155. date_from = fyear.date_start
  156. date_to = fyear.date_stop > time.strftime('%Y-%m-%d') and time.strftime('%Y-%m-%d') or fyear.date_stop
  157. else:
  158. date_from, date_to = time.strftime('%Y-01-01'), time.strftime('%Y-%m-%d')
  159. res['value'] = {'period_from': False, 'period_to': False, 'date_from': date_from, 'date_to': date_to}
  160. if filter == 'filter_period' and fiscalyear_id:
  161. start_period = end_period = False
  162. cr.execute('''
  163. SELECT * FROM (SELECT p.id
  164. FROM account_period p
  165. LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
  166. WHERE f.id = %s
  167. AND COALESCE(p.special, FALSE) = FALSE
  168. ORDER BY p.date_start ASC
  169. LIMIT 1) AS period_start
  170. UNION ALL
  171. SELECT * FROM (SELECT p.id
  172. FROM account_period p
  173. LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
  174. WHERE f.id = %s
  175. AND p.date_start < NOW()
  176. AND COALESCE(p.special, FALSE) = FALSE
  177. ORDER BY p.date_stop DESC
  178. LIMIT 1) AS period_stop''', (fiscalyear_id, fiscalyear_id))
  179. periods = [i[0] for i in cr.fetchall()]
  180. if periods:
  181. start_period = end_period = periods[0]
  182. if len(periods) > 1:
  183. end_period = periods[1]
  184. res['value'] = {'period_from': start_period, 'period_to': end_period, 'date_from': False, 'date_to': False}
  185. return res
  186. 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):
  187. res = {}
  188. fy_obj = self.pool.get('account.fiscalyear')
  189. last_fiscalyear_id = False
  190. if fiscalyear_id:
  191. fiscalyear = fy_obj.browse(cr, uid, fiscalyear_id, context=context)
  192. last_fiscalyear_ids = fy_obj.search(cr, uid, [('date_stop', '<', fiscalyear.date_start)],
  193. limit=self.COMPARISON_LEVEL, order='date_start desc', context=context)
  194. if last_fiscalyear_ids:
  195. if len(last_fiscalyear_ids) > index:
  196. last_fiscalyear_id = last_fiscalyear_ids[index] # first element for the comparison 1, second element for the comparison 2
  197. fy_id_field = "comp%s_fiscalyear_id" % (index,)
  198. period_from_field = "comp%s_period_from" % (index,)
  199. period_to_field = "comp%s_period_to" % (index,)
  200. date_from_field = "comp%s_date_from" % (index,)
  201. date_to_field = "comp%s_date_to" % (index,)
  202. if comp_filter == 'filter_no':
  203. res['value'] = {fy_id_field: False, period_from_field: False, period_to_field: False, date_from_field: False ,date_to_field: False}
  204. if comp_filter in ('filter_year', 'filter_opening'):
  205. res['value'] = {fy_id_field: last_fiscalyear_id, period_from_field: False, period_to_field: False, date_from_field: False ,date_to_field: False}
  206. if comp_filter == 'filter_date':
  207. dates = {}
  208. if main_filter == 'filter_date':
  209. dates = {
  210. 'date_start': previous_year_date(start_date, index + 1).strftime('%Y-%m-%d'),
  211. 'date_stop': previous_year_date(stop_date, index + 1).strftime('%Y-%m-%d'),}
  212. elif last_fiscalyear_id:
  213. dates = fy_obj.read(cr, uid, last_fiscalyear_id, ['date_start', 'date_stop'], context=context)
  214. 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)}
  215. if comp_filter == 'filter_period' and last_fiscalyear_id:
  216. start_period = end_period = False
  217. cr.execute('''
  218. SELECT * FROM (SELECT p.id
  219. FROM account_period p
  220. LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
  221. WHERE f.id = %(fiscalyear)s
  222. AND COALESCE(p.special, FALSE) = FALSE
  223. ORDER BY p.date_start ASC
  224. LIMIT 1) AS period_start
  225. UNION ALL
  226. SELECT * FROM (SELECT p.id
  227. FROM account_period p
  228. LEFT JOIN account_fiscalyear f ON (p.fiscalyear_id = f.id)
  229. WHERE f.id = %(fiscalyear)s
  230. AND p.date_start < NOW()
  231. AND COALESCE(p.special, FALSE) = FALSE
  232. ORDER BY p.date_stop DESC
  233. LIMIT 1) AS period_stop''', {'fiscalyear': last_fiscalyear_id})
  234. periods = [i[0] for i in cr.fetchall()]
  235. if periods and len(periods) > 1:
  236. start_period = end_period = periods[0]
  237. if len(periods) > 1:
  238. end_period = periods[1]
  239. res['value'] = {fy_id_field: False,
  240. period_from_field: start_period,
  241. period_to_field: end_period,
  242. date_from_field: False,
  243. date_to_field: False}
  244. return res
  245. def pre_print_report(self, cr, uid, ids, data, context=None):
  246. data = super(AccountBalanceCommonWizard, self).pre_print_report(
  247. cr, uid, ids, data, context)
  248. if context is None:
  249. context = {}
  250. # will be used to attach the report on the main account
  251. data['ids'] = [data['form']['chart_account_id']]
  252. fields_to_read = ['account_ids',]
  253. fields_to_read += self.DYNAMIC_FIELDS
  254. vals = self.read(cr, uid, ids, fields_to_read, context=context)[0]
  255. # extract the id from the m2o tuple (id, name)
  256. for field in self.M2O_DYNAMIC_FIELDS:
  257. if isinstance(vals[field], tuple):
  258. vals[field] = vals[field][0]
  259. vals['max_comparison'] = self.COMPARISON_LEVEL
  260. data['form'].update(vals)
  261. return data
  262. AccountBalanceCommonWizard()