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.

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