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.

409 lines
18 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 lxml import etree
  32. from datetime import datetime
  33. from openerp.osv import fields, orm
  34. from openerp.tools.translate import _
  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(orm.TransientModel):
  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' \
  68. and context.get('active_ids', False):
  69. res = context['active_ids']
  70. return res
  71. _columns = {
  72. 'account_ids': fields.many2many(
  73. 'account.account', string='Filter on accounts',
  74. help="Only selected accounts will be printed. Leave empty to \
  75. print all accounts."),
  76. 'filter': fields.selection(
  77. [('filter_no', 'No Filters'),
  78. ('filter_date', 'Date'),
  79. ('filter_period', 'Periods'),
  80. ('filter_opening', 'Opening Only')],
  81. "Filter by",
  82. required=True,
  83. help='Filter by date: no opening balance will be displayed. '
  84. '(opening balance can only be computed based on period to be \
  85. correct).'),
  86. }
  87. for index in range(COMPARISON_LEVEL):
  88. _columns.update(
  89. {"comp%s_filter" % index:
  90. fields.selection(
  91. COMPARE_SELECTION, string='Compare By', required=True),
  92. "comp%s_fiscalyear_id" % index:
  93. fields.many2one('account.fiscalyear', 'Fiscal Year'),
  94. "comp%s_period_from" % index:
  95. fields.many2one('account.period', 'Start Period'),
  96. "comp%s_period_to" % index:
  97. fields.many2one('account.period', 'End Period'),
  98. "comp%s_date_from" % index:
  99. fields.date("Start Date"),
  100. "comp%s_date_to" % index:
  101. fields.date("End Date")})
  102. _defaults = {
  103. 'account_ids': _get_account_ids,
  104. }
  105. def _check_fiscalyear(self, cr, uid, ids, context=None):
  106. obj = self.read(
  107. cr, uid, ids[0], ['fiscalyear_id', 'filter'], context=context)
  108. if not obj['fiscalyear_id'] and obj['filter'] == 'filter_no':
  109. return False
  110. return True
  111. _constraints = [
  112. (_check_fiscalyear,
  113. 'When no Fiscal year is selected, you must choose to filter by \
  114. periods or by date.', ['filter']),
  115. ]
  116. def default_get(self, cr, uid, fields_list, context=None):
  117. """
  118. To get default values for the object.
  119. @param self: The object pointer.
  120. @param cr: A database cursor
  121. @param uid: ID of the user currently logged in
  122. @param fields: List of fields for which we want default values
  123. @param context: A standard dictionary
  124. @return: A dictionary which of fields with values.
  125. """
  126. res = super(AccountBalanceCommonWizard, self).default_get(
  127. cr, uid, fields_list, context=context)
  128. for index in range(self.COMPARISON_LEVEL):
  129. field = "comp%s_filter" % (index,)
  130. if not res.get(field, False):
  131. res[field] = 'filter_no'
  132. return res
  133. def fields_view_get(self, cr, uid, view_id=None, view_type='form',
  134. context=None, toolbar=False, submenu=False):
  135. res = super(AccountBalanceCommonWizard, self).fields_view_get(
  136. cr, uid, view_id, view_type, context=context, toolbar=toolbar,
  137. submenu=submenu)
  138. res['fields'].update(self.fields_get(cr, uid,
  139. allfields=self.DYNAMIC_FIELDS,
  140. context=context,
  141. write_access=True))
  142. eview = etree.fromstring(res['arch'])
  143. placeholder = eview.xpath("//page[@name='placeholder']")
  144. if placeholder:
  145. placeholder = placeholder[0]
  146. for index in range(self.COMPARISON_LEVEL):
  147. page = etree.Element(
  148. 'page',
  149. {'name': "comp%s" % index,
  150. 'string': _("Comparison %s") % (index + 1, )})
  151. group = etree.Element('group')
  152. page.append(group)
  153. def modifiers_and_append(elem):
  154. orm.setup_modifiers(elem)
  155. group.append(elem)
  156. modifiers_and_append(etree.Element(
  157. 'field',
  158. {'name': "comp%s_filter" % index,
  159. 'on_change': "onchange_comp_filter(%(index)s, filter,\
  160. comp%(index)s_filter, fiscalyear_id, date_from, date_to)"
  161. % {'index': index}}))
  162. modifiers_and_append(etree.Element(
  163. 'field',
  164. {'name': "comp%s_fiscalyear_id" % index,
  165. 'attrs':
  166. "{'required': [('comp%(index)s_filter','in',\
  167. ('filter_year','filter_opening'))],"
  168. " 'invisible': [('comp%(index)s_filter','not in',\
  169. ('filter_year','filter_opening'))]}" % {'index': index}}))
  170. dates_attrs = "{'required': [('comp%(index)s_filter','=',\
  171. 'filter_date')], " \
  172. " 'invisible': [('comp%(index)s_filter','!=',\
  173. 'filter_date')]}" % {
  174. 'index': index}
  175. modifiers_and_append(etree.Element(
  176. 'separator',
  177. {'string': _('Dates'),
  178. 'colspan': '4',
  179. 'attrs': dates_attrs}))
  180. modifiers_and_append(etree.Element(
  181. 'field',
  182. {'name': "comp%s_date_from" % index,
  183. 'attrs': dates_attrs}))
  184. modifiers_and_append(etree.Element(
  185. 'field',
  186. {'name': "comp%s_date_to" % index,
  187. 'attrs': dates_attrs}))
  188. periods_attrs = "{'required': [('comp%(index)s_filter','=',\
  189. 'filter_period')]," \
  190. " 'invisible': [('comp%(index)s_filter','!=',\
  191. 'filter_period')]}" % {
  192. 'index': index}
  193. periods_domain = "[('special', '=', False)]"
  194. modifiers_and_append(etree.Element(
  195. 'separator',
  196. {'string': _('Periods'),
  197. 'colspan': '4',
  198. 'attrs': periods_attrs}))
  199. modifiers_and_append(etree.Element(
  200. 'field',
  201. {'name': "comp%s_period_from" % index,
  202. 'attrs': periods_attrs,
  203. 'domain': periods_domain}))
  204. modifiers_and_append(etree.Element(
  205. 'field',
  206. {'name': "comp%s_period_to" % index,
  207. 'attrs': periods_attrs,
  208. 'domain': periods_domain}))
  209. placeholder.addprevious(page)
  210. placeholder.getparent().remove(placeholder)
  211. res['arch'] = etree.tostring(eview)
  212. return res
  213. def onchange_filter(self, cr, uid, ids, filter='filter_no',
  214. fiscalyear_id=False, context=None):
  215. res = {}
  216. if filter == 'filter_no':
  217. res['value'] = {'period_from': False,
  218. 'period_to': False,
  219. 'date_from': False,
  220. 'date_to': False}
  221. if filter == 'filter_date':
  222. if fiscalyear_id:
  223. fyear = self.pool.get('account.fiscalyear').browse(
  224. cr, uid, fiscalyear_id, context=context)
  225. date_from = fyear.date_start
  226. date_to = fyear.date_stop > time.strftime(
  227. '%Y-%m-%d') and time.strftime('%Y-%m-%d') \
  228. or fyear.date_stop
  229. else:
  230. date_from, date_to = time.strftime(
  231. '%Y-01-01'), time.strftime('%Y-%m-%d')
  232. res['value'] = {'period_from': False, 'period_to':
  233. False, 'date_from': date_from, 'date_to': date_to}
  234. if filter == 'filter_period' and fiscalyear_id:
  235. start_period = end_period = False
  236. cr.execute('''
  237. SELECT * FROM (SELECT p.id
  238. FROM account_period p
  239. LEFT JOIN account_fiscalyear f
  240. ON (p.fiscalyear_id = f.id)
  241. WHERE f.id = %s
  242. AND COALESCE(p.special, FALSE) = FALSE
  243. ORDER BY p.date_start ASC
  244. LIMIT 1) AS period_start
  245. UNION ALL
  246. SELECT * FROM (SELECT p.id
  247. FROM account_period p
  248. LEFT JOIN account_fiscalyear f
  249. ON (p.fiscalyear_id = f.id)
  250. WHERE f.id = %s
  251. AND p.date_start < NOW()
  252. AND COALESCE(p.special, FALSE) = FALSE
  253. ORDER BY p.date_stop DESC
  254. LIMIT 1) AS period_stop''',
  255. (fiscalyear_id, fiscalyear_id))
  256. periods = [i[0] for i in cr.fetchall()]
  257. if periods:
  258. start_period = end_period = periods[0]
  259. if len(periods) > 1:
  260. end_period = periods[1]
  261. res['value'] = {'period_from': start_period, 'period_to':
  262. end_period, 'date_from': False, 'date_to': False}
  263. return res
  264. def onchange_comp_filter(self, cr, uid, ids, index,
  265. main_filter='filter_no', comp_filter='filter_no',
  266. fiscalyear_id=False, start_date=False,
  267. stop_date=False, context=None):
  268. res = {}
  269. fy_obj = self.pool.get('account.fiscalyear')
  270. last_fiscalyear_id = False
  271. if fiscalyear_id:
  272. fiscalyear = fy_obj.browse(cr, uid, fiscalyear_id, context=context)
  273. last_fiscalyear_ids = fy_obj.search(
  274. cr, uid, [('date_stop', '<', fiscalyear.date_start)],
  275. limit=self.COMPARISON_LEVEL, order='date_start desc',
  276. context=context)
  277. if last_fiscalyear_ids:
  278. if len(last_fiscalyear_ids) > index:
  279. # first element for the comparison 1, second element for
  280. # the comparison 2
  281. last_fiscalyear_id = last_fiscalyear_ids[index]
  282. fy_id_field = "comp%s_fiscalyear_id" % (index,)
  283. period_from_field = "comp%s_period_from" % (index,)
  284. period_to_field = "comp%s_period_to" % (index,)
  285. date_from_field = "comp%s_date_from" % (index,)
  286. date_to_field = "comp%s_date_to" % (index,)
  287. if comp_filter == 'filter_no':
  288. res['value'] = {
  289. fy_id_field: False,
  290. period_from_field: False,
  291. period_to_field: False,
  292. date_from_field: False,
  293. date_to_field: False
  294. }
  295. if comp_filter in ('filter_year', 'filter_opening'):
  296. res['value'] = {
  297. fy_id_field: last_fiscalyear_id,
  298. period_from_field: False,
  299. period_to_field: False,
  300. date_from_field: False,
  301. date_to_field: False
  302. }
  303. if comp_filter == 'filter_date':
  304. dates = {}
  305. if main_filter == 'filter_date':
  306. dates = {
  307. 'date_start': previous_year_date(start_date, index + 1).
  308. strftime('%Y-%m-%d'),
  309. 'date_stop': previous_year_date(stop_date, index + 1).
  310. strftime('%Y-%m-%d'),
  311. }
  312. elif last_fiscalyear_id:
  313. dates = fy_obj.read(
  314. cr, uid, last_fiscalyear_id, ['date_start', 'date_stop'],
  315. context=context)
  316. res['value'] = {fy_id_field: False,
  317. period_from_field: False,
  318. period_to_field: False,
  319. date_from_field: dates.get('date_start', False),
  320. date_to_field: dates.get('date_stop', False)}
  321. if comp_filter == 'filter_period' and last_fiscalyear_id:
  322. start_period = end_period = False
  323. cr.execute('''
  324. SELECT * FROM (SELECT p.id
  325. FROM account_period p
  326. LEFT JOIN account_fiscalyear f
  327. ON (p.fiscalyear_id = f.id)
  328. WHERE f.id = %(fiscalyear)s
  329. AND COALESCE(p.special, FALSE) = FALSE
  330. ORDER BY p.date_start ASC
  331. LIMIT 1) AS period_start
  332. UNION ALL
  333. SELECT * FROM (SELECT p.id
  334. FROM account_period p
  335. LEFT JOIN account_fiscalyear f
  336. ON (p.fiscalyear_id = f.id)
  337. WHERE f.id = %(fiscalyear)s
  338. AND p.date_start < NOW()
  339. AND COALESCE(p.special, FALSE) = FALSE
  340. ORDER BY p.date_stop DESC
  341. LIMIT 1) AS period_stop''',
  342. {'fiscalyear': last_fiscalyear_id})
  343. periods = [i[0] for i in cr.fetchall()]
  344. if periods and len(periods) > 1:
  345. start_period = end_period = periods[0]
  346. if len(periods) > 1:
  347. end_period = periods[1]
  348. res['value'] = {fy_id_field: False,
  349. period_from_field: start_period,
  350. period_to_field: end_period,
  351. date_from_field: False,
  352. date_to_field: False}
  353. return res
  354. def pre_print_report(self, cr, uid, ids, data, context=None):
  355. data = super(AccountBalanceCommonWizard, self).pre_print_report(
  356. cr, uid, ids, data, context)
  357. if context is None:
  358. context = {}
  359. # will be used to attach the report on the main account
  360. data['ids'] = [data['form']['chart_account_id']]
  361. fields_to_read = ['account_ids', ]
  362. fields_to_read += self.DYNAMIC_FIELDS
  363. vals = self.read(cr, uid, ids, fields_to_read, context=context)[0]
  364. # extract the id from the m2o tuple (id, name)
  365. for field in self.M2O_DYNAMIC_FIELDS:
  366. if isinstance(vals[field], tuple):
  367. vals[field] = vals[field][0]
  368. vals['max_comparison'] = self.COMPARISON_LEVEL
  369. data['form'].update(vals)
  370. return data