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.

250 lines
9.5 KiB

5 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. # Copyright 2016 Lorenzo Battistini - Agile Business Group
  2. # Copyright 2016 Antonio Espinosa <antonio.espinosa@tecnativa.com>
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from odoo import api, fields, models
  5. class AccountTax(models.Model):
  6. _inherit = "account.tax"
  7. balance = fields.Float(string="Total Balance", compute="_compute_balance")
  8. base_balance = fields.Float(string="Total Base Balance", compute="_compute_balance")
  9. balance_regular = fields.Float(string="Balance", compute="_compute_balance")
  10. base_balance_regular = fields.Float(
  11. string="Base Balance", compute="_compute_balance"
  12. )
  13. balance_refund = fields.Float(string="Balance Refund", compute="_compute_balance")
  14. base_balance_refund = fields.Float(
  15. string="Base Balance Refund", compute="_compute_balance"
  16. )
  17. def get_context_values(self):
  18. context = self.env.context
  19. actual_company_id = context.get("company_id", self.env.company.id)
  20. return (
  21. context.get("from_date", fields.Date.context_today(self)),
  22. context.get("to_date", fields.Date.context_today(self)),
  23. context.get("company_ids", [actual_company_id]),
  24. context.get("target_move", "posted"),
  25. )
  26. @api.model
  27. def _is_unsupported_search_operator(self, operator):
  28. return operator != "="
  29. def _compute_regular_and_refund(self, total):
  30. tax_ids = total.keys()
  31. total_refund = {}
  32. total_regular = {}
  33. for tax_id in tax_ids:
  34. total_refund[tax_id] = 0.0
  35. total_regular[tax_id] = 0.0
  36. move_types = total[tax_id].keys()
  37. for move_type in move_types:
  38. if move_type in ["receivable_refund", "payable_refund"]:
  39. total_refund[tax_id] += total[tax_id][move_type]
  40. else:
  41. total_regular[tax_id] += total[tax_id][move_type]
  42. return total_regular, total_refund
  43. def _compute_balance(self):
  44. total_balance_tax = self.compute_balance(tax_or_base="tax")
  45. total_balance_base = self.compute_balance(tax_or_base="base")
  46. total_balance_regular, total_balance_refund = self._compute_regular_and_refund(
  47. total_balance_tax
  48. )
  49. (
  50. total_base_balance_regular,
  51. total_base_balance_refund,
  52. ) = self._compute_regular_and_refund(total_balance_base)
  53. founded_taxes_ids = set(list(total_balance_tax.keys())).union(
  54. set(list(total_balance_base.keys()))
  55. )
  56. for tax_id in list(founded_taxes_ids):
  57. tax = self.browse(tax_id)
  58. tax.balance_regular = (
  59. total_balance_regular[tax.id]
  60. if tax.id in total_balance_regular.keys()
  61. else 0.0
  62. )
  63. tax.base_balance_regular = (
  64. total_base_balance_regular[tax.id]
  65. if tax.id in total_base_balance_regular.keys()
  66. else 0.0
  67. )
  68. tax.balance_refund = (
  69. total_balance_refund[tax.id]
  70. if tax.id in total_balance_refund.keys()
  71. else 0.0
  72. )
  73. tax.base_balance_refund = (
  74. total_base_balance_refund[tax.id]
  75. if tax.id in total_base_balance_refund.keys()
  76. else 0.0
  77. )
  78. tax.balance = tax.balance_regular + tax.balance_refund
  79. tax.base_balance = tax.base_balance_regular + tax.base_balance_refund
  80. def get_target_type_list(self, move_type=None):
  81. if move_type == "refund":
  82. return ["receivable_refund", "payable_refund"]
  83. elif move_type == "regular":
  84. return ["receivable", "payable", "liquidity", "other"]
  85. return []
  86. def get_target_state_list(self, target_move="posted"):
  87. if target_move == "posted":
  88. state = ["posted"]
  89. elif target_move == "all":
  90. state = ["posted", "draft"]
  91. else:
  92. state = []
  93. return state
  94. def get_move_line_partial_where(self, from_date, to_date, company_ids):
  95. query = "aml.date <= %s AND aml.date >= %s AND aml.company_id IN %s"
  96. params = [to_date, from_date, tuple(company_ids)]
  97. return query, params
  98. def compute_balance(self, tax_or_base="tax"):
  99. # There's really bad performace in m2m fields.
  100. # So we better do a direct query.
  101. # See https://github.com/odoo/odoo/issues/30350
  102. _select, _group_by, query, params = self.get_move_lines_query(
  103. tax_or_base=tax_or_base
  104. )
  105. query = query.format(select_clause=_select, group_by_clause=_group_by)
  106. self.env.cr.execute(query, params) # pylint: disable=E8103
  107. results = self.env.cr.fetchall()
  108. total_balance = {}
  109. for balance, tax_id, move_type in results:
  110. if tax_id not in total_balance.keys():
  111. total_balance[tax_id] = {}
  112. total_balance[tax_id][move_type] = balance
  113. return total_balance
  114. def get_move_lines_query(self, tax_or_base="tax"):
  115. from_date, to_date, company_ids, target_move = self.get_context_values()
  116. state_list = self.get_target_state_list(target_move)
  117. base_query = self.get_move_lines_base_query()
  118. _where = ""
  119. _joins = ""
  120. _group_by = ""
  121. _params = []
  122. _select = "SELECT SUM(balance)"
  123. _group_by = " GROUP BY am.move_type, "
  124. where, params = self.get_move_line_partial_where(
  125. from_date, to_date, company_ids
  126. )
  127. _where += where
  128. _params += params
  129. if tax_or_base == "tax":
  130. select, where, group_by, params = self.get_balance_where(state_list)
  131. _where += where
  132. _params += params
  133. _select += select
  134. _group_by += group_by
  135. elif tax_or_base == "base":
  136. select, joins, where, group_by, params = self.get_base_balance_where(
  137. state_list
  138. )
  139. _where += where
  140. _joins += joins
  141. _params += params
  142. _select += select
  143. _group_by += group_by
  144. query = base_query.format(
  145. select_clause="{select_clause}",
  146. where_clause=_where,
  147. additional_joins=_joins,
  148. group_by_clause="{group_by_clause}",
  149. )
  150. return _select, _group_by, query, _params
  151. def get_move_lines_base_query(self):
  152. return (
  153. "{select_clause} FROM account_move_line AS aml "
  154. "INNER JOIN account_move AS am ON aml.move_id = am.id "
  155. "{additional_joins}"
  156. " WHERE {where_clause}"
  157. "{group_by_clause}"
  158. )
  159. def get_balance_where(self, state_list):
  160. select = ", aml.tax_line_id as tax_id, am.move_type"
  161. where = (
  162. " AND am.state IN %s"
  163. " AND aml.tax_line_id IS NOT NULL"
  164. " AND aml.tax_exigible = True"
  165. )
  166. group_by = "aml.tax_line_id"
  167. params = [tuple(state_list)]
  168. return select, where, group_by, params
  169. def get_base_balance_where(self, state_list):
  170. select = ", rel.account_tax_id as tax_id, am.move_type"
  171. joins = (
  172. " INNER JOIN account_move_line_account_tax_rel AS rel "
  173. "ON aml.id = rel.account_move_line_id"
  174. )
  175. group_by = "rel.account_tax_id"
  176. where = " AND am.state IN %s" " AND aml.tax_exigible = True "
  177. params = [tuple(state_list)]
  178. return select, joins, where, group_by, params
  179. def get_move_lines_domain(self, tax_or_base="tax", move_type=None):
  180. _select, _group_by, query, params = self.get_move_lines_query(
  181. tax_or_base=tax_or_base
  182. )
  183. _select = "SELECT aml.id"
  184. _group_by = ""
  185. if tax_or_base == "tax":
  186. query += " AND aml.tax_line_id = " + str(self.id)
  187. elif tax_or_base == "base":
  188. query += " AND rel.account_tax_id = " + str(self.id)
  189. type_list = self.get_target_type_list(move_type)
  190. if type_list:
  191. query += " AND am.move_type IN %s"
  192. params += [tuple(type_list)]
  193. query = query.format(select_clause=_select, group_by_clause=_group_by)
  194. self.env.cr.execute(query, params) # pylint: disable=E8103
  195. amls = []
  196. for (aml_id,) in self.env.cr.fetchall():
  197. amls.append(aml_id)
  198. domain = [("id", "in", amls)]
  199. return domain
  200. def get_lines_action(self, tax_or_base="tax", move_type=None):
  201. domain = self.get_move_lines_domain(
  202. tax_or_base=tax_or_base, move_type=move_type
  203. )
  204. action = self.env.ref("account.action_account_moves_all_tree")
  205. vals = action.read()[0]
  206. vals["context"] = {}
  207. vals["domain"] = domain
  208. return vals
  209. def view_tax_lines(self):
  210. self.ensure_one()
  211. return self.get_lines_action(tax_or_base="tax")
  212. def view_base_lines(self):
  213. self.ensure_one()
  214. return self.get_lines_action(tax_or_base="base")
  215. def view_tax_regular_lines(self):
  216. self.ensure_one()
  217. return self.get_lines_action(tax_or_base="tax", move_type="regular")
  218. def view_base_regular_lines(self):
  219. self.ensure_one()
  220. return self.get_lines_action(tax_or_base="base", move_type="regular")
  221. def view_tax_refund_lines(self):
  222. self.ensure_one()
  223. return self.get_lines_action(tax_or_base="tax", move_type="refund")
  224. def view_base_refund_lines(self):
  225. self.ensure_one()
  226. return self.get_lines_action(tax_or_base="base", move_type="refund")