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.

870 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. base_domain = []
  173. if company_id:
  174. base_domain += [("company_id", "=", company_id)]
  175. if partner_ids:
  176. base_domain += [("partner_id", "in", partner_ids)]
  177. if only_posted_moves:
  178. base_domain += [("move_id.state", "=", "posted")]
  179. if analytic_tag_ids:
  180. base_domain += [("analytic_tag_ids", "in", analytic_tag_ids)]
  181. if cost_center_ids:
  182. base_domain += [("analytic_account_id", "in", cost_center_ids)]
  183. if extra_domain:
  184. base_domain += extra_domain
  185. initial_domain_bs = self._get_initial_balances_bs_ml_domain(
  186. account_ids, company_id, date_from, base_domain
  187. )
  188. initial_domain_pl = self._get_initial_balances_pl_ml_domain(
  189. account_ids, company_id, date_from, fy_start_date, base_domain
  190. )
  191. gl_initial_acc = self._get_accounts_initial_balance(
  192. initial_domain_bs, initial_domain_pl
  193. )
  194. initial_domain_acc_prt = self._get_initial_balances_bs_ml_domain(
  195. account_ids, company_id, date_from, base_domain, acc_prt=True
  196. )
  197. gl_initial_acc_prt = self.env["account.move.line"].read_group(
  198. domain=initial_domain_acc_prt,
  199. fields=[
  200. "account_id",
  201. "partner_id",
  202. "debit",
  203. "credit",
  204. "balance",
  205. "amount_currency",
  206. ],
  207. groupby=["account_id", "partner_id"],
  208. lazy=False,
  209. )
  210. gen_ld_data = {}
  211. for gl in gl_initial_acc:
  212. acc_id = gl["account_id"][0]
  213. gen_ld_data[acc_id] = {}
  214. gen_ld_data[acc_id]["id"] = acc_id
  215. gen_ld_data[acc_id]["partners"] = False
  216. gen_ld_data[acc_id]["init_bal"] = {}
  217. gen_ld_data[acc_id]["init_bal"]["credit"] = gl["credit"]
  218. gen_ld_data[acc_id]["init_bal"]["debit"] = gl["debit"]
  219. gen_ld_data[acc_id]["init_bal"]["balance"] = gl["balance"]
  220. gen_ld_data[acc_id]["fin_bal"] = {}
  221. gen_ld_data[acc_id]["fin_bal"]["credit"] = gl["credit"]
  222. gen_ld_data[acc_id]["fin_bal"]["debit"] = gl["debit"]
  223. gen_ld_data[acc_id]["fin_bal"]["balance"] = gl["balance"]
  224. gen_ld_data[acc_id]["init_bal"]["bal_curr"] = gl["amount_currency"]
  225. gen_ld_data[acc_id]["fin_bal"]["bal_curr"] = gl["amount_currency"]
  226. partners_data = {}
  227. partners_ids = set()
  228. if gl_initial_acc_prt:
  229. for gl in gl_initial_acc_prt:
  230. if not gl["partner_id"]:
  231. prt_id = 0
  232. prt_name = "Missing Partner"
  233. else:
  234. prt_id = gl["partner_id"][0]
  235. prt_name = gl["partner_id"][1]
  236. prt_name = prt_name._value
  237. if prt_id not in partners_ids:
  238. partners_ids.add(prt_id)
  239. partners_data.update({prt_id: {"id": prt_id, "name": prt_name}})
  240. acc_id = gl["account_id"][0]
  241. gen_ld_data[acc_id][prt_id] = {}
  242. gen_ld_data[acc_id][prt_id]["id"] = prt_id
  243. gen_ld_data[acc_id]["partners"] = True
  244. gen_ld_data[acc_id][prt_id]["init_bal"] = {}
  245. gen_ld_data[acc_id][prt_id]["init_bal"]["credit"] = gl["credit"]
  246. gen_ld_data[acc_id][prt_id]["init_bal"]["debit"] = gl["debit"]
  247. gen_ld_data[acc_id][prt_id]["init_bal"]["balance"] = gl["balance"]
  248. gen_ld_data[acc_id][prt_id]["fin_bal"] = {}
  249. gen_ld_data[acc_id][prt_id]["fin_bal"]["credit"] = gl["credit"]
  250. gen_ld_data[acc_id][prt_id]["fin_bal"]["debit"] = gl["debit"]
  251. gen_ld_data[acc_id][prt_id]["fin_bal"]["balance"] = gl["balance"]
  252. gen_ld_data[acc_id][prt_id]["init_bal"]["bal_curr"] = gl[
  253. "amount_currency"
  254. ]
  255. gen_ld_data[acc_id][prt_id]["fin_bal"]["bal_curr"] = gl[
  256. "amount_currency"
  257. ]
  258. accounts_ids = list(gen_ld_data.keys())
  259. unaffected_id = unaffected_earnings_account
  260. if unaffected_id not in accounts_ids:
  261. accounts_ids.append(unaffected_id)
  262. self._initialize_account(gen_ld_data, unaffected_id, foreign_currency)
  263. pl_initial_balance = self._get_pl_initial_balance(
  264. account_ids, company_id, fy_start_date, foreign_currency, base_domain
  265. )
  266. gen_ld_data[unaffected_id]["init_bal"]["debit"] += pl_initial_balance["debit"]
  267. gen_ld_data[unaffected_id]["init_bal"]["credit"] += pl_initial_balance["credit"]
  268. gen_ld_data[unaffected_id]["init_bal"]["balance"] += pl_initial_balance[
  269. "balance"
  270. ]
  271. gen_ld_data[unaffected_id]["fin_bal"]["debit"] += pl_initial_balance["debit"]
  272. gen_ld_data[unaffected_id]["fin_bal"]["credit"] += pl_initial_balance["credit"]
  273. gen_ld_data[unaffected_id]["fin_bal"]["balance"] += pl_initial_balance[
  274. "balance"
  275. ]
  276. if foreign_currency:
  277. gen_ld_data[unaffected_id]["init_bal"]["bal_curr"] += pl_initial_balance[
  278. "bal_curr"
  279. ]
  280. gen_ld_data[unaffected_id]["fin_bal"]["bal_curr"] += pl_initial_balance[
  281. "bal_curr"
  282. ]
  283. return gen_ld_data, partners_data, partner_ids
  284. @api.model
  285. def _get_move_line_data(self, move_line):
  286. move_line_data = {
  287. "id": move_line["id"],
  288. "date": move_line["date"],
  289. "entry": move_line["move_id"][1],
  290. "entry_id": move_line["move_id"][0],
  291. "journal_id": move_line["journal_id"][0],
  292. "account_id": move_line["account_id"][0],
  293. "partner_id": move_line["partner_id"][0]
  294. if move_line["partner_id"]
  295. else False,
  296. "partner_name": move_line["partner_id"][1]
  297. if move_line["partner_id"]
  298. else "",
  299. "ref": "" if not move_line["ref"] else move_line["ref"],
  300. "name": "" if not move_line["name"] else move_line["name"],
  301. "tax_ids": move_line["tax_ids"],
  302. "debit": move_line["debit"],
  303. "credit": move_line["credit"],
  304. "balance": move_line["balance"],
  305. "bal_curr": move_line["amount_currency"],
  306. "rec_id": move_line["full_reconcile_id"][0]
  307. if move_line["full_reconcile_id"]
  308. else False,
  309. "rec_name": move_line["full_reconcile_id"][1]
  310. if move_line["full_reconcile_id"]
  311. else "",
  312. "tag_ids": move_line["analytic_tag_ids"],
  313. "currency_id": move_line["currency_id"],
  314. "analytic_account": move_line["analytic_account_id"][1]
  315. if move_line["analytic_account_id"]
  316. else "",
  317. "analytic_account_id": move_line["analytic_account_id"][0]
  318. if move_line["analytic_account_id"]
  319. else False,
  320. }
  321. if (
  322. move_line_data["ref"] == move_line_data["name"]
  323. or move_line_data["ref"] == ""
  324. ):
  325. ref_label = move_line_data["name"]
  326. elif move_line_data["name"] == "":
  327. ref_label = move_line_data["ref"]
  328. else:
  329. ref_label = move_line_data["ref"] + str(" - ") + move_line_data["name"]
  330. move_line_data.update({"ref_label": ref_label})
  331. return move_line_data
  332. @api.model
  333. def _get_period_domain(
  334. self,
  335. account_ids,
  336. partner_ids,
  337. company_id,
  338. only_posted_moves,
  339. date_to,
  340. date_from,
  341. analytic_tag_ids,
  342. cost_center_ids,
  343. ):
  344. domain = [
  345. ("display_type", "=", False),
  346. ("date", ">=", date_from),
  347. ("date", "<=", date_to),
  348. ]
  349. if account_ids:
  350. domain += [("account_id", "in", account_ids)]
  351. if company_id:
  352. domain += [("company_id", "=", company_id)]
  353. if partner_ids:
  354. domain += [("partner_id", "in", partner_ids)]
  355. if only_posted_moves:
  356. domain += [("move_id.state", "=", "posted")]
  357. if analytic_tag_ids:
  358. domain += [("analytic_tag_ids", "in", analytic_tag_ids)]
  359. if cost_center_ids:
  360. domain += [("analytic_account_id", "in", cost_center_ids)]
  361. return domain
  362. @api.model
  363. def _initialize_partner(self, gen_ld_data, acc_id, prt_id, foreign_currency):
  364. gen_ld_data[acc_id]["partners"] = True
  365. gen_ld_data[acc_id][prt_id] = {}
  366. gen_ld_data[acc_id][prt_id]["id"] = prt_id
  367. gen_ld_data[acc_id][prt_id]["init_bal"] = {}
  368. gen_ld_data[acc_id][prt_id]["init_bal"]["balance"] = 0.0
  369. gen_ld_data[acc_id][prt_id]["init_bal"]["credit"] = 0.0
  370. gen_ld_data[acc_id][prt_id]["init_bal"]["debit"] = 0.0
  371. gen_ld_data[acc_id][prt_id]["fin_bal"] = {}
  372. gen_ld_data[acc_id][prt_id]["fin_bal"]["credit"] = 0.0
  373. gen_ld_data[acc_id][prt_id]["fin_bal"]["debit"] = 0.0
  374. gen_ld_data[acc_id][prt_id]["fin_bal"]["balance"] = 0.0
  375. if foreign_currency:
  376. gen_ld_data[acc_id][prt_id]["init_bal"]["bal_curr"] = 0.0
  377. gen_ld_data[acc_id][prt_id]["fin_bal"]["bal_curr"] = 0.0
  378. return gen_ld_data
  379. def _initialize_account(self, gen_ld_data, acc_id, foreign_currency):
  380. gen_ld_data[acc_id] = {}
  381. gen_ld_data[acc_id]["id"] = acc_id
  382. gen_ld_data[acc_id]["partners"] = False
  383. gen_ld_data[acc_id]["init_bal"] = {}
  384. gen_ld_data[acc_id]["init_bal"]["balance"] = 0.0
  385. gen_ld_data[acc_id]["init_bal"]["credit"] = 0.0
  386. gen_ld_data[acc_id]["init_bal"]["debit"] = 0.0
  387. gen_ld_data[acc_id]["fin_bal"] = {}
  388. gen_ld_data[acc_id]["fin_bal"]["credit"] = 0.0
  389. gen_ld_data[acc_id]["fin_bal"]["debit"] = 0.0
  390. gen_ld_data[acc_id]["fin_bal"]["balance"] = 0.0
  391. if foreign_currency:
  392. gen_ld_data[acc_id]["init_bal"]["bal_curr"] = 0.0
  393. gen_ld_data[acc_id]["fin_bal"]["bal_curr"] = 0.0
  394. return gen_ld_data
  395. def _get_reconciled_after_date_to_ids(self, full_reconcile_ids, date_to):
  396. full_reconcile_ids = list(full_reconcile_ids)
  397. domain = [
  398. ("max_date", ">", date_to),
  399. ("full_reconcile_id", "in", full_reconcile_ids),
  400. ]
  401. fields = ["full_reconcile_id"]
  402. reconciled_after_date_to = self.env["account.partial.reconcile"].search_read(
  403. domain=domain, fields=fields
  404. )
  405. rec_after_date_to_ids = list(
  406. map(operator.itemgetter("full_reconcile_id"), reconciled_after_date_to)
  407. )
  408. rec_after_date_to_ids = [i[0] for i in rec_after_date_to_ids]
  409. return rec_after_date_to_ids
  410. def _get_period_ml_data(
  411. self,
  412. account_ids,
  413. partner_ids,
  414. company_id,
  415. foreign_currency,
  416. only_posted_moves,
  417. date_from,
  418. date_to,
  419. partners_data,
  420. gen_ld_data,
  421. partners_ids,
  422. analytic_tag_ids,
  423. cost_center_ids,
  424. extra_domain,
  425. ):
  426. domain = self._get_period_domain(
  427. account_ids,
  428. partner_ids,
  429. company_id,
  430. only_posted_moves,
  431. date_to,
  432. date_from,
  433. analytic_tag_ids,
  434. cost_center_ids,
  435. )
  436. if extra_domain:
  437. domain += extra_domain
  438. ml_fields = [
  439. "id",
  440. "name",
  441. "date",
  442. "move_id",
  443. "journal_id",
  444. "account_id",
  445. "partner_id",
  446. "debit",
  447. "credit",
  448. "balance",
  449. "currency_id",
  450. "full_reconcile_id",
  451. "tax_ids",
  452. "analytic_tag_ids",
  453. "amount_currency",
  454. "ref",
  455. "name",
  456. "analytic_account_id",
  457. ]
  458. move_lines = self.env["account.move.line"].search_read(
  459. domain=domain, fields=ml_fields
  460. )
  461. journal_ids = set()
  462. full_reconcile_ids = set()
  463. taxes_ids = set()
  464. tags_ids = set()
  465. full_reconcile_data = {}
  466. acc_prt_account_ids = self._get_acc_prt_accounts_ids(company_id)
  467. for move_line in move_lines:
  468. journal_ids.add(move_line["journal_id"][0])
  469. for tax_id in move_line["tax_ids"]:
  470. taxes_ids.add(tax_id)
  471. for analytic_tag_id in move_line["analytic_tag_ids"]:
  472. tags_ids.add(analytic_tag_id)
  473. if move_line["full_reconcile_id"]:
  474. rec_id = move_line["full_reconcile_id"][0]
  475. if rec_id not in full_reconcile_ids:
  476. full_reconcile_data.update(
  477. {
  478. rec_id: {
  479. "id": rec_id,
  480. "name": move_line["full_reconcile_id"][1],
  481. }
  482. }
  483. )
  484. full_reconcile_ids.add(rec_id)
  485. acc_id = move_line["account_id"][0]
  486. ml_id = move_line["id"]
  487. if move_line["partner_id"]:
  488. prt_id = move_line["partner_id"][0]
  489. partner_name = move_line["partner_id"][1]
  490. if acc_id not in gen_ld_data.keys():
  491. gen_ld_data = self._initialize_account(
  492. gen_ld_data, acc_id, foreign_currency
  493. )
  494. if acc_id in acc_prt_account_ids:
  495. if not move_line["partner_id"]:
  496. prt_id = 0
  497. partner_name = "Missing Partner"
  498. partners_ids.append(prt_id)
  499. partners_data.update({prt_id: {"id": prt_id, "name": partner_name}})
  500. if prt_id not in gen_ld_data[acc_id]:
  501. gen_ld_data = self._initialize_partner(
  502. gen_ld_data, acc_id, prt_id, foreign_currency
  503. )
  504. gen_ld_data[acc_id][prt_id][ml_id] = self._get_move_line_data(move_line)
  505. gen_ld_data[acc_id][prt_id]["fin_bal"]["credit"] += move_line["credit"]
  506. gen_ld_data[acc_id][prt_id]["fin_bal"]["debit"] += move_line["debit"]
  507. gen_ld_data[acc_id][prt_id]["fin_bal"]["balance"] += move_line[
  508. "balance"
  509. ]
  510. if foreign_currency:
  511. gen_ld_data[acc_id][prt_id]["fin_bal"]["bal_curr"] += move_line[
  512. "amount_currency"
  513. ]
  514. else:
  515. gen_ld_data[acc_id][ml_id] = self._get_move_line_data(move_line)
  516. gen_ld_data[acc_id]["fin_bal"]["credit"] += move_line["credit"]
  517. gen_ld_data[acc_id]["fin_bal"]["debit"] += move_line["debit"]
  518. gen_ld_data[acc_id]["fin_bal"]["balance"] += move_line["balance"]
  519. if foreign_currency:
  520. gen_ld_data[acc_id]["fin_bal"]["bal_curr"] += move_line[
  521. "amount_currency"
  522. ]
  523. journals_data = self._get_journals_data(list(journal_ids))
  524. accounts_data = self._get_accounts_data(gen_ld_data.keys())
  525. taxes_data = self._get_taxes_data(list(taxes_ids))
  526. tags_data = self._get_tags_data(list(tags_ids))
  527. rec_after_date_to_ids = self._get_reconciled_after_date_to_ids(
  528. full_reconcile_data.keys(), date_to
  529. )
  530. return (
  531. gen_ld_data,
  532. accounts_data,
  533. partners_data,
  534. journals_data,
  535. full_reconcile_data,
  536. taxes_data,
  537. tags_data,
  538. rec_after_date_to_ids,
  539. )
  540. @api.model
  541. def _recalculate_cumul_balance(
  542. self, move_lines, last_cumul_balance, rec_after_date_to_ids
  543. ):
  544. for move_line in move_lines:
  545. move_line["balance"] += last_cumul_balance
  546. last_cumul_balance = move_line["balance"]
  547. if move_line["rec_id"] in rec_after_date_to_ids:
  548. move_line["rec_name"] = "(" + _("future") + ") " + move_line["rec_name"]
  549. return move_lines
  550. def _create_account(self, account, acc_id, gen_led_data, rec_after_date_to_ids):
  551. move_lines = []
  552. for ml_id in gen_led_data[acc_id].keys():
  553. if not isinstance(ml_id, int):
  554. account.update({ml_id: gen_led_data[acc_id][ml_id]})
  555. else:
  556. move_lines += [gen_led_data[acc_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})
  564. return account
  565. def _create_account_not_show_partner(
  566. self, account, acc_id, gen_led_data, rec_after_date_to_ids
  567. ):
  568. move_lines = []
  569. for prt_id in gen_led_data[acc_id].keys():
  570. if not isinstance(prt_id, int):
  571. account.update({prt_id: gen_led_data[acc_id][prt_id]})
  572. else:
  573. for ml_id in gen_led_data[acc_id][prt_id].keys():
  574. if isinstance(ml_id, int):
  575. move_lines += [gen_led_data[acc_id][prt_id][ml_id]]
  576. move_lines = sorted(move_lines, key=lambda k: (k["date"]))
  577. move_lines = self._recalculate_cumul_balance(
  578. move_lines,
  579. gen_led_data[acc_id]["init_bal"]["balance"],
  580. rec_after_date_to_ids,
  581. )
  582. account.update({"move_lines": move_lines, "partners": False})
  583. return account
  584. def _create_general_ledger(
  585. self,
  586. gen_led_data,
  587. accounts_data,
  588. show_partner_details,
  589. rec_after_date_to_ids,
  590. hide_account_at_0,
  591. ):
  592. general_ledger = []
  593. rounding = self.env.user.company_id.currency_id.rounding
  594. for acc_id in gen_led_data.keys():
  595. account = {}
  596. account.update(
  597. {
  598. "code": accounts_data[acc_id]["code"],
  599. "name": accounts_data[acc_id]["name"],
  600. "type": "account",
  601. "currency_id": accounts_data[acc_id]["currency_id"],
  602. "centralized": accounts_data[acc_id]["centralized"],
  603. }
  604. )
  605. if not gen_led_data[acc_id]["partners"]:
  606. account = self._create_account(
  607. account, acc_id, gen_led_data, rec_after_date_to_ids
  608. )
  609. if (
  610. hide_account_at_0
  611. and float_is_zero(
  612. gen_led_data[acc_id]["init_bal"]["balance"],
  613. precision_rounding=rounding,
  614. )
  615. and account["move_lines"] == []
  616. ):
  617. continue
  618. else:
  619. if show_partner_details:
  620. list_partner = []
  621. for prt_id in gen_led_data[acc_id].keys():
  622. partner = {}
  623. move_lines = []
  624. if not isinstance(prt_id, int):
  625. account.update({prt_id: gen_led_data[acc_id][prt_id]})
  626. else:
  627. for ml_id in gen_led_data[acc_id][prt_id].keys():
  628. if not isinstance(ml_id, int):
  629. partner.update(
  630. {ml_id: gen_led_data[acc_id][prt_id][ml_id]}
  631. )
  632. else:
  633. move_lines += [gen_led_data[acc_id][prt_id][ml_id]]
  634. move_lines = sorted(move_lines, key=lambda k: (k["date"]))
  635. move_lines = self._recalculate_cumul_balance(
  636. move_lines,
  637. gen_led_data[acc_id][prt_id]["init_bal"]["balance"],
  638. rec_after_date_to_ids,
  639. )
  640. partner.update({"move_lines": move_lines})
  641. if (
  642. hide_account_at_0
  643. and float_is_zero(
  644. gen_led_data[acc_id][prt_id]["init_bal"]["balance"],
  645. precision_rounding=rounding,
  646. )
  647. and partner["move_lines"] == []
  648. ):
  649. continue
  650. list_partner += [partner]
  651. account.update({"list_partner": list_partner})
  652. if (
  653. hide_account_at_0
  654. and float_is_zero(
  655. gen_led_data[acc_id]["init_bal"]["balance"],
  656. precision_rounding=rounding,
  657. )
  658. and account["list_partner"] == []
  659. ):
  660. continue
  661. else:
  662. account = self._create_account_not_show_partner(
  663. account, acc_id, gen_led_data, rec_after_date_to_ids
  664. )
  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["move_lines"] == []
  672. ):
  673. continue
  674. general_ledger += [account]
  675. return general_ledger
  676. @api.model
  677. def _calculate_centralization(self, centralized_ml, move_line, date_to):
  678. jnl_id = move_line["journal_id"]
  679. month = move_line["date"].month
  680. if jnl_id not in centralized_ml.keys():
  681. centralized_ml[jnl_id] = {}
  682. if month not in centralized_ml[jnl_id].keys():
  683. centralized_ml[jnl_id][month] = {}
  684. last_day_month = calendar.monthrange(move_line["date"].year, month)
  685. date = datetime.date(move_line["date"].year, month, last_day_month[1])
  686. if date > date_to:
  687. date = date_to
  688. centralized_ml[jnl_id][month].update(
  689. {
  690. "journal_id": jnl_id,
  691. "ref_label": "Centralized entries",
  692. "date": date,
  693. "debit": 0.0,
  694. "credit": 0.0,
  695. "balance": 0.0,
  696. "bal_curr": 0.0,
  697. "partner_id": False,
  698. "rec_id": 0,
  699. "entry_id": False,
  700. "tax_ids": [],
  701. "full_reconcile_id": False,
  702. "id": False,
  703. "tag_ids": False,
  704. "currency_id": False,
  705. "analytic_account_id": False,
  706. }
  707. )
  708. centralized_ml[jnl_id][month]["debit"] += move_line["debit"]
  709. centralized_ml[jnl_id][month]["credit"] += move_line["credit"]
  710. centralized_ml[jnl_id][month]["balance"] += (
  711. move_line["debit"] - move_line["credit"]
  712. )
  713. centralized_ml[jnl_id][month]["bal_curr"] += move_line["bal_curr"]
  714. return centralized_ml
  715. @api.model
  716. def _get_centralized_ml(self, account, date_to):
  717. centralized_ml = {}
  718. if isinstance(date_to, str):
  719. date_to = datetime.datetime.strptime(date_to, "%Y-%m-%d").date()
  720. if account["partners"]:
  721. for partner in account["list_partner"]:
  722. for move_line in partner["move_lines"]:
  723. centralized_ml = self._calculate_centralization(
  724. centralized_ml,
  725. move_line,
  726. date_to,
  727. )
  728. else:
  729. for move_line in account["move_lines"]:
  730. centralized_ml = self._calculate_centralization(
  731. centralized_ml,
  732. move_line,
  733. date_to,
  734. )
  735. list_centralized_ml = []
  736. for jnl_id in centralized_ml.keys():
  737. list_centralized_ml += list(centralized_ml[jnl_id].values())
  738. return list_centralized_ml
  739. def _get_report_values(self, docids, data):
  740. wizard_id = data["wizard_id"]
  741. company = self.env["res.company"].browse(data["company_id"])
  742. company_id = data["company_id"]
  743. date_to = data["date_to"]
  744. date_from = data["date_from"]
  745. partner_ids = data["partner_ids"]
  746. if not partner_ids:
  747. filter_partner_ids = False
  748. else:
  749. filter_partner_ids = True
  750. account_ids = data["account_ids"]
  751. analytic_tag_ids = data["analytic_tag_ids"]
  752. cost_center_ids = data["cost_center_ids"]
  753. show_partner_details = data["show_partner_details"]
  754. hide_account_at_0 = data["hide_account_at_0"]
  755. foreign_currency = data["foreign_currency"]
  756. only_posted_moves = data["only_posted_moves"]
  757. unaffected_earnings_account = data["unaffected_earnings_account"]
  758. fy_start_date = data["fy_start_date"]
  759. extra_domain = data["domain"]
  760. gen_ld_data, partners_data, partners_ids = self._get_initial_balance_data(
  761. account_ids,
  762. partner_ids,
  763. company_id,
  764. date_from,
  765. foreign_currency,
  766. only_posted_moves,
  767. unaffected_earnings_account,
  768. fy_start_date,
  769. analytic_tag_ids,
  770. cost_center_ids,
  771. extra_domain,
  772. )
  773. centralize = data["centralize"]
  774. (
  775. gen_ld_data,
  776. accounts_data,
  777. partners_data,
  778. journals_data,
  779. full_reconcile_data,
  780. taxes_data,
  781. tags_data,
  782. rec_after_date_to_ids,
  783. ) = self._get_period_ml_data(
  784. account_ids,
  785. partner_ids,
  786. company_id,
  787. foreign_currency,
  788. only_posted_moves,
  789. date_from,
  790. date_to,
  791. partners_data,
  792. gen_ld_data,
  793. partners_ids,
  794. analytic_tag_ids,
  795. cost_center_ids,
  796. extra_domain,
  797. )
  798. general_ledger = self._create_general_ledger(
  799. gen_ld_data,
  800. accounts_data,
  801. show_partner_details,
  802. rec_after_date_to_ids,
  803. hide_account_at_0,
  804. )
  805. if centralize:
  806. for account in general_ledger:
  807. if account["centralized"]:
  808. centralized_ml = self._get_centralized_ml(account, date_to)
  809. account["move_lines"] = centralized_ml
  810. account["move_lines"] = self._recalculate_cumul_balance(
  811. account["move_lines"],
  812. gen_ld_data[account["id"]]["init_bal"]["balance"],
  813. rec_after_date_to_ids,
  814. )
  815. if account["partners"]:
  816. account["partners"] = False
  817. del account["list_partner"]
  818. general_ledger = sorted(general_ledger, key=lambda k: k["code"])
  819. return {
  820. "doc_ids": [wizard_id],
  821. "doc_model": "general.ledger.report.wizard",
  822. "docs": self.env["general.ledger.report.wizard"].browse(wizard_id),
  823. "foreign_currency": data["foreign_currency"],
  824. "company_name": company.display_name,
  825. "company_currency": company.currency_id,
  826. "currency_name": company.currency_id.name,
  827. "date_from": data["date_from"],
  828. "date_to": data["date_to"],
  829. "only_posted_moves": data["only_posted_moves"],
  830. "hide_account_at_0": data["hide_account_at_0"],
  831. "show_analytic_tags": data["show_analytic_tags"],
  832. "show_cost_center": data["show_cost_center"],
  833. "general_ledger": general_ledger,
  834. "accounts_data": accounts_data,
  835. "partners_data": partners_data,
  836. "journals_data": journals_data,
  837. "full_reconcile_data": full_reconcile_data,
  838. "taxes_data": taxes_data,
  839. "centralize": centralize,
  840. "tags_data": tags_data,
  841. "filter_partner_ids": filter_partner_ids,
  842. }