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.

263 lines
9.5 KiB

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