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.

360 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 [("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):
  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. }
  106. def _get_account_data(self, accounts):
  107. data = {}
  108. for account in accounts:
  109. data[account.id] = self._get_account_id_data(account)
  110. return data
  111. def _get_account_id_data(self, account):
  112. return {
  113. "name": account.name,
  114. "code": account.code,
  115. "internal_type": account.internal_type,
  116. }
  117. def _get_partner_data(self, partners):
  118. data = {}
  119. for partner in partners:
  120. data[partner.id] = self._get_partner_id_data(partner)
  121. return data
  122. def _get_partner_id_data(self, partner):
  123. return {"name": partner.name}
  124. def _get_currency_data(self, currencies):
  125. data = {}
  126. for currency in currencies:
  127. data[currency.id] = self._get_currency_id_data(currency)
  128. return data
  129. def _get_currency_id_data(self, currency):
  130. return {"name": currency.name}
  131. def _get_tax_line_data(self, taxes):
  132. data = {}
  133. for tax in taxes:
  134. data[tax.id] = self._get_tax_line_id_data(tax)
  135. return data
  136. def _get_tax_line_id_data(self, tax):
  137. return {"name": tax.name, "description": tax.description}
  138. def _get_query_taxes(self):
  139. return """
  140. SELECT aml_at_rel.account_move_line_id, aml_at_rel.account_tax_id,
  141. at.description, at.name
  142. FROM account_move_line_account_tax_rel AS aml_at_rel
  143. LEFT JOIN
  144. account_tax AS at on (at.id = aml_at_rel.account_tax_id)
  145. WHERE account_move_line_id IN %(move_line_ids)s
  146. """
  147. def _get_query_taxes_params(self, move_lines):
  148. return {"move_line_ids": tuple(move_lines.ids)}
  149. def _get_move_lines(self, move_ids, wizard, journal_ids):
  150. move_lines = self.env["account.move.line"].search(
  151. self._get_move_lines_domain(move_ids, wizard, journal_ids),
  152. order=self._get_move_lines_order(move_ids, wizard, journal_ids),
  153. )
  154. move_line_ids_taxes_data = {}
  155. if move_lines:
  156. # Get the taxes ids for the move lines
  157. query_taxes_params = self._get_query_taxes_params(move_lines)
  158. query_taxes = self._get_query_taxes()
  159. self.env.cr.execute(query_taxes, query_taxes_params)
  160. # Fetch the taxes associated to the move line
  161. for (
  162. move_line_id,
  163. account_tax_id,
  164. tax_description,
  165. tax_name,
  166. ) in self.env.cr.fetchall():
  167. if move_line_id not in move_line_ids_taxes_data.keys():
  168. move_line_ids_taxes_data[move_line_id] = {}
  169. move_line_ids_taxes_data[move_line_id][account_tax_id] = {
  170. "name": tax_name,
  171. "description": tax_description,
  172. }
  173. Move_Lines = {}
  174. accounts = self.env["account.account"]
  175. partners = self.env["res.partner"]
  176. currencies = self.env["res.currency"]
  177. tax_lines = self.env["account.tax"]
  178. for ml in move_lines:
  179. if ml.account_id not in accounts:
  180. accounts |= ml.account_id
  181. if ml.partner_id not in partners:
  182. partners |= ml.partner_id
  183. if ml.currency_id not in currencies:
  184. currencies |= ml.currency_id
  185. if ml.tax_line_id not in tax_lines:
  186. tax_lines |= ml.tax_line_id
  187. if ml.move_id.id not in Move_Lines.keys():
  188. Move_Lines[ml.move_id.id] = []
  189. taxes = (
  190. ml.id in move_line_ids_taxes_data.keys()
  191. and move_line_ids_taxes_data[ml.id]
  192. or {}
  193. )
  194. Move_Lines[ml.move_id.id].append(
  195. self._get_move_lines_data(ml, wizard, taxes)
  196. )
  197. account_ids_data = self._get_account_data(accounts)
  198. partner_ids_data = self._get_partner_data(partners)
  199. currency_ids_data = self._get_currency_data(currencies)
  200. tax_line_ids_data = self._get_tax_line_data(tax_lines)
  201. return (
  202. move_lines.ids,
  203. Move_Lines,
  204. account_ids_data,
  205. partner_ids_data,
  206. currency_ids_data,
  207. tax_line_ids_data,
  208. move_line_ids_taxes_data,
  209. )
  210. def _get_journal_tax_lines(self, wizard, moves_data):
  211. journals_taxes_data = {}
  212. for move_data in moves_data:
  213. report_move_lines = move_data["report_move_lines"]
  214. for report_move_line in report_move_lines:
  215. ml_data = report_move_line
  216. tax_ids = []
  217. if ml_data["tax_line_id"]:
  218. tax_ids.append(ml_data["tax_line_id"])
  219. if ml_data["tax_ids"]:
  220. tax_ids += ml_data["tax_ids"]
  221. tax_ids = list(set(tax_ids))
  222. journal_id = ml_data["journal_id"]
  223. if journal_id not in journals_taxes_data.keys():
  224. journals_taxes_data[journal_id] = {}
  225. taxes = self.env["account.tax"].browse(tax_ids)
  226. for tax in taxes:
  227. if tax.id not in journals_taxes_data[journal_id]:
  228. journals_taxes_data[journal_id][tax.id] = {
  229. "base_debit": 0.0,
  230. "base_credit": 0.0,
  231. "base_balance": 0.0,
  232. "tax_debit": 0.0,
  233. "tax_credit": 0.0,
  234. "tax_balance": 0.0,
  235. "tax_name": tax.name,
  236. "tax_code": tax.description,
  237. }
  238. field_keys = [
  239. "base_debit",
  240. "base_credit",
  241. "base_balance",
  242. "tax_debit",
  243. "tax_credit",
  244. "tax_balance",
  245. ]
  246. for field_key in field_keys:
  247. journals_taxes_data[journal_id][tax.id][field_key] += ml_data[
  248. field_key
  249. ]
  250. journals_taxes_data_2 = {}
  251. for journal_id in journals_taxes_data.keys():
  252. journals_taxes_data_2[journal_id] = []
  253. for tax_id in journals_taxes_data[journal_id].keys():
  254. journals_taxes_data_2[journal_id] += [
  255. journals_taxes_data[journal_id][tax_id]
  256. ]
  257. return journals_taxes_data_2
  258. def _get_report_values(self, docids, data):
  259. wizard_id = data["wizard_id"]
  260. wizard = self.env["journal.ledger.report.wizard"].browse(wizard_id)
  261. company = self.env["res.company"].browse(data["company_id"])
  262. journal_ids = data["journal_ids"]
  263. journal_ledgers_data = self._get_journal_ledgers(wizard, journal_ids, company)
  264. move_ids, moves_data, move_ids_data = self._get_moves(wizard, journal_ids)
  265. journal_moves_data = {}
  266. for key, items in itertools.groupby(
  267. moves_data, operator.itemgetter("journal_id")
  268. ):
  269. if key not in journal_moves_data.keys():
  270. journal_moves_data[key] = []
  271. journal_moves_data[key] += list(items)
  272. move_lines_data = (
  273. account_ids_data
  274. ) = (
  275. partner_ids_data
  276. ) = currency_ids_data = tax_line_ids_data = move_line_ids_taxes_data = {}
  277. if move_ids:
  278. move_lines = self._get_move_lines(move_ids, wizard, journal_ids)
  279. move_lines_data = move_lines[1]
  280. account_ids_data = move_lines[2]
  281. partner_ids_data = move_lines[3]
  282. currency_ids_data = move_lines[4]
  283. tax_line_ids_data = move_lines[5]
  284. for move_data in moves_data:
  285. move_id = move_data["move_id"]
  286. move_data["report_move_lines"] = []
  287. if move_id in move_lines_data.keys():
  288. move_data["report_move_lines"] += move_lines_data[move_id]
  289. journals_taxes_data = {}
  290. if moves_data:
  291. journals_taxes_data = self._get_journal_tax_lines(wizard, moves_data)
  292. for journal_ledger_data in journal_ledgers_data:
  293. journal_id = journal_ledger_data["id"]
  294. journal_ledger_data["tax_lines"] = journals_taxes_data.get(journal_id, [])
  295. journal_totals = {}
  296. for move_id in move_lines_data.keys():
  297. for move_line_data in move_lines_data[move_id]:
  298. journal_id = move_line_data["journal_id"]
  299. if journal_id not in journal_totals.keys():
  300. journal_totals[journal_id] = {"debit": 0.0, "credit": 0.0}
  301. for item in ["debit", "credit"]:
  302. journal_totals[journal_id][item] += move_line_data[item]
  303. for journal_ledger_data in journal_ledgers_data:
  304. journal_id = journal_ledger_data["id"]
  305. if journal_id in journal_moves_data.keys():
  306. journal_ledger_data["report_moves"] = journal_moves_data[journal_id]
  307. else:
  308. journal_ledger_data["report_moves"] = []
  309. if journal_id in journal_totals.keys():
  310. for item in ["debit", "credit"]:
  311. journal_ledger_data[item] += journal_totals[journal_id][item]
  312. return {
  313. "doc_ids": [wizard_id],
  314. "doc_model": "journal.ledger.report.wizard",
  315. "docs": self.env["journal.ledger.report.wizard"].browse(wizard_id),
  316. "group_option": data["group_option"],
  317. "foreign_currency": data["foreign_currency"],
  318. "with_account_name": data["with_account_name"],
  319. "company_name": company.display_name,
  320. "currency_name": company.currency_id.name,
  321. "date_from": data["date_from"],
  322. "date_to": data["date_to"],
  323. "move_target": data["move_target"],
  324. "account_ids_data": account_ids_data,
  325. "partner_ids_data": partner_ids_data,
  326. "currency_ids_data": currency_ids_data,
  327. "move_ids_data": move_ids_data,
  328. "tax_line_data": tax_line_ids_data,
  329. "move_line_ids_taxes_data": move_line_ids_taxes_data,
  330. "Journal_Ledgers": journal_ledgers_data,
  331. "Moves": moves_data,
  332. }