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.

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