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.

249 lines
9.7 KiB

  1. # Author: Julien Coux
  2. # Copyright 2016 Camptocamp SA
  3. # Copyright 2017 Akretion - Alexis de Lattre
  4. # Copyright 2018 Eficent Business and IT Consuting Services, S.L.
  5. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  6. from odoo import _, api, fields, models
  7. from odoo.exceptions import UserError, ValidationError
  8. from odoo.tools.safe_eval import safe_eval
  9. class TrialBalanceReportWizard(models.TransientModel):
  10. """Trial balance report wizard."""
  11. _name = "trial.balance.report.wizard"
  12. _description = "Trial Balance Report Wizard"
  13. _inherit = "account_financial_report_abstract_wizard"
  14. company_id = fields.Many2one(
  15. comodel_name="res.company",
  16. default=lambda self: self.env.company,
  17. required=False,
  18. string="Company",
  19. )
  20. date_range_id = fields.Many2one(comodel_name="date.range", string="Date range")
  21. date_from = fields.Date(required=True)
  22. date_to = fields.Date(required=True)
  23. fy_start_date = fields.Date(compute="_compute_fy_start_date")
  24. target_move = fields.Selection(
  25. [("posted", "All Posted Entries"), ("all", "All Entries")],
  26. string="Target Moves",
  27. required=True,
  28. default="posted",
  29. )
  30. hierarchy_on = fields.Selection(
  31. [
  32. ("computed", "Computed Accounts"),
  33. ("relation", "Child Accounts"),
  34. ("none", "No hierarchy"),
  35. ],
  36. string="Hierarchy On",
  37. required=True,
  38. default="computed",
  39. help="""Computed Accounts: Use when the account group have codes
  40. that represent prefixes of the actual accounts.\n
  41. Child Accounts: Use when your account groups are hierarchical.\n
  42. No hierarchy: Use to display just the accounts, without any grouping.
  43. """,
  44. )
  45. limit_hierarchy_level = fields.Boolean("Limit hierarchy levels")
  46. show_hierarchy_level = fields.Integer("Hierarchy Levels to display", default=1)
  47. hide_parent_hierarchy_level = fields.Boolean(
  48. "Do not display parent levels", default=False
  49. )
  50. account_ids = fields.Many2many(
  51. comodel_name="account.account", string="Filter accounts",
  52. )
  53. hide_account_at_0 = fields.Boolean(
  54. string="Hide accounts at 0",
  55. default=True,
  56. help="When this option is enabled, the trial balance will "
  57. "not display accounts that have initial balance = "
  58. "debit = credit = end balance = 0",
  59. )
  60. receivable_accounts_only = fields.Boolean()
  61. payable_accounts_only = fields.Boolean()
  62. show_partner_details = fields.Boolean()
  63. partner_ids = fields.Many2many(
  64. comodel_name="res.partner", string="Filter partners",
  65. )
  66. journal_ids = fields.Many2many(comodel_name="account.journal",)
  67. not_only_one_unaffected_earnings_account = fields.Boolean(
  68. readonly=True, string="Not only one unaffected earnings account"
  69. )
  70. foreign_currency = fields.Boolean(
  71. string="Show foreign currency",
  72. help="Display foreign currency for move lines, unless "
  73. "account currency is not setup through chart of accounts "
  74. "will display initial and final balance in that currency.",
  75. )
  76. @api.constrains("hierarchy_on", "show_hierarchy_level")
  77. def _check_show_hierarchy_level(self):
  78. for rec in self:
  79. if rec.hierarchy_on != "none" and rec.show_hierarchy_level <= 0:
  80. raise UserError(
  81. _("The hierarchy level to filter on must be " "greater than 0.")
  82. )
  83. @api.depends("date_from")
  84. def _compute_fy_start_date(self):
  85. for wiz in self:
  86. if wiz.date_from:
  87. res = self.company_id.compute_fiscalyear_dates(wiz.date_from)
  88. wiz.fy_start_date = res["date_from"]
  89. else:
  90. wiz.fy_start_date = False
  91. @api.onchange("company_id")
  92. def onchange_company_id(self):
  93. """Handle company change."""
  94. account_type = self.env.ref("account.data_unaffected_earnings")
  95. count = self.env["account.account"].search_count(
  96. [
  97. ("user_type_id", "=", account_type.id),
  98. ("company_id", "=", self.company_id.id),
  99. ]
  100. )
  101. self.not_only_one_unaffected_earnings_account = count != 1
  102. if (
  103. self.company_id
  104. and self.date_range_id.company_id
  105. and self.date_range_id.company_id != self.company_id
  106. ):
  107. self.date_range_id = False
  108. if self.company_id and self.partner_ids:
  109. self.partner_ids = self.partner_ids.filtered(
  110. lambda p: p.company_id == self.company_id or not p.company_id
  111. )
  112. if self.company_id and self.journal_ids:
  113. self.journal_ids = self.journal_ids.filtered(
  114. lambda a: a.company_id == self.company_id
  115. )
  116. if self.company_id and self.account_ids:
  117. if self.receivable_accounts_only or self.payable_accounts_only:
  118. self.onchange_type_accounts_only()
  119. else:
  120. self.account_ids = self.account_ids.filtered(
  121. lambda a: a.company_id == self.company_id
  122. )
  123. res = {
  124. "domain": {
  125. "account_ids": [],
  126. "partner_ids": [],
  127. "date_range_id": [],
  128. "journal_ids": [],
  129. }
  130. }
  131. if not self.company_id:
  132. return res
  133. else:
  134. res["domain"]["account_ids"] += [("company_id", "=", self.company_id.id)]
  135. res["domain"]["partner_ids"] += self._get_partner_ids_domain()
  136. res["domain"]["date_range_id"] += [
  137. "|",
  138. ("company_id", "=", self.company_id.id),
  139. ("company_id", "=", False),
  140. ]
  141. res["domain"]["journal_ids"] += [("company_id", "=", self.company_id.id)]
  142. return res
  143. @api.onchange("date_range_id")
  144. def onchange_date_range_id(self):
  145. """Handle date range change."""
  146. self.date_from = self.date_range_id.date_start
  147. self.date_to = self.date_range_id.date_end
  148. @api.constrains("company_id", "date_range_id")
  149. def _check_company_id_date_range_id(self):
  150. for rec in self.sudo():
  151. if (
  152. rec.company_id
  153. and rec.date_range_id.company_id
  154. and rec.company_id != rec.date_range_id.company_id
  155. ):
  156. raise ValidationError(
  157. _(
  158. "The Company in the Trial Balance Report Wizard and in "
  159. "Date Range must be the same."
  160. )
  161. )
  162. @api.onchange("receivable_accounts_only", "payable_accounts_only")
  163. def onchange_type_accounts_only(self):
  164. """Handle receivable/payable accounts only change."""
  165. if self.receivable_accounts_only or self.payable_accounts_only:
  166. domain = [("company_id", "=", self.company_id.id)]
  167. if self.receivable_accounts_only and self.payable_accounts_only:
  168. domain += [("internal_type", "in", ("receivable", "payable"))]
  169. elif self.receivable_accounts_only:
  170. domain += [("internal_type", "=", "receivable")]
  171. elif self.payable_accounts_only:
  172. domain += [("internal_type", "=", "payable")]
  173. self.account_ids = self.env["account.account"].search(domain)
  174. else:
  175. self.account_ids = None
  176. @api.onchange("show_partner_details")
  177. def onchange_show_partner_details(self):
  178. """Handle partners change."""
  179. if self.show_partner_details:
  180. self.receivable_accounts_only = self.payable_accounts_only = True
  181. else:
  182. self.receivable_accounts_only = self.payable_accounts_only = False
  183. def button_export_html(self):
  184. self.ensure_one()
  185. action = self.env.ref("account_financial_report.action_report_trial_balance")
  186. vals = action.read()[0]
  187. context1 = vals.get("context", {})
  188. if isinstance(context1, str):
  189. context1 = safe_eval(context1)
  190. model = self.env["report_trial_balance"]
  191. report = model.create(self._prepare_report_trial_balance())
  192. report.compute_data_for_report()
  193. context1["active_id"] = report.id
  194. context1["active_ids"] = report.ids
  195. vals["context"] = context1
  196. return vals
  197. def button_export_pdf(self):
  198. self.ensure_one()
  199. report_type = "qweb-pdf"
  200. return self._export(report_type)
  201. def button_export_xlsx(self):
  202. self.ensure_one()
  203. report_type = "xlsx"
  204. return self._export(report_type)
  205. def _prepare_report_trial_balance(self):
  206. self.ensure_one()
  207. return {
  208. "date_from": self.date_from,
  209. "date_to": self.date_to,
  210. "only_posted_moves": self.target_move == "posted",
  211. "hide_account_at_0": self.hide_account_at_0,
  212. "foreign_currency": self.foreign_currency,
  213. "company_id": self.company_id.id,
  214. "filter_account_ids": [(6, 0, self.account_ids.ids)],
  215. "filter_partner_ids": [(6, 0, self.partner_ids.ids)],
  216. "filter_journal_ids": [(6, 0, self.journal_ids.ids)],
  217. "fy_start_date": self.fy_start_date,
  218. "hierarchy_on": self.hierarchy_on,
  219. "limit_hierarchy_level": self.limit_hierarchy_level,
  220. "show_hierarchy_level": self.show_hierarchy_level,
  221. "hide_parent_hierarchy_level": self.hide_parent_hierarchy_level,
  222. "show_partner_details": self.show_partner_details,
  223. }
  224. def _export(self, report_type):
  225. """Default export is PDF."""
  226. model = self.env["report_trial_balance"]
  227. report = model.create(self._prepare_report_trial_balance())
  228. report.compute_data_for_report()
  229. return report.print_report(report_type)