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.

361 lines
14 KiB

  1. # Copyright 2019-20 ForgeFlow S.L. (https://www.forgeflow.com)
  2. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
  3. import itertools
  4. import operator
  5. from odoo import models
  6. class JournalLedgerReport(models.AbstractModel):
  7. _name = "report.account_financial_report.journal_ledger"
  8. _description = "Journal Ledger Report"
  9. def _get_journal_ledger_data(self, journal):
  10. return {
  11. "id": journal.id,
  12. "name": journal.name,
  13. "currency_id": journal.currency_id.id,
  14. "currency_name": journal.currency_id
  15. and journal.currency_id.name
  16. or journal.company_id.currency_id.name,
  17. "debit": 0.0,
  18. "credit": 0.0,
  19. }
  20. def _get_journal_ledgers_domain(self, wizard, journal_ids, company):
  21. domain = []
  22. if company:
  23. domain += [("company_id", "=", company.id)]
  24. if journal_ids:
  25. domain += [("id", "in", journal_ids)]
  26. return domain
  27. def _get_journal_ledgers(self, wizard, journal_ids, company):
  28. journals = self.env["account.journal"].search(
  29. self._get_journal_ledgers_domain(wizard, journal_ids, company),
  30. order="name asc",
  31. )
  32. journal_ledgers_data = []
  33. for journal in journals:
  34. journal_ledgers_data.append(self._get_journal_ledger_data(journal))
  35. return journal_ledgers_data
  36. def _get_moves_domain(self, wizard, journal_ids):
  37. domain = [
  38. ("journal_id", "in", journal_ids),
  39. ("date", ">=", wizard.date_from),
  40. ("date", "<=", wizard.date_to),
  41. ]
  42. if wizard.move_target != "all":
  43. domain += [("state", "=", wizard.move_target)]
  44. else:
  45. domain += [("state", "in", ["posted", "draft"])]
  46. return domain
  47. def _get_moves_order(self, wizard, journal_ids):
  48. search_order = ""
  49. if wizard.sort_option == "move_name":
  50. search_order = "name asc"
  51. elif wizard.sort_option == "date":
  52. search_order = "date asc, name asc"
  53. return search_order
  54. def _get_moves_data(self, move):
  55. return {
  56. "move_id": move.id,
  57. "journal_id": move.journal_id.id,
  58. "entry": move.name,
  59. }
  60. def _get_moves(self, wizard, journal_ids):
  61. moves = self.env["account.move"].search(
  62. self._get_moves_domain(wizard, journal_ids),
  63. order=self._get_moves_order(wizard, journal_ids),
  64. )
  65. Moves = []
  66. move_data = {}
  67. for move in moves:
  68. move_data[move.id] = self._get_moves_data(move)
  69. Moves.append(move_data[move.id])
  70. return moves.ids, Moves, move_data
  71. def _get_move_lines_domain(self, move_ids, wizard, journal_ids):
  72. return [("display_type", "=", False), ("move_id", "in", move_ids)]
  73. def _get_move_lines_order(self, move_ids, wizard, journal_ids):
  74. return ""
  75. def _get_move_lines_data(self, ml, wizard, ml_taxes):
  76. base_debit = (
  77. base_credit
  78. ) = tax_debit = tax_credit = base_balance = tax_balance = 0.0
  79. if ml.tax_exigible:
  80. base_debit = ml_taxes and ml.debit or 0.0
  81. base_credit = ml_taxes and ml.credit or 0.0
  82. base_balance = ml_taxes and ml.balance or 0.0
  83. tax_debit = ml.tax_line_id and ml.debit or 0.0
  84. tax_credit = ml.tax_line_id and ml.credit or 0.0
  85. tax_balance = ml.tax_line_id and ml.balance or 0.0
  86. return {
  87. "move_line_id": ml.id,
  88. "move_id": ml.move_id.id,
  89. "date": ml.date,
  90. "journal_id": ml.journal_id.id,
  91. "account_id": ml.account_id.id,
  92. "partner_id": ml.partner_id.id,
  93. "label": ml.name,
  94. "debit": ml.debit,
  95. "credit": ml.credit,
  96. "company_currency_id": ml.company_currency_id.id,
  97. "amount_currency": ml.amount_currency,
  98. "currency_id": ml.currency_id.id,
  99. "tax_line_id": ml.tax_line_id.id,
  100. "tax_ids": list(ml_taxes.keys()),
  101. "base_debit": base_debit,
  102. "base_credit": base_credit,
  103. "tax_debit": tax_debit,
  104. "tax_credit": tax_credit,
  105. "base_balance": base_balance,
  106. "tax_balance": tax_balance,
  107. }
  108. def _get_account_data(self, accounts):
  109. data = {}
  110. for account in accounts:
  111. data[account.id] = self._get_account_id_data(account)
  112. return data
  113. def _get_account_id_data(self, account):
  114. return {
  115. "name": account.name,
  116. "code": account.code,
  117. "internal_type": account.internal_type,
  118. }
  119. def _get_partner_data(self, partners):
  120. data = {}
  121. for partner in partners:
  122. data[partner.id] = self._get_partner_id_data(partner)
  123. return data
  124. def _get_partner_id_data(self, partner):
  125. return {"name": partner.name}
  126. def _get_currency_data(self, currencies):
  127. data = {}
  128. for currency in currencies:
  129. data[currency.id] = self._get_currency_id_data(currency)
  130. return data
  131. def _get_currency_id_data(self, currency):
  132. return {"name": currency.name}
  133. def _get_tax_line_data(self, taxes):
  134. data = {}
  135. for tax in taxes:
  136. data[tax.id] = self._get_tax_line_id_data(tax)
  137. return data
  138. def _get_tax_line_id_data(self, tax):
  139. return {"name": tax.name, "description": tax.description}
  140. def _get_query_taxes(self):
  141. return """
  142. SELECT aml_at_rel.account_move_line_id, aml_at_rel.account_tax_id,
  143. at.description, at.name
  144. FROM account_move_line_account_tax_rel AS aml_at_rel
  145. LEFT JOIN
  146. account_tax AS at on (at.id = aml_at_rel.account_tax_id)
  147. WHERE account_move_line_id IN %(move_line_ids)s
  148. """
  149. def _get_query_taxes_params(self, move_lines):
  150. return {"move_line_ids": tuple(move_lines.ids)}
  151. def _get_move_lines(self, move_ids, wizard, journal_ids):
  152. move_lines = self.env["account.move.line"].search(
  153. self._get_move_lines_domain(move_ids, wizard, journal_ids),
  154. order=self._get_move_lines_order(move_ids, wizard, journal_ids),
  155. )
  156. move_line_ids_taxes_data = {}
  157. if move_lines:
  158. # Get the taxes ids for the move lines
  159. query_taxes_params = self._get_query_taxes_params(move_lines)
  160. query_taxes = self._get_query_taxes()
  161. self.env.cr.execute(query_taxes, query_taxes_params)
  162. # Fetch the taxes associated to the move line
  163. for (
  164. move_line_id,
  165. account_tax_id,
  166. tax_description,
  167. tax_name,
  168. ) in self.env.cr.fetchall():
  169. if move_line_id not in move_line_ids_taxes_data.keys():
  170. move_line_ids_taxes_data[move_line_id] = {}
  171. move_line_ids_taxes_data[move_line_id][account_tax_id] = {
  172. "name": tax_name,
  173. "description": tax_description,
  174. }
  175. Move_Lines = {}
  176. accounts = self.env["account.account"]
  177. partners = self.env["res.partner"]
  178. currencies = self.env["res.currency"]
  179. tax_lines = self.env["account.tax"]
  180. for ml in move_lines:
  181. if ml.account_id not in accounts:
  182. accounts |= ml.account_id
  183. if ml.partner_id not in partners:
  184. partners |= ml.partner_id
  185. if ml.currency_id not in currencies:
  186. currencies |= ml.currency_id
  187. if ml.tax_line_id not in tax_lines:
  188. tax_lines |= ml.tax_line_id
  189. if ml.move_id.id not in Move_Lines.keys():
  190. Move_Lines[ml.move_id.id] = []
  191. taxes = (
  192. ml.id in move_line_ids_taxes_data.keys()
  193. and move_line_ids_taxes_data[ml.id]
  194. or {}
  195. )
  196. Move_Lines[ml.move_id.id].append(
  197. self._get_move_lines_data(ml, wizard, taxes)
  198. )
  199. account_ids_data = self._get_account_data(accounts)
  200. partner_ids_data = self._get_partner_data(partners)
  201. currency_ids_data = self._get_currency_data(currencies)
  202. tax_line_ids_data = self._get_tax_line_data(tax_lines)
  203. return (
  204. move_lines.ids,
  205. Move_Lines,
  206. account_ids_data,
  207. partner_ids_data,
  208. currency_ids_data,
  209. tax_line_ids_data,
  210. move_line_ids_taxes_data,
  211. )
  212. def _get_journal_tax_lines(self, wizard, moves_data):
  213. journals_taxes_data = {}
  214. for move_data in moves_data:
  215. report_move_lines = move_data["report_move_lines"]
  216. for report_move_line in report_move_lines:
  217. ml_data = report_move_line
  218. tax_ids = []
  219. if ml_data["tax_line_id"]:
  220. tax_ids.append(ml_data["tax_line_id"])
  221. if ml_data["tax_ids"]:
  222. tax_ids += ml_data["tax_ids"]
  223. tax_ids = list(set(tax_ids))
  224. journal_id = ml_data["journal_id"]
  225. if journal_id not in journals_taxes_data.keys():
  226. journals_taxes_data[journal_id] = {}
  227. taxes = self.env["account.tax"].browse(tax_ids)
  228. for tax in taxes:
  229. if tax.id not in journals_taxes_data[journal_id]:
  230. journals_taxes_data[journal_id][tax.id] = {
  231. "base_debit": 0.0,
  232. "base_credit": 0.0,
  233. "base_balance": 0.0,
  234. "tax_debit": 0.0,
  235. "tax_credit": 0.0,
  236. "tax_balance": 0.0,
  237. "tax_name": tax.name,
  238. "tax_code": tax.description,
  239. }
  240. field_keys = [
  241. "base_debit",
  242. "base_credit",
  243. "base_balance",
  244. "tax_debit",
  245. "tax_credit",
  246. "tax_balance",
  247. ]
  248. for field_key in field_keys:
  249. journals_taxes_data[journal_id][tax.id][field_key] += ml_data[
  250. field_key
  251. ]
  252. journals_taxes_data_2 = {}
  253. for journal_id in journals_taxes_data.keys():
  254. journals_taxes_data_2[journal_id] = []
  255. for tax_id in journals_taxes_data[journal_id].keys():
  256. journals_taxes_data_2[journal_id] += [
  257. journals_taxes_data[journal_id][tax_id]
  258. ]
  259. return journals_taxes_data_2
  260. def _get_report_values(self, docids, data):
  261. wizard_id = data["wizard_id"]
  262. wizard = self.env["journal.ledger.report.wizard"].browse(wizard_id)
  263. company = self.env["res.company"].browse(data["company_id"])
  264. journal_ids = data["journal_ids"]
  265. journal_ledgers_data = self._get_journal_ledgers(wizard, journal_ids, company)
  266. move_ids, moves_data, move_ids_data = self._get_moves(wizard, journal_ids)
  267. journal_moves_data = {}
  268. for key, items in itertools.groupby(
  269. moves_data, operator.itemgetter("journal_id")
  270. ):
  271. if key not in journal_moves_data.keys():
  272. journal_moves_data[key] = []
  273. journal_moves_data[key] += list(items)
  274. move_lines_data = (
  275. account_ids_data
  276. ) = (
  277. partner_ids_data
  278. ) = currency_ids_data = tax_line_ids_data = move_line_ids_taxes_data = {}
  279. if move_ids:
  280. move_lines = self._get_move_lines(move_ids, wizard, journal_ids)
  281. move_lines_data = move_lines[1]
  282. account_ids_data = move_lines[2]
  283. partner_ids_data = move_lines[3]
  284. currency_ids_data = move_lines[4]
  285. tax_line_ids_data = move_lines[5]
  286. for move_data in moves_data:
  287. move_id = move_data["move_id"]
  288. move_data["report_move_lines"] = []
  289. if move_id in move_lines_data.keys():
  290. move_data["report_move_lines"] += move_lines_data[move_id]
  291. journals_taxes_data = {}
  292. if moves_data:
  293. journals_taxes_data = self._get_journal_tax_lines(wizard, moves_data)
  294. for journal_ledger_data in journal_ledgers_data:
  295. journal_id = journal_ledger_data["id"]
  296. journal_ledger_data["tax_lines"] = journals_taxes_data.get(journal_id, [])
  297. journal_totals = {}
  298. for move_id in move_lines_data.keys():
  299. for move_line_data in move_lines_data[move_id]:
  300. journal_id = move_line_data["journal_id"]
  301. if journal_id not in journal_totals.keys():
  302. journal_totals[journal_id] = {"debit": 0.0, "credit": 0.0}
  303. for item in ["debit", "credit"]:
  304. journal_totals[journal_id][item] += move_line_data[item]
  305. for journal_ledger_data in journal_ledgers_data:
  306. journal_id = journal_ledger_data["id"]
  307. if journal_id in journal_moves_data.keys():
  308. journal_ledger_data["report_moves"] = journal_moves_data[journal_id]
  309. else:
  310. journal_ledger_data["report_moves"] = []
  311. if journal_id in journal_totals.keys():
  312. for item in ["debit", "credit"]:
  313. journal_ledger_data[item] += journal_totals[journal_id][item]
  314. return {
  315. "doc_ids": [wizard_id],
  316. "doc_model": "journal.ledger.report.wizard",
  317. "docs": self.env["journal.ledger.report.wizard"].browse(wizard_id),
  318. "group_option": data["group_option"],
  319. "foreign_currency": data["foreign_currency"],
  320. "with_account_name": data["with_account_name"],
  321. "company_name": company.display_name,
  322. "currency_name": company.currency_id.name,
  323. "date_from": data["date_from"],
  324. "date_to": data["date_to"],
  325. "move_target": data["move_target"],
  326. "account_ids_data": account_ids_data,
  327. "partner_ids_data": partner_ids_data,
  328. "currency_ids_data": currency_ids_data,
  329. "move_ids_data": move_ids_data,
  330. "tax_line_data": tax_line_ids_data,
  331. "move_line_ids_taxes_data": move_line_ids_taxes_data,
  332. "Journal_Ledgers": journal_ledgers_data,
  333. "Moves": moves_data,
  334. }