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.

270 lines
11 KiB

  1. # © 2016 Julien Coux (Camptocamp)
  2. # Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. import operator
  5. from datetime import date, datetime
  6. from odoo import api, models
  7. from odoo.tools import float_is_zero
  8. class OpenItemsReport(models.AbstractModel):
  9. _name = "report.account_financial_report.open_items"
  10. _description = "Open Items Report"
  11. _inherit = "report.account_financial_report.abstract_report"
  12. def _get_account_partial_reconciled(self, company_id, date_at_object):
  13. domain = [("max_date", ">", date_at_object), ("company_id", "=", company_id)]
  14. fields = ["debit_move_id", "credit_move_id", "amount"]
  15. accounts_partial_reconcile = self.env["account.partial.reconcile"].search_read(
  16. domain=domain, fields=fields
  17. )
  18. debit_amount = {}
  19. credit_amount = {}
  20. for account_partial_reconcile_data in accounts_partial_reconcile:
  21. debit_move_id = account_partial_reconcile_data["debit_move_id"][0]
  22. credit_move_id = account_partial_reconcile_data["credit_move_id"][0]
  23. if debit_move_id not in debit_amount.keys():
  24. debit_amount[debit_move_id] = 0.0
  25. debit_amount[debit_move_id] += account_partial_reconcile_data["amount"]
  26. if credit_move_id not in credit_amount.keys():
  27. credit_amount[credit_move_id] = 0.0
  28. credit_amount[credit_move_id] += account_partial_reconcile_data["amount"]
  29. account_partial_reconcile_data.update(
  30. {"debit_move_id": debit_move_id, "credit_move_id": credit_move_id}
  31. )
  32. return accounts_partial_reconcile, debit_amount, credit_amount
  33. def _get_data(
  34. self,
  35. account_ids,
  36. partner_ids,
  37. date_at_object,
  38. only_posted_moves,
  39. company_id,
  40. date_from,
  41. ):
  42. domain = self._get_move_lines_domain_not_reconciled(
  43. company_id, account_ids, partner_ids, only_posted_moves, date_from
  44. )
  45. ml_fields = [
  46. "id",
  47. "name",
  48. "date",
  49. "move_id",
  50. "journal_id",
  51. "account_id",
  52. "partner_id",
  53. "amount_residual",
  54. "date_maturity",
  55. "ref",
  56. "debit",
  57. "credit",
  58. "reconciled",
  59. "currency_id",
  60. "amount_currency",
  61. "amount_residual_currency",
  62. ]
  63. move_lines = self.env["account.move.line"].search_read(
  64. domain=domain, fields=ml_fields
  65. )
  66. journals_ids = set()
  67. partners_ids = set()
  68. partners_data = {}
  69. if date_at_object < date.today():
  70. (
  71. acc_partial_rec,
  72. debit_amount,
  73. credit_amount,
  74. ) = self._get_account_partial_reconciled(company_id, date_at_object)
  75. if acc_partial_rec:
  76. ml_ids = list(map(operator.itemgetter("id"), move_lines))
  77. debit_ids = list(
  78. map(operator.itemgetter("debit_move_id"), acc_partial_rec)
  79. )
  80. credit_ids = list(
  81. map(operator.itemgetter("credit_move_id"), acc_partial_rec)
  82. )
  83. move_lines = self._recalculate_move_lines(
  84. move_lines,
  85. debit_ids,
  86. credit_ids,
  87. debit_amount,
  88. credit_amount,
  89. ml_ids,
  90. account_ids,
  91. company_id,
  92. partner_ids,
  93. only_posted_moves,
  94. )
  95. move_lines = [
  96. move_line
  97. for move_line in move_lines
  98. if move_line["date"] <= date_at_object
  99. and not float_is_zero(move_line["amount_residual"], precision_digits=2)
  100. ]
  101. open_items_move_lines_data = {}
  102. for move_line in move_lines:
  103. journals_ids.add(move_line["journal_id"][0])
  104. acc_id = move_line["account_id"][0]
  105. # Partners data
  106. if move_line["partner_id"]:
  107. prt_id = move_line["partner_id"][0]
  108. prt_name = move_line["partner_id"][1]
  109. else:
  110. prt_id = 0
  111. prt_name = "Missing Partner"
  112. if prt_id not in partners_ids:
  113. partners_data.update({prt_id: {"id": prt_id, "name": prt_name}})
  114. partners_ids.add(prt_id)
  115. # Move line update
  116. original = 0
  117. if not float_is_zero(move_line["credit"], precision_digits=2):
  118. original = move_line["credit"] * (-1)
  119. if not float_is_zero(move_line["debit"], precision_digits=2):
  120. original = move_line["debit"]
  121. if move_line["ref"] == move_line["name"]:
  122. if move_line["ref"]:
  123. ref_label = move_line["ref"]
  124. else:
  125. ref_label = ""
  126. elif not move_line["ref"]:
  127. ref_label = move_line["name"]
  128. elif not move_line["name"]:
  129. ref_label = move_line["ref"]
  130. else:
  131. ref_label = move_line["ref"] + str(" - ") + move_line["name"]
  132. move_line.update(
  133. {
  134. "date": move_line["date"],
  135. "date_maturity": move_line["date_maturity"]
  136. and move_line["date_maturity"].strftime("%d/%m/%Y"),
  137. "original": original,
  138. "partner_id": prt_id,
  139. "partner_name": prt_name,
  140. "ref_label": ref_label,
  141. "journal_id": move_line["journal_id"][0],
  142. "move_name": move_line["move_id"][1],
  143. "currency_id": move_line["currency_id"][0]
  144. if move_line["currency_id"]
  145. else False,
  146. "currency_name": move_line["currency_id"][1]
  147. if move_line["currency_id"]
  148. else False,
  149. }
  150. )
  151. # Open Items Move Lines Data
  152. if acc_id not in open_items_move_lines_data.keys():
  153. open_items_move_lines_data[acc_id] = {prt_id: [move_line]}
  154. else:
  155. if prt_id not in open_items_move_lines_data[acc_id].keys():
  156. open_items_move_lines_data[acc_id][prt_id] = [move_line]
  157. else:
  158. open_items_move_lines_data[acc_id][prt_id].append(move_line)
  159. journals_data = self._get_journals_data(list(journals_ids))
  160. accounts_data = self._get_accounts_data(open_items_move_lines_data.keys())
  161. return (
  162. move_lines,
  163. partners_data,
  164. journals_data,
  165. accounts_data,
  166. open_items_move_lines_data,
  167. )
  168. @api.model
  169. def _calculate_amounts(self, open_items_move_lines_data):
  170. total_amount = {}
  171. for account_id in open_items_move_lines_data.keys():
  172. total_amount[account_id] = {}
  173. total_amount[account_id]["residual"] = 0.0
  174. for partner_id in open_items_move_lines_data[account_id].keys():
  175. total_amount[account_id][partner_id] = {}
  176. total_amount[account_id][partner_id]["residual"] = 0.0
  177. for move_line in open_items_move_lines_data[account_id][partner_id]:
  178. total_amount[account_id][partner_id]["residual"] += move_line[
  179. "amount_residual"
  180. ]
  181. total_amount[account_id]["residual"] += move_line["amount_residual"]
  182. return total_amount
  183. @api.model
  184. def _order_open_items_by_date(
  185. self, open_items_move_lines_data, show_partner_details
  186. ):
  187. new_open_items = {}
  188. if not show_partner_details:
  189. for acc_id in open_items_move_lines_data.keys():
  190. new_open_items[acc_id] = {}
  191. move_lines = []
  192. for prt_id in open_items_move_lines_data[acc_id]:
  193. for move_line in open_items_move_lines_data[acc_id][prt_id]:
  194. move_lines += [move_line]
  195. move_lines = sorted(move_lines, key=lambda k: (k["date"]))
  196. new_open_items[acc_id] = move_lines
  197. else:
  198. for acc_id in open_items_move_lines_data.keys():
  199. new_open_items[acc_id] = {}
  200. for prt_id in open_items_move_lines_data[acc_id]:
  201. new_open_items[acc_id][prt_id] = {}
  202. move_lines = []
  203. for move_line in open_items_move_lines_data[acc_id][prt_id]:
  204. move_lines += [move_line]
  205. move_lines = sorted(move_lines, key=lambda k: (k["date"]))
  206. new_open_items[acc_id][prt_id] = move_lines
  207. return new_open_items
  208. def _get_report_values(self, docids, data):
  209. wizard_id = data["wizard_id"]
  210. company = self.env["res.company"].browse(data["company_id"])
  211. company_id = data["company_id"]
  212. account_ids = data["account_ids"]
  213. partner_ids = data["partner_ids"]
  214. date_at = data["date_at"]
  215. date_at_object = datetime.strptime(date_at, "%Y-%m-%d").date()
  216. date_from = data["date_from"]
  217. only_posted_moves = data["only_posted_moves"]
  218. show_partner_details = data["show_partner_details"]
  219. (
  220. move_lines_data,
  221. partners_data,
  222. journals_data,
  223. accounts_data,
  224. open_items_move_lines_data,
  225. ) = self._get_data(
  226. account_ids,
  227. partner_ids,
  228. date_at_object,
  229. only_posted_moves,
  230. company_id,
  231. date_from,
  232. )
  233. total_amount = self._calculate_amounts(open_items_move_lines_data)
  234. open_items_move_lines_data = self._order_open_items_by_date(
  235. open_items_move_lines_data, show_partner_details
  236. )
  237. return {
  238. "doc_ids": [wizard_id],
  239. "doc_model": "open.items.report.wizard",
  240. "docs": self.env["open.items.report.wizard"].browse(wizard_id),
  241. "foreign_currency": data["foreign_currency"],
  242. "show_partner_details": data["show_partner_details"],
  243. "company_name": company.display_name,
  244. "currency_name": company.currency_id.name,
  245. "date_at": date_at_object.strftime("%d/%m/%Y"),
  246. "hide_account_at_0": data["hide_account_at_0"],
  247. "target_move": data["target_move"],
  248. "journals_data": journals_data,
  249. "partners_data": partners_data,
  250. "accounts_data": accounts_data,
  251. "total_amount": total_amount,
  252. "Open_Items": open_items_move_lines_data,
  253. }