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.

204 lines
7.5 KiB

5 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. has_moves = fields.Boolean(
  18. string="Has balance in period",
  19. compute="_compute_has_moves",
  20. search="_search_has_moves",
  21. )
  22. def get_context_values(self):
  23. context = self.env.context
  24. return (
  25. context.get("from_date", fields.Date.context_today(self)),
  26. context.get("to_date", fields.Date.context_today(self)),
  27. context.get("company_ids", [self.env.user.company_id.id]),
  28. context.get("target_move", "posted"),
  29. )
  30. def _account_tax_ids_with_moves(self):
  31. """ Return all account.tax ids for which there is at least
  32. one account.move.line in the context period
  33. for the user company.
  34. Caveat: this ignores record rules and ACL but it is good
  35. enough for filtering taxes with activity during the period.
  36. """
  37. from_date, to_date, company_ids, _ = self.get_context_values()
  38. company_ids = tuple(company_ids)
  39. req = """
  40. SELECT id
  41. FROM account_tax at
  42. WHERE
  43. company_id in %s AND
  44. EXISTS (
  45. SELECT 1 FROM account_move_Line aml
  46. WHERE
  47. date >= %s AND
  48. date <= %s AND
  49. company_id in %s AND (
  50. tax_line_id = at.id OR
  51. EXISTS (
  52. SELECT 1 FROM account_move_line_account_tax_rel
  53. WHERE account_move_line_id = aml.id AND
  54. account_tax_id = at.id
  55. )
  56. )
  57. )
  58. """
  59. self.env.cr.execute(req, (company_ids, from_date, to_date, company_ids))
  60. return [r[0] for r in self.env.cr.fetchall()]
  61. def _compute_has_moves(self):
  62. ids_with_moves = set(self._account_tax_ids_with_moves())
  63. for tax in self:
  64. tax.has_moves = tax.id in ids_with_moves
  65. @api.model
  66. def _is_unsupported_search_operator(self, operator):
  67. return operator != "="
  68. @api.model
  69. def _search_has_moves(self, operator, value):
  70. if self._is_unsupported_search_operator(operator) or not value:
  71. raise ValueError(_("Unsupported search operator"))
  72. ids_with_moves = self._account_tax_ids_with_moves()
  73. return [("id", "in", ids_with_moves)]
  74. def _compute_balance(self):
  75. for tax in self:
  76. tax.balance_regular = tax.compute_balance(
  77. tax_or_base="tax", move_type="regular"
  78. )
  79. tax.base_balance_regular = tax.compute_balance(
  80. tax_or_base="base", move_type="regular"
  81. )
  82. tax.balance_refund = tax.compute_balance(
  83. tax_or_base="tax", move_type="refund"
  84. )
  85. tax.base_balance_refund = tax.compute_balance(
  86. tax_or_base="base", move_type="refund"
  87. )
  88. tax.balance = tax.balance_regular + tax.balance_refund
  89. tax.base_balance = tax.base_balance_regular + tax.base_balance_refund
  90. def get_target_type_list(self, move_type=None):
  91. if move_type == "refund":
  92. return ["receivable_refund", "payable_refund"]
  93. elif move_type == "regular":
  94. return ["receivable", "payable", "liquidity", "other"]
  95. return []
  96. def get_target_state_list(self, target_move="posted"):
  97. if target_move == "posted":
  98. state = ["posted"]
  99. elif target_move == "all":
  100. state = ["posted", "draft"]
  101. else:
  102. state = []
  103. return state
  104. def get_move_line_partial_domain(self, from_date, to_date, company_ids):
  105. return [
  106. ("date", "<=", to_date),
  107. ("date", ">=", from_date),
  108. ("company_id", "in", company_ids),
  109. ]
  110. def compute_balance(self, tax_or_base="tax", move_type=None):
  111. self.ensure_one()
  112. domain = self.get_move_lines_domain(
  113. tax_or_base=tax_or_base, move_type=move_type
  114. )
  115. # balance is debit - credit whereas on tax return you want to see what
  116. # vat has to be paid so:
  117. # VAT on sales (credit) - VAT on purchases (debit).
  118. balance = self.env["account.move.line"].read_group(domain, ["balance"], [])[0][
  119. "balance"
  120. ]
  121. return balance and -balance or 0
  122. def get_balance_domain(self, state_list, type_list):
  123. domain = [
  124. ("move_id.state", "in", state_list),
  125. ("tax_line_id", "=", self.id),
  126. ("tax_exigible", "=", True),
  127. ]
  128. if type_list:
  129. domain.append(("move_id.move_type", "in", type_list))
  130. return domain
  131. def get_base_balance_domain(self, state_list, type_list):
  132. domain = [
  133. ("move_id.state", "in", state_list),
  134. ("tax_ids", "in", self.id),
  135. ("tax_exigible", "=", True),
  136. ]
  137. if type_list:
  138. domain.append(("move_id.move_type", "in", type_list))
  139. return domain
  140. def get_move_lines_domain(self, tax_or_base="tax", move_type=None):
  141. from_date, to_date, company_ids, target_move = self.get_context_values()
  142. state_list = self.get_target_state_list(target_move)
  143. type_list = self.get_target_type_list(move_type)
  144. domain = self.get_move_line_partial_domain(from_date, to_date, company_ids)
  145. balance_domain = []
  146. if tax_or_base == "tax":
  147. balance_domain = self.get_balance_domain(state_list, type_list)
  148. elif tax_or_base == "base":
  149. balance_domain = self.get_base_balance_domain(state_list, type_list)
  150. domain.extend(balance_domain)
  151. return domain
  152. def get_lines_action(self, tax_or_base="tax", move_type=None):
  153. domain = self.get_move_lines_domain(
  154. tax_or_base=tax_or_base, move_type=move_type
  155. )
  156. action = self.env.ref("account.action_account_moves_all_tree")
  157. vals = action.read()[0]
  158. vals["context"] = {}
  159. vals["domain"] = domain
  160. return vals
  161. def view_tax_lines(self):
  162. self.ensure_one()
  163. return self.get_lines_action(tax_or_base="tax")
  164. def view_base_lines(self):
  165. self.ensure_one()
  166. return self.get_lines_action(tax_or_base="base")
  167. def view_tax_regular_lines(self):
  168. self.ensure_one()
  169. return self.get_lines_action(tax_or_base="tax", move_type="regular")
  170. def view_base_regular_lines(self):
  171. self.ensure_one()
  172. return self.get_lines_action(tax_or_base="base", move_type="regular")
  173. def view_tax_refund_lines(self):
  174. self.ensure_one()
  175. return self.get_lines_action(tax_or_base="tax", move_type="refund")
  176. def view_base_refund_lines(self):
  177. self.ensure_one()
  178. return self.get_lines_action(tax_or_base="base", move_type="refund")