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.

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