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.

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