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