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.

845 lines
34 KiB

  1. # © 2016 Julien Coux (Camptocamp)
  2. # Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. import calendar
  5. import datetime
  6. import operator
  7. from odoo import _, api, models
  8. from odoo.tools import float_is_zero
  9. class GeneralLedgerReport(models.AbstractModel):
  10. _name = "report.account_financial_report.general_ledger"
  11. _description = "General Ledger Report"
  12. _inherit = "report.account_financial_report.abstract_report"
  13. def _get_tags_data(self, tags_ids):
  14. tags = self.env["account.analytic.tag"].browse(tags_ids)
  15. tags_data = {}
  16. for tag in tags:
  17. tags_data.update({tag.id: {"name": tag.name}})
  18. return tags_data
  19. def _get_taxes_data(self, taxes_ids):
  20. taxes = self.env["account.tax"].browse(taxes_ids)
  21. taxes_data = {}
  22. for tax in taxes:
  23. taxes_data.update(
  24. {
  25. tax.id: {
  26. "id": tax.id,
  27. "amount": tax.amount,
  28. "amount_type": tax.amount_type,
  29. "display_name": tax.display_name,
  30. }
  31. }
  32. )
  33. if tax.amount_type == "percent" or tax.amount_type == "division":
  34. taxes_data[tax.id]["string"] = "%"
  35. else:
  36. taxes_data[tax.id]["string"] = ""
  37. taxes_data[tax.id]["tax_name"] = (
  38. tax.display_name
  39. + " ("
  40. + str(tax.amount)
  41. + taxes_data[tax.id]["string"]
  42. + ")"
  43. )
  44. return taxes_data
  45. def _get_acc_prt_accounts_ids(self, company_id):
  46. accounts_domain = [
  47. ("company_id", "=", company_id),
  48. ("internal_type", "in", ["receivable", "payable"]),
  49. ]
  50. acc_prt_accounts = self.env["account.account"].search(accounts_domain)
  51. return acc_prt_accounts.ids
  52. def _get_initial_balances_bs_ml_domain(
  53. self, account_ids, company_id, date_from, base_domain, acc_prt=False
  54. ):
  55. accounts_domain = [
  56. ("company_id", "=", company_id),
  57. ("user_type_id.include_initial_balance", "=", True),
  58. ]
  59. if account_ids:
  60. accounts_domain += [("id", "in", account_ids)]
  61. domain = []
  62. domain += base_domain
  63. domain += [("date", "<", date_from)]
  64. accounts = self.env["account.account"].search(accounts_domain)
  65. domain += [("account_id", "in", accounts.ids)]
  66. if acc_prt:
  67. domain += [("account_id.internal_type", "in", ["receivable", "payable"])]
  68. return domain
  69. def _get_initial_balances_pl_ml_domain(
  70. self, account_ids, company_id, date_from, fy_start_date, base_domain
  71. ):
  72. accounts_domain = [
  73. ("company_id", "=", company_id),
  74. ("user_type_id.include_initial_balance", "=", False),
  75. ]
  76. if account_ids:
  77. accounts_domain += [("id", "in", account_ids)]
  78. domain = []
  79. domain += base_domain
  80. domain += [("date", "<", date_from), ("date", ">=", fy_start_date)]
  81. accounts = self.env["account.account"].search(accounts_domain)
  82. domain += [("account_id", "in", accounts.ids)]
  83. return domain
  84. def _get_accounts_initial_balance(self, initial_domain_bs, initial_domain_pl):
  85. gl_initial_acc_bs = self.env["account.move.line"].read_group(
  86. domain=initial_domain_bs,
  87. fields=["account_id", "debit", "credit", "balance", "amount_currency"],
  88. groupby=["account_id"],
  89. )
  90. gl_initial_acc_pl = self.env["account.move.line"].read_group(
  91. domain=initial_domain_pl,
  92. fields=["account_id", "debit", "credit", "balance", "amount_currency"],
  93. groupby=["account_id"],
  94. )
  95. gl_initial_acc = gl_initial_acc_bs + gl_initial_acc_pl
  96. return gl_initial_acc
  97. def _get_initial_balance_fy_pl_ml_domain(
  98. self, account_ids, company_id, fy_start_date, base_domain
  99. ):
  100. accounts_domain = [
  101. ("company_id", "=", company_id),
  102. ("user_type_id.include_initial_balance", "=", False),
  103. ]
  104. if account_ids:
  105. accounts_domain += [("id", "in", account_ids)]
  106. domain = []
  107. domain += base_domain
  108. domain += [("date", "<", fy_start_date)]
  109. accounts = self.env["account.account"].search(accounts_domain)
  110. domain += [("account_id", "in", accounts.ids)]
  111. return domain
  112. def _get_pl_initial_balance(
  113. self, account_ids, company_id, fy_start_date, foreign_currency, base_domain
  114. ):
  115. domain = self._get_initial_balance_fy_pl_ml_domain(
  116. account_ids, company_id, fy_start_date, base_domain
  117. )
  118. initial_balances = self.env["account.move.line"].read_group(
  119. domain=domain,
  120. fields=["account_id", "debit", "credit", "balance", "amount_currency"],
  121. groupby=["account_id"],
  122. )
  123. pl_initial_balance = {
  124. "debit": 0.0,
  125. "credit": 0.0,
  126. "balance": 0.0,
  127. "bal_curr": 0.0,
  128. }
  129. for initial_balance in initial_balances:
  130. pl_initial_balance["debit"] += initial_balance["debit"]
  131. pl_initial_balance["credit"] += initial_balance["credit"]
  132. pl_initial_balance["balance"] += initial_balance["balance"]
  133. pl_initial_balance["bal_curr"] += initial_balance["amount_currency"]
  134. return pl_initial_balance
  135. def _get_initial_balance_data(
  136. self,
  137. account_ids,
  138. partner_ids,
  139. company_id,
  140. date_from,
  141. foreign_currency,
  142. only_posted_moves,
  143. unaffected_earnings_account,
  144. fy_start_date,
  145. analytic_tag_ids,
  146. cost_center_ids,
  147. extra_domain,
  148. ):
  149. base_domain = []
  150. if company_id:
  151. base_domain += [("company_id", "=", company_id)]
  152. if partner_ids:
  153. base_domain += [("partner_id", "in", partner_ids)]
  154. if only_posted_moves:
  155. base_domain += [("move_id.state", "=", "posted")]
  156. else:
  157. base_domain += [("move_id.state", "in", ["posted", "draft"])]
  158. if analytic_tag_ids:
  159. base_domain += [("analytic_tag_ids", "in", analytic_tag_ids)]
  160. if cost_center_ids:
  161. base_domain += [("analytic_account_id", "in", cost_center_ids)]
  162. if extra_domain:
  163. base_domain += extra_domain
  164. initial_domain_bs = self._get_initial_balances_bs_ml_domain(
  165. account_ids, company_id, date_from, base_domain
  166. )
  167. initial_domain_pl = self._get_initial_balances_pl_ml_domain(
  168. account_ids, company_id, date_from, fy_start_date, base_domain
  169. )
  170. gl_initial_acc = self._get_accounts_initial_balance(
  171. initial_domain_bs, initial_domain_pl
  172. )
  173. initial_domain_acc_prt = self._get_initial_balances_bs_ml_domain(
  174. account_ids, company_id, date_from, base_domain, acc_prt=True
  175. )
  176. gl_initial_acc_prt = self.env["account.move.line"].read_group(
  177. domain=initial_domain_acc_prt,
  178. fields=[
  179. "account_id",
  180. "partner_id",
  181. "debit",
  182. "credit",
  183. "balance",
  184. "amount_currency",
  185. ],
  186. groupby=["account_id", "partner_id"],
  187. lazy=False,
  188. )
  189. gen_ld_data = {}
  190. for gl in gl_initial_acc:
  191. acc_id = gl["account_id"][0]
  192. gen_ld_data[acc_id] = {}
  193. gen_ld_data[acc_id]["id"] = acc_id
  194. gen_ld_data[acc_id]["partners"] = False
  195. gen_ld_data[acc_id]["init_bal"] = {}
  196. gen_ld_data[acc_id]["init_bal"]["credit"] = gl["credit"]
  197. gen_ld_data[acc_id]["init_bal"]["debit"] = gl["debit"]
  198. gen_ld_data[acc_id]["init_bal"]["balance"] = gl["balance"]
  199. gen_ld_data[acc_id]["fin_bal"] = {}
  200. gen_ld_data[acc_id]["fin_bal"]["credit"] = gl["credit"]
  201. gen_ld_data[acc_id]["fin_bal"]["debit"] = gl["debit"]
  202. gen_ld_data[acc_id]["fin_bal"]["balance"] = gl["balance"]
  203. gen_ld_data[acc_id]["init_bal"]["bal_curr"] = gl["amount_currency"]
  204. gen_ld_data[acc_id]["fin_bal"]["bal_curr"] = gl["amount_currency"]
  205. partners_data = {}
  206. partners_ids = set()
  207. if gl_initial_acc_prt:
  208. for gl in gl_initial_acc_prt:
  209. if not gl["partner_id"]:
  210. prt_id = 0
  211. prt_name = "Missing Partner"
  212. else:
  213. prt_id = gl["partner_id"][0]
  214. prt_name = gl["partner_id"][1]
  215. prt_name = prt_name._value
  216. if prt_id not in partners_ids:
  217. partners_ids.add(prt_id)
  218. partners_data.update({prt_id: {"id": prt_id, "name": prt_name}})
  219. acc_id = gl["account_id"][0]
  220. gen_ld_data[acc_id][prt_id] = {}
  221. gen_ld_data[acc_id][prt_id]["id"] = prt_id
  222. gen_ld_data[acc_id]["partners"] = True
  223. gen_ld_data[acc_id][prt_id]["init_bal"] = {}
  224. gen_ld_data[acc_id][prt_id]["init_bal"]["credit"] = gl["credit"]
  225. gen_ld_data[acc_id][prt_id]["init_bal"]["debit"] = gl["debit"]
  226. gen_ld_data[acc_id][prt_id]["init_bal"]["balance"] = gl["balance"]
  227. gen_ld_data[acc_id][prt_id]["fin_bal"] = {}
  228. gen_ld_data[acc_id][prt_id]["fin_bal"]["credit"] = gl["credit"]
  229. gen_ld_data[acc_id][prt_id]["fin_bal"]["debit"] = gl["debit"]
  230. gen_ld_data[acc_id][prt_id]["fin_bal"]["balance"] = gl["balance"]
  231. gen_ld_data[acc_id][prt_id]["init_bal"]["bal_curr"] = gl[
  232. "amount_currency"
  233. ]
  234. gen_ld_data[acc_id][prt_id]["fin_bal"]["bal_curr"] = gl[
  235. "amount_currency"
  236. ]
  237. accounts_ids = list(gen_ld_data.keys())
  238. unaffected_id = unaffected_earnings_account
  239. if unaffected_id not in accounts_ids:
  240. accounts_ids.append(unaffected_id)
  241. self._initialize_account(gen_ld_data, unaffected_id, foreign_currency)
  242. pl_initial_balance = self._get_pl_initial_balance(
  243. account_ids, company_id, fy_start_date, foreign_currency, base_domain
  244. )
  245. gen_ld_data[unaffected_id]["init_bal"]["debit"] += pl_initial_balance["debit"]
  246. gen_ld_data[unaffected_id]["init_bal"]["credit"] += pl_initial_balance["credit"]
  247. gen_ld_data[unaffected_id]["init_bal"]["balance"] += pl_initial_balance[
  248. "balance"
  249. ]
  250. gen_ld_data[unaffected_id]["fin_bal"]["debit"] += pl_initial_balance["debit"]
  251. gen_ld_data[unaffected_id]["fin_bal"]["credit"] += pl_initial_balance["credit"]
  252. gen_ld_data[unaffected_id]["fin_bal"]["balance"] += pl_initial_balance[
  253. "balance"
  254. ]
  255. if foreign_currency:
  256. gen_ld_data[unaffected_id]["init_bal"]["bal_curr"] += pl_initial_balance[
  257. "bal_curr"
  258. ]
  259. gen_ld_data[unaffected_id]["fin_bal"]["bal_curr"] += pl_initial_balance[
  260. "bal_curr"
  261. ]
  262. return gen_ld_data, partners_data, partner_ids
  263. @api.model
  264. def _get_move_line_data(self, move_line):
  265. move_line_data = {
  266. "id": move_line["id"],
  267. "date": move_line["date"],
  268. "entry": move_line["move_id"][1],
  269. "entry_id": move_line["move_id"][0],
  270. "journal_id": move_line["journal_id"][0],
  271. "account_id": move_line["account_id"][0],
  272. "partner_id": move_line["partner_id"][0]
  273. if move_line["partner_id"]
  274. else False,
  275. "partner_name": move_line["partner_id"][1]
  276. if move_line["partner_id"]
  277. else "",
  278. "ref": "" if not move_line["ref"] else move_line["ref"],
  279. "name": "" if not move_line["name"] else move_line["name"],
  280. "tax_ids": move_line["tax_ids"],
  281. "debit": move_line["debit"],
  282. "credit": move_line["credit"],
  283. "balance": move_line["balance"],
  284. "bal_curr": move_line["amount_currency"],
  285. "rec_id": move_line["full_reconcile_id"][0]
  286. if move_line["full_reconcile_id"]
  287. else False,
  288. "rec_name": move_line["full_reconcile_id"][1]
  289. if move_line["full_reconcile_id"]
  290. else "",
  291. "tag_ids": move_line["analytic_tag_ids"],
  292. "currency_id": move_line["currency_id"],
  293. "analytic_account": move_line["analytic_account_id"][1]
  294. if move_line["analytic_account_id"]
  295. else "",
  296. "analytic_account_id": move_line["analytic_account_id"][0]
  297. if move_line["analytic_account_id"]
  298. else False,
  299. }
  300. if (
  301. move_line_data["ref"] == move_line_data["name"]
  302. or move_line_data["ref"] == ""
  303. ):
  304. ref_label = move_line_data["name"]
  305. elif move_line_data["name"] == "":
  306. ref_label = move_line_data["ref"]
  307. else:
  308. ref_label = move_line_data["ref"] + str(" - ") + move_line_data["name"]
  309. move_line_data.update({"ref_label": ref_label})
  310. return move_line_data
  311. @api.model
  312. def _get_period_domain(
  313. self,
  314. account_ids,
  315. partner_ids,
  316. company_id,
  317. only_posted_moves,
  318. date_to,
  319. date_from,
  320. analytic_tag_ids,
  321. cost_center_ids,
  322. ):
  323. domain = [
  324. ("display_type", "=", False),
  325. ("date", ">=", date_from),
  326. ("date", "<=", date_to),
  327. ]
  328. if account_ids:
  329. domain += [("account_id", "in", account_ids)]
  330. if company_id:
  331. domain += [("company_id", "=", company_id)]
  332. if partner_ids:
  333. domain += [("partner_id", "in", partner_ids)]
  334. if only_posted_moves:
  335. domain += [("move_id.state", "=", "posted")]
  336. else:
  337. domain += [("move_id.state", "in", ["posted", "draft"])]
  338. if analytic_tag_ids:
  339. domain += [("analytic_tag_ids", "in", analytic_tag_ids)]
  340. if cost_center_ids:
  341. domain += [("analytic_account_id", "in", cost_center_ids)]
  342. return domain
  343. @api.model
  344. def _initialize_partner(self, gen_ld_data, acc_id, prt_id, foreign_currency):
  345. gen_ld_data[acc_id]["partners"] = True
  346. gen_ld_data[acc_id][prt_id] = {}
  347. gen_ld_data[acc_id][prt_id]["id"] = prt_id
  348. gen_ld_data[acc_id][prt_id]["init_bal"] = {}
  349. gen_ld_data[acc_id][prt_id]["init_bal"]["balance"] = 0.0
  350. gen_ld_data[acc_id][prt_id]["init_bal"]["credit"] = 0.0
  351. gen_ld_data[acc_id][prt_id]["init_bal"]["debit"] = 0.0
  352. gen_ld_data[acc_id][prt_id]["fin_bal"] = {}
  353. gen_ld_data[acc_id][prt_id]["fin_bal"]["credit"] = 0.0
  354. gen_ld_data[acc_id][prt_id]["fin_bal"]["debit"] = 0.0
  355. gen_ld_data[acc_id][prt_id]["fin_bal"]["balance"] = 0.0
  356. if foreign_currency:
  357. gen_ld_data[acc_id][prt_id]["init_bal"]["bal_curr"] = 0.0
  358. gen_ld_data[acc_id][prt_id]["fin_bal"]["bal_curr"] = 0.0
  359. return gen_ld_data
  360. def _initialize_account(self, gen_ld_data, acc_id, foreign_currency):
  361. gen_ld_data[acc_id] = {}
  362. gen_ld_data[acc_id]["id"] = acc_id
  363. gen_ld_data[acc_id]["partners"] = False
  364. gen_ld_data[acc_id]["init_bal"] = {}
  365. gen_ld_data[acc_id]["init_bal"]["balance"] = 0.0
  366. gen_ld_data[acc_id]["init_bal"]["credit"] = 0.0
  367. gen_ld_data[acc_id]["init_bal"]["debit"] = 0.0
  368. gen_ld_data[acc_id]["fin_bal"] = {}
  369. gen_ld_data[acc_id]["fin_bal"]["credit"] = 0.0
  370. gen_ld_data[acc_id]["fin_bal"]["debit"] = 0.0
  371. gen_ld_data[acc_id]["fin_bal"]["balance"] = 0.0
  372. if foreign_currency:
  373. gen_ld_data[acc_id]["init_bal"]["bal_curr"] = 0.0
  374. gen_ld_data[acc_id]["fin_bal"]["bal_curr"] = 0.0
  375. return gen_ld_data
  376. def _get_reconciled_after_date_to_ids(self, full_reconcile_ids, date_to):
  377. full_reconcile_ids = list(full_reconcile_ids)
  378. domain = [
  379. ("max_date", ">", date_to),
  380. ("full_reconcile_id", "in", full_reconcile_ids),
  381. ]
  382. fields = ["full_reconcile_id"]
  383. reconciled_after_date_to = self.env["account.partial.reconcile"].search_read(
  384. domain=domain, fields=fields
  385. )
  386. rec_after_date_to_ids = list(
  387. map(operator.itemgetter("full_reconcile_id"), reconciled_after_date_to)
  388. )
  389. rec_after_date_to_ids = [i[0] for i in rec_after_date_to_ids]
  390. return rec_after_date_to_ids
  391. def _get_period_ml_data(
  392. self,
  393. account_ids,
  394. partner_ids,
  395. company_id,
  396. foreign_currency,
  397. only_posted_moves,
  398. date_from,
  399. date_to,
  400. partners_data,
  401. gen_ld_data,
  402. partners_ids,
  403. analytic_tag_ids,
  404. cost_center_ids,
  405. extra_domain,
  406. ):
  407. domain = self._get_period_domain(
  408. account_ids,
  409. partner_ids,
  410. company_id,
  411. only_posted_moves,
  412. date_to,
  413. date_from,
  414. analytic_tag_ids,
  415. cost_center_ids,
  416. )
  417. if extra_domain:
  418. domain += extra_domain
  419. ml_fields = [
  420. "id",
  421. "name",
  422. "date",
  423. "move_id",
  424. "journal_id",
  425. "account_id",
  426. "partner_id",
  427. "debit",
  428. "credit",
  429. "balance",
  430. "currency_id",
  431. "full_reconcile_id",
  432. "tax_ids",
  433. "analytic_tag_ids",
  434. "amount_currency",
  435. "ref",
  436. "name",
  437. "analytic_account_id",
  438. ]
  439. move_lines = self.env["account.move.line"].search_read(
  440. domain=domain, fields=ml_fields
  441. )
  442. journal_ids = set()
  443. full_reconcile_ids = set()
  444. taxes_ids = set()
  445. tags_ids = set()
  446. full_reconcile_data = {}
  447. acc_prt_account_ids = self._get_acc_prt_accounts_ids(company_id)
  448. for move_line in move_lines:
  449. journal_ids.add(move_line["journal_id"][0])
  450. for tax_id in move_line["tax_ids"]:
  451. taxes_ids.add(tax_id)
  452. for analytic_tag_id in move_line["analytic_tag_ids"]:
  453. tags_ids.add(analytic_tag_id)
  454. if move_line["full_reconcile_id"]:
  455. rec_id = move_line["full_reconcile_id"][0]
  456. if rec_id not in full_reconcile_ids:
  457. full_reconcile_data.update(
  458. {
  459. rec_id: {
  460. "id": rec_id,
  461. "name": move_line["full_reconcile_id"][1],
  462. }
  463. }
  464. )
  465. full_reconcile_ids.add(rec_id)
  466. acc_id = move_line["account_id"][0]
  467. ml_id = move_line["id"]
  468. if move_line["partner_id"]:
  469. prt_id = move_line["partner_id"][0]
  470. partner_name = move_line["partner_id"][1]
  471. if acc_id not in gen_ld_data.keys():
  472. gen_ld_data = self._initialize_account(
  473. gen_ld_data, acc_id, foreign_currency
  474. )
  475. if acc_id in acc_prt_account_ids:
  476. if not move_line["partner_id"]:
  477. prt_id = 0
  478. partner_name = "Missing Partner"
  479. partners_ids.append(prt_id)
  480. partners_data.update({prt_id: {"id": prt_id, "name": partner_name}})
  481. if prt_id not in gen_ld_data[acc_id]:
  482. gen_ld_data = self._initialize_partner(
  483. gen_ld_data, acc_id, prt_id, foreign_currency
  484. )
  485. gen_ld_data[acc_id][prt_id][ml_id] = self._get_move_line_data(move_line)
  486. gen_ld_data[acc_id][prt_id]["fin_bal"]["credit"] += move_line["credit"]
  487. gen_ld_data[acc_id][prt_id]["fin_bal"]["debit"] += move_line["debit"]
  488. gen_ld_data[acc_id][prt_id]["fin_bal"]["balance"] += move_line[
  489. "balance"
  490. ]
  491. if foreign_currency:
  492. gen_ld_data[acc_id][prt_id]["fin_bal"]["bal_curr"] += move_line[
  493. "amount_currency"
  494. ]
  495. else:
  496. gen_ld_data[acc_id][ml_id] = self._get_move_line_data(move_line)
  497. gen_ld_data[acc_id]["fin_bal"]["credit"] += move_line["credit"]
  498. gen_ld_data[acc_id]["fin_bal"]["debit"] += move_line["debit"]
  499. gen_ld_data[acc_id]["fin_bal"]["balance"] += move_line["balance"]
  500. if foreign_currency:
  501. gen_ld_data[acc_id]["fin_bal"]["bal_curr"] += move_line[
  502. "amount_currency"
  503. ]
  504. journals_data = self._get_journals_data(list(journal_ids))
  505. accounts_data = self._get_accounts_data(gen_ld_data.keys())
  506. taxes_data = self._get_taxes_data(list(taxes_ids))
  507. tags_data = self._get_tags_data(list(tags_ids))
  508. rec_after_date_to_ids = self._get_reconciled_after_date_to_ids(
  509. full_reconcile_data.keys(), date_to
  510. )
  511. return (
  512. gen_ld_data,
  513. accounts_data,
  514. partners_data,
  515. journals_data,
  516. full_reconcile_data,
  517. taxes_data,
  518. tags_data,
  519. rec_after_date_to_ids,
  520. )
  521. @api.model
  522. def _recalculate_cumul_balance(
  523. self, move_lines, last_cumul_balance, rec_after_date_to_ids
  524. ):
  525. for move_line in move_lines:
  526. move_line["balance"] += last_cumul_balance
  527. last_cumul_balance = move_line["balance"]
  528. if move_line["rec_id"] in rec_after_date_to_ids:
  529. move_line["rec_name"] = "(" + _("future") + ") " + move_line["rec_name"]
  530. return move_lines
  531. def _create_account(self, account, acc_id, gen_led_data, rec_after_date_to_ids):
  532. move_lines = []
  533. for ml_id in gen_led_data[acc_id].keys():
  534. if not isinstance(ml_id, int):
  535. account.update({ml_id: gen_led_data[acc_id][ml_id]})
  536. else:
  537. move_lines += [gen_led_data[acc_id][ml_id]]
  538. move_lines = sorted(move_lines, key=lambda k: (k["date"]))
  539. move_lines = self._recalculate_cumul_balance(
  540. move_lines,
  541. gen_led_data[acc_id]["init_bal"]["balance"],
  542. rec_after_date_to_ids,
  543. )
  544. account.update({"move_lines": move_lines})
  545. return account
  546. def _create_account_not_show_partner(
  547. self, account, acc_id, gen_led_data, rec_after_date_to_ids
  548. ):
  549. move_lines = []
  550. for prt_id in gen_led_data[acc_id].keys():
  551. if not isinstance(prt_id, int):
  552. account.update({prt_id: gen_led_data[acc_id][prt_id]})
  553. else:
  554. for ml_id in gen_led_data[acc_id][prt_id].keys():
  555. if isinstance(ml_id, int):
  556. move_lines += [gen_led_data[acc_id][prt_id][ml_id]]
  557. move_lines = sorted(move_lines, key=lambda k: (k["date"]))
  558. move_lines = self._recalculate_cumul_balance(
  559. move_lines,
  560. gen_led_data[acc_id]["init_bal"]["balance"],
  561. rec_after_date_to_ids,
  562. )
  563. account.update({"move_lines": move_lines, "partners": False})
  564. return account
  565. def _create_general_ledger(
  566. self,
  567. gen_led_data,
  568. accounts_data,
  569. show_partner_details,
  570. rec_after_date_to_ids,
  571. hide_account_at_0,
  572. ):
  573. general_ledger = []
  574. rounding = self.env.company.currency_id.rounding
  575. for acc_id in gen_led_data.keys():
  576. account = {}
  577. account.update(
  578. {
  579. "code": accounts_data[acc_id]["code"],
  580. "name": accounts_data[acc_id]["name"],
  581. "type": "account",
  582. "currency_id": accounts_data[acc_id]["currency_id"],
  583. "centralized": accounts_data[acc_id]["centralized"],
  584. }
  585. )
  586. if not gen_led_data[acc_id]["partners"]:
  587. account = self._create_account(
  588. account, acc_id, gen_led_data, rec_after_date_to_ids
  589. )
  590. if (
  591. hide_account_at_0
  592. and float_is_zero(
  593. gen_led_data[acc_id]["init_bal"]["balance"],
  594. precision_rounding=rounding,
  595. )
  596. and account["move_lines"] == []
  597. ):
  598. continue
  599. else:
  600. if show_partner_details:
  601. list_partner = []
  602. for prt_id in gen_led_data[acc_id].keys():
  603. partner = {}
  604. move_lines = []
  605. if not isinstance(prt_id, int):
  606. account.update({prt_id: gen_led_data[acc_id][prt_id]})
  607. else:
  608. for ml_id in gen_led_data[acc_id][prt_id].keys():
  609. if not isinstance(ml_id, int):
  610. partner.update(
  611. {ml_id: gen_led_data[acc_id][prt_id][ml_id]}
  612. )
  613. else:
  614. move_lines += [gen_led_data[acc_id][prt_id][ml_id]]
  615. move_lines = sorted(move_lines, key=lambda k: (k["date"]))
  616. move_lines = self._recalculate_cumul_balance(
  617. move_lines,
  618. gen_led_data[acc_id][prt_id]["init_bal"]["balance"],
  619. rec_after_date_to_ids,
  620. )
  621. partner.update({"move_lines": move_lines})
  622. if (
  623. hide_account_at_0
  624. and float_is_zero(
  625. gen_led_data[acc_id][prt_id]["init_bal"]["balance"],
  626. precision_rounding=rounding,
  627. )
  628. and partner["move_lines"] == []
  629. ):
  630. continue
  631. list_partner += [partner]
  632. account.update({"list_partner": list_partner})
  633. if (
  634. hide_account_at_0
  635. and float_is_zero(
  636. gen_led_data[acc_id]["init_bal"]["balance"],
  637. precision_rounding=rounding,
  638. )
  639. and account["list_partner"] == []
  640. ):
  641. continue
  642. else:
  643. account = self._create_account_not_show_partner(
  644. account, acc_id, gen_led_data, rec_after_date_to_ids
  645. )
  646. if (
  647. hide_account_at_0
  648. and float_is_zero(
  649. gen_led_data[acc_id]["init_bal"]["balance"],
  650. precision_rounding=rounding,
  651. )
  652. and account["move_lines"] == []
  653. ):
  654. continue
  655. general_ledger += [account]
  656. return general_ledger
  657. @api.model
  658. def _calculate_centralization(self, centralized_ml, move_line, date_to):
  659. jnl_id = move_line["journal_id"]
  660. month = move_line["date"].month
  661. if jnl_id not in centralized_ml.keys():
  662. centralized_ml[jnl_id] = {}
  663. if month not in centralized_ml[jnl_id].keys():
  664. centralized_ml[jnl_id][month] = {}
  665. last_day_month = calendar.monthrange(move_line["date"].year, month)
  666. date = datetime.date(move_line["date"].year, month, last_day_month[1])
  667. if date > date_to:
  668. date = date_to
  669. centralized_ml[jnl_id][month].update(
  670. {
  671. "journal_id": jnl_id,
  672. "ref_label": "Centralized entries",
  673. "date": date,
  674. "debit": 0.0,
  675. "credit": 0.0,
  676. "balance": 0.0,
  677. "bal_curr": 0.0,
  678. "partner_id": False,
  679. "rec_id": 0,
  680. "entry_id": False,
  681. "tax_ids": [],
  682. "full_reconcile_id": False,
  683. "id": False,
  684. "tag_ids": False,
  685. "currency_id": False,
  686. "analytic_account_id": False,
  687. }
  688. )
  689. centralized_ml[jnl_id][month]["debit"] += move_line["debit"]
  690. centralized_ml[jnl_id][month]["credit"] += move_line["credit"]
  691. centralized_ml[jnl_id][month]["balance"] += (
  692. move_line["debit"] - move_line["credit"]
  693. )
  694. centralized_ml[jnl_id][month]["bal_curr"] += move_line["bal_curr"]
  695. return centralized_ml
  696. @api.model
  697. def _get_centralized_ml(self, account, date_to):
  698. centralized_ml = {}
  699. if isinstance(date_to, str):
  700. date_to = datetime.datetime.strptime(date_to, "%Y-%m-%d").date()
  701. if account["partners"]:
  702. for partner in account["list_partner"]:
  703. for move_line in partner["move_lines"]:
  704. centralized_ml = self._calculate_centralization(
  705. centralized_ml, move_line, date_to,
  706. )
  707. else:
  708. for move_line in account["move_lines"]:
  709. centralized_ml = self._calculate_centralization(
  710. centralized_ml, move_line, date_to,
  711. )
  712. list_centralized_ml = []
  713. for jnl_id in centralized_ml.keys():
  714. list_centralized_ml += list(centralized_ml[jnl_id].values())
  715. return list_centralized_ml
  716. def _get_report_values(self, docids, data):
  717. wizard_id = data["wizard_id"]
  718. company = self.env["res.company"].browse(data["company_id"])
  719. company_id = data["company_id"]
  720. date_to = data["date_to"]
  721. date_from = data["date_from"]
  722. partner_ids = data["partner_ids"]
  723. if not partner_ids:
  724. filter_partner_ids = False
  725. else:
  726. filter_partner_ids = True
  727. account_ids = data["account_ids"]
  728. analytic_tag_ids = data["analytic_tag_ids"]
  729. cost_center_ids = data["cost_center_ids"]
  730. show_partner_details = data["show_partner_details"]
  731. hide_account_at_0 = data["hide_account_at_0"]
  732. foreign_currency = data["foreign_currency"]
  733. only_posted_moves = data["only_posted_moves"]
  734. unaffected_earnings_account = data["unaffected_earnings_account"]
  735. fy_start_date = data["fy_start_date"]
  736. extra_domain = data["domain"]
  737. gen_ld_data, partners_data, partners_ids = self._get_initial_balance_data(
  738. account_ids,
  739. partner_ids,
  740. company_id,
  741. date_from,
  742. foreign_currency,
  743. only_posted_moves,
  744. unaffected_earnings_account,
  745. fy_start_date,
  746. analytic_tag_ids,
  747. cost_center_ids,
  748. extra_domain,
  749. )
  750. centralize = data["centralize"]
  751. (
  752. gen_ld_data,
  753. accounts_data,
  754. partners_data,
  755. journals_data,
  756. full_reconcile_data,
  757. taxes_data,
  758. tags_data,
  759. rec_after_date_to_ids,
  760. ) = self._get_period_ml_data(
  761. account_ids,
  762. partner_ids,
  763. company_id,
  764. foreign_currency,
  765. only_posted_moves,
  766. date_from,
  767. date_to,
  768. partners_data,
  769. gen_ld_data,
  770. partners_ids,
  771. analytic_tag_ids,
  772. cost_center_ids,
  773. extra_domain,
  774. )
  775. general_ledger = self._create_general_ledger(
  776. gen_ld_data,
  777. accounts_data,
  778. show_partner_details,
  779. rec_after_date_to_ids,
  780. hide_account_at_0,
  781. )
  782. if centralize:
  783. for account in general_ledger:
  784. if account["centralized"]:
  785. centralized_ml = self._get_centralized_ml(account, date_to)
  786. account["move_lines"] = centralized_ml
  787. account["move_lines"] = self._recalculate_cumul_balance(
  788. account["move_lines"],
  789. gen_ld_data[account["id"]]["init_bal"]["balance"],
  790. rec_after_date_to_ids,
  791. )
  792. if account["partners"]:
  793. account["partners"] = False
  794. del account["list_partner"]
  795. general_ledger = sorted(general_ledger, key=lambda k: k["code"])
  796. return {
  797. "doc_ids": [wizard_id],
  798. "doc_model": "general.ledger.report.wizard",
  799. "docs": self.env["general.ledger.report.wizard"].browse(wizard_id),
  800. "foreign_currency": data["foreign_currency"],
  801. "company_name": company.display_name,
  802. "company_currency": company.currency_id,
  803. "currency_name": company.currency_id.name,
  804. "date_from": data["date_from"],
  805. "date_to": data["date_to"],
  806. "only_posted_moves": data["only_posted_moves"],
  807. "hide_account_at_0": data["hide_account_at_0"],
  808. "show_analytic_tags": data["show_analytic_tags"],
  809. "show_cost_center": data["show_cost_center"],
  810. "general_ledger": general_ledger,
  811. "accounts_data": accounts_data,
  812. "partners_data": partners_data,
  813. "journals_data": journals_data,
  814. "full_reconcile_data": full_reconcile_data,
  815. "taxes_data": taxes_data,
  816. "centralize": centralize,
  817. "tags_data": tags_data,
  818. "filter_partner_ids": filter_partner_ids,
  819. }