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.

308 lines
12 KiB

  1. # Author: Damien Crier
  2. # Author: Julien Coux
  3. # Author: Jordi Ballester
  4. # Copyright 2016 Camptocamp SA
  5. # Copyright 2017 Akretion - Alexis de Lattre
  6. # Copyright 2017 Eficent Business and IT Consulting Services, S.L.
  7. # Copyright 2020 Druidoo
  8. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  9. from odoo import api, fields, models, _
  10. from odoo.exceptions import ValidationError
  11. import time
  12. class GeneralLedgerReportWizard(models.TransientModel):
  13. """General ledger report wizard."""
  14. _name = "general.ledger.report.wizard"
  15. _description = "General Ledger Report Wizard"
  16. _inherit = 'account_financial_report_abstract_wizard'
  17. company_id = fields.Many2one(
  18. comodel_name='res.company',
  19. default=lambda self: self.env.user.company_id,
  20. required=False,
  21. string='Company'
  22. )
  23. date_range_id = fields.Many2one(
  24. comodel_name='date.range',
  25. string='Date range'
  26. )
  27. date_from = fields.Date(required=True,
  28. default=lambda self: self._init_date_from())
  29. date_to = fields.Date(required=True,
  30. default=fields.Date.context_today)
  31. fy_start_date = fields.Date(compute='_compute_fy_start_date')
  32. target_move = fields.Selection([('posted', 'All Posted Entries'),
  33. ('all', 'All Entries')],
  34. string='Target Moves',
  35. required=True,
  36. default='posted')
  37. account_ids = fields.Many2many(
  38. comodel_name='account.account',
  39. string='Filter accounts',
  40. )
  41. centralize = fields.Boolean(string='Activate centralization',
  42. default=True)
  43. hide_account_at_0 = fields.Boolean(
  44. string='Hide account ending balance at 0',
  45. help='Use this filter to hide an account or a partner '
  46. 'with an ending balance at 0. '
  47. 'If partners are filtered, '
  48. 'debits and credits totals will not match the trial balance.'
  49. )
  50. show_analytic_tags = fields.Boolean(
  51. string='Show analytic tags',
  52. )
  53. account_type_ids = fields.Many2many(
  54. 'account.account.type',
  55. string='Account Types',
  56. )
  57. partner_ids = fields.Many2many(
  58. comodel_name='res.partner',
  59. string='Filter partners',
  60. default=lambda self: self._default_partners(),
  61. )
  62. analytic_tag_ids = fields.Many2many(
  63. comodel_name='account.analytic.tag',
  64. string='Filter analytic tags',
  65. )
  66. account_journal_ids = fields.Many2many(
  67. comodel_name='account.journal',
  68. string='Filter journals',
  69. )
  70. cost_center_ids = fields.Many2many(
  71. comodel_name='account.analytic.account',
  72. string='Filter cost centers',
  73. )
  74. not_only_one_unaffected_earnings_account = fields.Boolean(
  75. readonly=True,
  76. string='Not only one unaffected earnings account'
  77. )
  78. foreign_currency = fields.Boolean(
  79. string='Show foreign currency',
  80. help='Display foreign currency for move lines, unless '
  81. 'account currency is not setup through chart of accounts '
  82. 'will display initial and final balance in that currency.',
  83. default=lambda self: self._default_foreign_currency(),
  84. )
  85. account_code_from = fields.Many2one(
  86. comodel_name='account.account',
  87. string='Account Code From',
  88. help='Starting account in a range')
  89. account_code_to = fields.Many2one(
  90. comodel_name='account.account',
  91. string='Account Code To',
  92. help='Ending account in a range')
  93. show_partner_details = fields.Boolean(
  94. string='Show Partner Details',
  95. default=True,
  96. )
  97. @api.onchange('account_code_from', 'account_code_to')
  98. def on_change_account_range(self):
  99. if self.account_code_from and self.account_code_from.code.isdigit() and \
  100. self.account_code_to and self.account_code_to.code.isdigit():
  101. start_range = int(self.account_code_from.code)
  102. end_range = int(self.account_code_to.code)
  103. self.account_ids = self.env['account.account'].search(
  104. [('code', 'in', [
  105. x for x in range(start_range, end_range + 1)])])
  106. if self.company_id:
  107. self.account_ids = self.account_ids.filtered(
  108. lambda a: a.company_id == self.company_id)
  109. def _init_date_from(self):
  110. """set start date to begin of current year if fiscal year running"""
  111. today = fields.Date.context_today(self)
  112. cur_month = fields.Date.from_string(today).month
  113. cur_day = fields.Date.from_string(today).day
  114. last_fsc_month = self.env.user.company_id.fiscalyear_last_month
  115. last_fsc_day = self.env.user.company_id.fiscalyear_last_day
  116. if cur_month < last_fsc_month \
  117. or cur_month == last_fsc_month and cur_day <= last_fsc_day:
  118. return time.strftime('%Y-01-01')
  119. def _default_foreign_currency(self):
  120. return self.env.user.has_group('base.group_multi_currency')
  121. @api.depends('date_from')
  122. def _compute_fy_start_date(self):
  123. for wiz in self.filtered('date_from'):
  124. date = fields.Datetime.from_string(wiz.date_from)
  125. res = self.company_id.compute_fiscalyear_dates(date)
  126. wiz.fy_start_date = fields.Date.to_string(res['date_from'])
  127. @api.onchange('company_id')
  128. def onchange_company_id(self):
  129. """Handle company change."""
  130. account_type = self.env.ref('account.data_unaffected_earnings')
  131. count = self.env['account.account'].search_count(
  132. [
  133. ('user_type_id', '=', account_type.id),
  134. ('company_id', '=', self.company_id.id)
  135. ])
  136. self.not_only_one_unaffected_earnings_account = count != 1
  137. if self.company_id and self.date_range_id.company_id and \
  138. self.date_range_id.company_id != self.company_id:
  139. self.date_range_id = False
  140. if self.company_id and self.account_journal_ids:
  141. self.account_journal_ids = self.account_journal_ids.filtered(
  142. lambda p: p.company_id == self.company_id or
  143. not p.company_id)
  144. if self.company_id and self.partner_ids:
  145. self.partner_ids = self.partner_ids.filtered(
  146. lambda p: p.company_id == self.company_id or
  147. not p.company_id)
  148. if self.company_id and self.account_ids:
  149. if self.account_type_ids:
  150. self._onchange_account_type_ids()
  151. else:
  152. self.account_ids = self.account_ids.filtered(
  153. lambda a: a.company_id == self.company_id)
  154. if self.company_id and self.cost_center_ids:
  155. self.cost_center_ids = self.cost_center_ids.filtered(
  156. lambda c: c.company_id == self.company_id)
  157. res = {'domain': {'account_ids': [],
  158. 'partner_ids': [],
  159. 'account_journal_ids': [],
  160. 'cost_center_ids': [],
  161. 'date_range_id': []
  162. }
  163. }
  164. if not self.company_id:
  165. return res
  166. else:
  167. res['domain']['account_ids'] += [
  168. ('company_id', '=', self.company_id.id)]
  169. res['domain']['account_journal_ids'] += [
  170. ('company_id', '=', self.company_id.id)]
  171. res['domain']['partner_ids'] += self._get_partner_ids_domain()
  172. res['domain']['cost_center_ids'] += [
  173. ('company_id', '=', self.company_id.id)]
  174. res['domain']['date_range_id'] += [
  175. '|', ('company_id', '=', self.company_id.id),
  176. ('company_id', '=', False)]
  177. return res
  178. @api.onchange('date_range_id')
  179. def onchange_date_range_id(self):
  180. """Handle date range change."""
  181. if self.date_range_id:
  182. self.date_from = self.date_range_id.date_start
  183. self.date_to = self.date_range_id.date_end
  184. @api.multi
  185. @api.constrains('company_id', 'date_range_id')
  186. def _check_company_id_date_range_id(self):
  187. for rec in self.sudo():
  188. if rec.company_id and rec.date_range_id.company_id and\
  189. rec.company_id != rec.date_range_id.company_id:
  190. raise ValidationError(
  191. _('The Company in the General Ledger Report Wizard and in '
  192. 'Date Range must be the same.'))
  193. @api.onchange('account_type_ids')
  194. def _onchange_account_type_ids(self):
  195. if self.account_type_ids:
  196. self.account_ids = self.env['account.account'].search([
  197. ('company_id', '=', self.company_id.id),
  198. ('user_type_id', 'in', self.account_type_ids.ids)])
  199. else:
  200. self.account_ids = None
  201. @api.onchange('partner_ids')
  202. def onchange_partner_ids(self):
  203. """Handle partners change."""
  204. if self.partner_ids:
  205. self.account_type_ids = self.env['account.account.type'].search([
  206. ('type', 'in', ['receivable', 'payable'])])
  207. else:
  208. self.account_type_ids = None
  209. # Somehow this is required to force onchange on _default_partners()
  210. self._onchange_account_type_ids()
  211. @api.multi
  212. @api.depends('company_id')
  213. def _compute_unaffected_earnings_account(self):
  214. account_type = self.env.ref('account.data_unaffected_earnings')
  215. for record in self:
  216. record.unaffected_earnings_account = self.env[
  217. 'account.account'].search(
  218. [
  219. ('user_type_id', '=', account_type.id),
  220. ('company_id', '=', record.company_id.id)
  221. ])
  222. unaffected_earnings_account = fields.Many2one(
  223. comodel_name='account.account',
  224. compute='_compute_unaffected_earnings_account',
  225. store=True
  226. )
  227. @api.multi
  228. def _print_report(self, report_type):
  229. self.ensure_one()
  230. data = self._prepare_report_general_ledger()
  231. if report_type == 'xlsx':
  232. report_name = 'a_f_r.report_general_ledger_xlsx'
  233. else:
  234. report_name = 'account_financial_report.general_ledger'
  235. return self.env['ir.actions.report'].search(
  236. [('report_name', '=', report_name),
  237. ('report_type', '=', report_type)], limit=1).report_action(
  238. self, data=data)
  239. @api.multi
  240. def button_export_html(self):
  241. self.ensure_one()
  242. report_type = 'qweb-html'
  243. return self._export(report_type)
  244. @api.multi
  245. def button_export_pdf(self):
  246. self.ensure_one()
  247. report_type = 'qweb-pdf'
  248. return self._export(report_type)
  249. @api.multi
  250. def button_export_xlsx(self):
  251. self.ensure_one()
  252. report_type = 'xlsx'
  253. return self._export(report_type)
  254. def _prepare_report_general_ledger(self):
  255. self.ensure_one()
  256. return {
  257. 'wizard_id': self.id,
  258. 'date_from': self.date_from,
  259. 'date_to': self.date_to,
  260. 'only_posted_moves': self.target_move == 'posted',
  261. 'hide_account_at_0': self.hide_account_at_0,
  262. 'foreign_currency': self.foreign_currency,
  263. 'show_analytic_tags': self.show_analytic_tags,
  264. 'company_id': self.company_id.id,
  265. 'account_ids': self.account_ids.ids,
  266. 'partner_ids': self.partner_ids.ids,
  267. 'show_partner_details': self.show_partner_details,
  268. 'cost_center_ids': self.cost_center_ids.ids,
  269. 'analytic_tag_ids': self.analytic_tag_ids.ids,
  270. 'journal_ids': self.account_journal_ids.ids,
  271. 'centralize': self.centralize,
  272. 'fy_start_date': self.fy_start_date,
  273. 'unaffected_earnings_account': self.unaffected_earnings_account.id,
  274. }
  275. def _export(self, report_type):
  276. """Default export is PDF."""
  277. return self._print_report(report_type)
  278. def _get_atr_from_dict(self, obj_id, data, key):
  279. try:
  280. return data[obj_id][key]
  281. except KeyError:
  282. return data[str(obj_id)][key]