odoo-addon-account-financial-report 15.0.1.1.0.1__py3-none-any.whl → 18.0.1.4.4.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. odoo/addons/account_financial_report/README.rst +131 -74
  2. odoo/addons/account_financial_report/__manifest__.py +6 -9
  3. odoo/addons/account_financial_report/i18n/account_financial_report.pot +313 -188
  4. odoo/addons/account_financial_report/i18n/ar.po +579 -433
  5. odoo/addons/account_financial_report/i18n/ca.po +474 -289
  6. odoo/addons/account_financial_report/i18n/{fr_FR.po → ca_AD.po} +539 -491
  7. odoo/addons/account_financial_report/i18n/ca_ES.po +1891 -0
  8. odoo/addons/account_financial_report/i18n/de.po +455 -295
  9. odoo/addons/account_financial_report/i18n/es.po +458 -394
  10. odoo/addons/account_financial_report/i18n/es_AR.po +464 -283
  11. odoo/addons/account_financial_report/i18n/es_MX.po +315 -220
  12. odoo/addons/account_financial_report/i18n/fr.po +620 -435
  13. odoo/addons/account_financial_report/i18n/fr_CH.po +616 -462
  14. odoo/addons/account_financial_report/i18n/hr.po +506 -355
  15. odoo/addons/account_financial_report/i18n/hr_HR.po +331 -232
  16. odoo/addons/account_financial_report/i18n/it.po +538 -356
  17. odoo/addons/account_financial_report/i18n/ja.po +339 -240
  18. odoo/addons/account_financial_report/i18n/nl.po +462 -324
  19. odoo/addons/account_financial_report/i18n/nl_NL.po +318 -220
  20. odoo/addons/account_financial_report/i18n/pt.po +429 -242
  21. odoo/addons/account_financial_report/i18n/pt_BR.po +588 -438
  22. odoo/addons/account_financial_report/i18n/ro.po +499 -342
  23. odoo/addons/account_financial_report/i18n/sl.po +1945 -0
  24. odoo/addons/account_financial_report/i18n/sv.po +1997 -0
  25. odoo/addons/account_financial_report/i18n/tr.po +1947 -0
  26. odoo/addons/account_financial_report/menuitems.xml +1 -1
  27. odoo/addons/account_financial_report/models/__init__.py +2 -0
  28. odoo/addons/account_financial_report/models/account_age_report_configuration.py +49 -0
  29. odoo/addons/account_financial_report/models/account_group.py +62 -23
  30. odoo/addons/account_financial_report/models/account_move_line.py +33 -3
  31. odoo/addons/account_financial_report/models/ir_actions_report.py +6 -4
  32. odoo/addons/account_financial_report/models/res_config_settings.py +36 -0
  33. odoo/addons/account_financial_report/readme/CONFIGURE.md +26 -0
  34. odoo/addons/account_financial_report/readme/CONTRIBUTORS.md +38 -0
  35. odoo/addons/account_financial_report/readme/CREDITS.md +1 -0
  36. odoo/addons/account_financial_report/readme/DESCRIPTION.md +21 -0
  37. odoo/addons/account_financial_report/readme/HISTORY.md +16 -0
  38. odoo/addons/account_financial_report/readme/ROADMAP.md +6 -0
  39. odoo/addons/account_financial_report/report/abstract_report.py +73 -23
  40. odoo/addons/account_financial_report/report/abstract_report_xlsx.py +28 -23
  41. odoo/addons/account_financial_report/report/aged_partner_balance.py +131 -30
  42. odoo/addons/account_financial_report/report/aged_partner_balance_xlsx.py +158 -118
  43. odoo/addons/account_financial_report/report/general_ledger.py +421 -340
  44. odoo/addons/account_financial_report/report/general_ledger_xlsx.py +127 -75
  45. odoo/addons/account_financial_report/report/journal_ledger.py +84 -68
  46. odoo/addons/account_financial_report/report/journal_ledger_xlsx.py +14 -8
  47. odoo/addons/account_financial_report/report/open_items.py +113 -70
  48. odoo/addons/account_financial_report/report/open_items_xlsx.py +152 -19
  49. odoo/addons/account_financial_report/report/templates/aged_partner_balance.xml +408 -311
  50. odoo/addons/account_financial_report/report/templates/general_ledger.xml +273 -213
  51. odoo/addons/account_financial_report/report/templates/journal_ledger.xml +70 -76
  52. odoo/addons/account_financial_report/report/templates/layouts.xml +12 -1
  53. odoo/addons/account_financial_report/report/templates/open_items.xml +181 -55
  54. odoo/addons/account_financial_report/report/templates/trial_balance.xml +304 -195
  55. odoo/addons/account_financial_report/report/templates/vat_report.xml +10 -10
  56. odoo/addons/account_financial_report/report/trial_balance.py +463 -211
  57. odoo/addons/account_financial_report/report/trial_balance_xlsx.py +37 -38
  58. odoo/addons/account_financial_report/report/vat_report.py +36 -25
  59. odoo/addons/account_financial_report/report/vat_report_xlsx.py +1 -1
  60. odoo/addons/account_financial_report/security/ir.model.access.csv +2 -0
  61. odoo/addons/account_financial_report/security/security.xml +8 -0
  62. odoo/addons/account_financial_report/static/description/index.html +106 -55
  63. odoo/addons/account_financial_report/static/src/css/report.css +77 -42
  64. odoo/addons/account_financial_report/static/src/css/report_html.css +10 -0
  65. odoo/addons/account_financial_report/static/src/js/report.esm.js +72 -0
  66. odoo/addons/account_financial_report/static/src/js/report_action.esm.js +39 -0
  67. odoo/addons/account_financial_report/static/src/xml/report.xml +10 -9
  68. odoo/addons/account_financial_report/tests/__init__.py +1 -0
  69. odoo/addons/account_financial_report/tests/test_age_report_configuration.py +42 -0
  70. odoo/addons/account_financial_report/tests/test_aged_partner_balance.py +99 -9
  71. odoo/addons/account_financial_report/tests/test_general_ledger.py +19 -9
  72. odoo/addons/account_financial_report/tests/test_journal_ledger.py +18 -9
  73. odoo/addons/account_financial_report/tests/test_open_items.py +42 -2
  74. odoo/addons/account_financial_report/tests/test_trial_balance.py +114 -223
  75. odoo/addons/account_financial_report/tests/test_vat_report.py +17 -9
  76. odoo/addons/account_financial_report/view/account_age_report_configuration_views.xml +41 -0
  77. odoo/addons/account_financial_report/view/res_config_settings_views.xml +51 -0
  78. odoo/addons/account_financial_report/wizard/abstract_wizard.py +23 -0
  79. odoo/addons/account_financial_report/wizard/aged_partner_balance_wizard.py +22 -8
  80. odoo/addons/account_financial_report/wizard/aged_partner_balance_wizard_view.xml +2 -3
  81. odoo/addons/account_financial_report/wizard/general_ledger_wizard.py +42 -36
  82. odoo/addons/account_financial_report/wizard/general_ledger_wizard_view.xml +26 -41
  83. odoo/addons/account_financial_report/wizard/journal_ledger_wizard.py +19 -7
  84. odoo/addons/account_financial_report/wizard/journal_ledger_wizard_view.xml +15 -14
  85. odoo/addons/account_financial_report/wizard/open_items_wizard.py +34 -8
  86. odoo/addons/account_financial_report/wizard/open_items_wizard_view.xml +16 -14
  87. odoo/addons/account_financial_report/wizard/trial_balance_wizard.py +68 -45
  88. odoo/addons/account_financial_report/wizard/trial_balance_wizard_view.xml +40 -39
  89. odoo/addons/account_financial_report/wizard/vat_report_wizard.py +9 -3
  90. odoo/addons/account_financial_report/wizard/vat_report_wizard_view.xml +14 -14
  91. odoo_addon_account_financial_report-18.0.1.4.4.3.dist-info/METADATA +234 -0
  92. odoo_addon_account_financial_report-18.0.1.4.4.3.dist-info/RECORD +107 -0
  93. {odoo_addon_account_financial_report-15.0.1.1.0.1.dist-info → odoo_addon_account_financial_report-18.0.1.4.4.3.dist-info}/WHEEL +1 -1
  94. odoo_addon_account_financial_report-18.0.1.4.4.3.dist-info/top_level.txt +1 -0
  95. odoo/addons/account_financial_report/readme/CONTRIBUTORS.rst +0 -35
  96. odoo/addons/account_financial_report/readme/DESCRIPTION.rst +0 -16
  97. odoo/addons/account_financial_report/readme/HISTORY.rst +0 -19
  98. odoo/addons/account_financial_report/readme/ROADMAP.rst +0 -7
  99. odoo/addons/account_financial_report/static/src/js/action_manager_report.js +0 -37
  100. odoo/addons/account_financial_report/static/src/js/client_action.js +0 -58
  101. odoo/addons/account_financial_report/static/src/js/report.js +0 -58
  102. odoo_addon_account_financial_report-15.0.1.1.0.1.dist-info/METADATA +0 -179
  103. odoo_addon_account_financial_report-15.0.1.1.0.1.dist-info/RECORD +0 -95
  104. odoo_addon_account_financial_report-15.0.1.1.0.1.dist-info/top_level.txt +0 -1
@@ -17,7 +17,7 @@ class JournalLedgerXslx(models.AbstractModel):
17
17
  report_name = _("Journal Ledger")
18
18
  if company_id:
19
19
  company = self.env["res.company"].browse(company_id)
20
- suffix = " - {} - {}".format(company.name, company.currency_id.name)
20
+ suffix = f" - {company.name} - {company.currency_id.name}"
21
21
  report_name = report_name + suffix
22
22
  return report_name
23
23
 
@@ -149,7 +149,7 @@ class JournalLedgerXslx(models.AbstractModel):
149
149
  _("Journals"),
150
150
  ", ".join(
151
151
  [
152
- "{} - {}".format(report_journal.code, report_journal.name)
152
+ f"{report_journal.code} - {report_journal.name}"
153
153
  for report_journal in report.journal_ids
154
154
  ]
155
155
  ),
@@ -178,13 +178,17 @@ class JournalLedgerXslx(models.AbstractModel):
178
178
  def _generate_journal_content(
179
179
  self, workbook, report, res_data, ledger, report_data
180
180
  ):
181
- journal = self.env["account.journal"].browse(ledger["id"])
181
+ journal = (
182
+ self.env["account.journal"]
183
+ .with_context(active_test=False)
184
+ .browse(ledger["id"])
185
+ )
182
186
  currency_name = (
183
187
  journal.currency_id
184
188
  and journal.currency_id.name
185
189
  or journal.company_id.currency_id.name
186
190
  )
187
- sheet_name = "{} ({}) - {}".format(journal.code, currency_name, journal.name)
191
+ sheet_name = f"{journal.code} ({currency_name}) - {journal.name}"
188
192
  self._generate_moves_content(
189
193
  workbook, sheet_name, report, res_data, ledger["report_moves"], report_data
190
194
  )
@@ -196,15 +200,17 @@ class JournalLedgerXslx(models.AbstractModel):
196
200
  )
197
201
 
198
202
  def _generate_journal_taxes_summary(self, workbook, ledger, report_data):
199
- journal = self.env["account.journal"].browse(ledger["id"])
203
+ journal = (
204
+ self.env["account.journal"]
205
+ .with_context(active_test=False)
206
+ .browse(ledger["id"])
207
+ )
200
208
  currency_name = (
201
209
  journal.currency_id
202
210
  and journal.currency_id.name
203
211
  or journal.company_id.currency_id.name
204
212
  )
205
- sheet_name = "Tax - {} ({}) - {}".format(
206
- journal.code, currency_name, journal.name
207
- )
213
+ sheet_name = f"Tax - {journal.code} ({currency_name}) - {journal.name}"
208
214
  self._generate_taxes_summary(
209
215
  workbook, sheet_name, ledger["tax_lines"], report_data
210
216
  )
@@ -1,11 +1,12 @@
1
1
  # © 2016 Julien Coux (Camptocamp)
2
2
  # Copyright 2020 ForgeFlow S.L. (https://www.forgeflow.com)
3
+ # Copyright 2024 Tecnativa - Carolina Fernandez
3
4
  # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
4
5
 
5
6
  import operator
6
7
  from datetime import date, datetime
7
8
 
8
- from odoo import api, models
9
+ from odoo import _, api, models
9
10
  from odoo.tools import float_is_zero
10
11
 
11
12
 
@@ -16,25 +17,47 @@ class OpenItemsReport(models.AbstractModel):
16
17
 
17
18
  def _get_account_partial_reconciled(self, company_id, date_at_object):
18
19
  domain = [("max_date", ">", date_at_object), ("company_id", "=", company_id)]
19
- fields = ["debit_move_id", "credit_move_id", "amount"]
20
+ fields = [
21
+ "debit_move_id",
22
+ "credit_move_id",
23
+ "amount",
24
+ "debit_amount_currency",
25
+ "credit_amount_currency",
26
+ ]
20
27
  accounts_partial_reconcile = self.env["account.partial.reconcile"].search_read(
21
28
  domain=domain, fields=fields
22
29
  )
23
30
  debit_amount = {}
31
+ debit_amount_currency = {}
24
32
  credit_amount = {}
33
+ credit_amount_currency = {}
25
34
  for account_partial_reconcile_data in accounts_partial_reconcile:
26
35
  debit_move_id = account_partial_reconcile_data["debit_move_id"][0]
27
36
  credit_move_id = account_partial_reconcile_data["credit_move_id"][0]
28
37
  if debit_move_id not in debit_amount.keys():
29
38
  debit_amount[debit_move_id] = 0.0
39
+ debit_amount_currency[debit_move_id] = 0.0
30
40
  debit_amount[debit_move_id] += account_partial_reconcile_data["amount"]
41
+ debit_amount_currency[debit_move_id] += account_partial_reconcile_data[
42
+ "debit_amount_currency"
43
+ ]
31
44
  if credit_move_id not in credit_amount.keys():
32
45
  credit_amount[credit_move_id] = 0.0
46
+ credit_amount_currency[credit_move_id] = 0.0
33
47
  credit_amount[credit_move_id] += account_partial_reconcile_data["amount"]
48
+ credit_amount_currency[credit_move_id] += account_partial_reconcile_data[
49
+ "credit_amount_currency"
50
+ ]
34
51
  account_partial_reconcile_data.update(
35
52
  {"debit_move_id": debit_move_id, "credit_move_id": credit_move_id}
36
53
  )
37
- return accounts_partial_reconcile, debit_amount, credit_amount
54
+ return (
55
+ accounts_partial_reconcile,
56
+ debit_amount,
57
+ credit_amount,
58
+ debit_amount_currency,
59
+ credit_amount_currency,
60
+ )
38
61
 
39
62
  def _get_data(
40
63
  self,
@@ -44,39 +67,25 @@ class OpenItemsReport(models.AbstractModel):
44
67
  only_posted_moves,
45
68
  company_id,
46
69
  date_from,
70
+ grouped_by,
47
71
  ):
48
72
  domain = self._get_move_lines_domain_not_reconciled(
49
73
  company_id, account_ids, partner_ids, only_posted_moves, date_from
50
74
  )
51
- ml_fields = [
52
- "id",
53
- "name",
54
- "date",
55
- "move_id",
56
- "journal_id",
57
- "account_id",
58
- "partner_id",
59
- "amount_residual",
60
- "date_maturity",
61
- "ref",
62
- "debit",
63
- "credit",
64
- "reconciled",
65
- "currency_id",
66
- "amount_currency",
67
- "amount_residual_currency",
68
- ]
75
+ ml_fields = self._get_ml_fields()
69
76
  move_lines = self.env["account.move.line"].search_read(
70
77
  domain=domain, fields=ml_fields
71
78
  )
72
79
  journals_ids = set()
73
- partners_ids = set()
80
+ group_ids = set()
74
81
  partners_data = {}
75
82
  if date_at_object < date.today():
76
83
  (
77
84
  acc_partial_rec,
78
85
  debit_amount,
79
86
  credit_amount,
87
+ debit_amount_currency,
88
+ credit_amount_currency,
80
89
  ) = self._get_account_partial_reconciled(company_id, date_at_object)
81
90
  if acc_partial_rec:
82
91
  ml_ids = list(map(operator.itemgetter("id"), move_lines))
@@ -97,6 +106,8 @@ class OpenItemsReport(models.AbstractModel):
97
106
  company_id,
98
107
  partner_ids,
99
108
  only_posted_moves,
109
+ debit_amount_currency,
110
+ credit_amount_currency,
100
111
  )
101
112
  move_lines = [
102
113
  move_line
@@ -110,35 +121,33 @@ class OpenItemsReport(models.AbstractModel):
110
121
  journals_ids.add(move_line["journal_id"][0])
111
122
  acc_id = move_line["account_id"][0]
112
123
  # Partners data
113
- if move_line["partner_id"]:
114
- prt_id = move_line["partner_id"][0]
115
- prt_name = move_line["partner_id"][1]
124
+ partner = self.env["res.partner"]
125
+ if move_line.get("partner_id"):
126
+ partner = self.env["res.partner"].browse(move_line["partner_id"][0])
127
+ if grouped_by == "salesperson":
128
+ user = partner.user_id
129
+ group_id = user.id or 0
130
+ group_name = user.name or _("Missing Salesperson")
116
131
  else:
117
- prt_id = 0
118
- prt_name = "Missing Partner"
119
- if prt_id not in partners_ids:
120
- partners_data.update({prt_id: {"id": prt_id, "name": prt_name}})
121
- partners_ids.add(prt_id)
122
-
132
+ group_id = partner.id or 0
133
+ group_name = partner.name or _("Missing Partner")
134
+ if group_id not in group_ids:
135
+ partners_data.update({group_id: {"id": group_id, "name": group_name}})
136
+ group_ids.add(group_id)
123
137
  # Move line update
124
- original = 0
125
-
126
138
  if not float_is_zero(move_line["credit"], precision_digits=2):
127
139
  original = move_line["credit"] * (-1)
128
- if not float_is_zero(move_line["debit"], precision_digits=2):
140
+ else:
129
141
  original = move_line["debit"]
130
142
 
131
143
  if move_line["ref"] == move_line["name"]:
132
- if move_line["ref"]:
133
- ref_label = move_line["ref"]
134
- else:
135
- ref_label = ""
144
+ ref_label = move_line["ref"] or ""
136
145
  elif not move_line["ref"]:
137
146
  ref_label = move_line["name"]
138
147
  elif not move_line["name"]:
139
148
  ref_label = move_line["ref"]
140
149
  else:
141
- ref_label = move_line["ref"] + str(" - ") + move_line["name"]
150
+ ref_label = move_line["ref"] + " - " + move_line["name"]
142
151
 
143
152
  move_line.update(
144
153
  {
@@ -146,11 +155,11 @@ class OpenItemsReport(models.AbstractModel):
146
155
  "date_maturity": move_line["date_maturity"]
147
156
  and move_line["date_maturity"].strftime("%d/%m/%Y"),
148
157
  "original": original,
149
- "partner_id": prt_id,
150
- "partner_name": prt_name,
158
+ "partner_id": partner.id or 0,
159
+ "partner_name": partner.name or "",
151
160
  "ref_label": ref_label,
152
161
  "journal_id": move_line["journal_id"][0],
153
- "move_name": move_line["move_id"][1],
162
+ "move_name": move_line["move_name"],
154
163
  "entry_id": move_line["move_id"][0],
155
164
  "currency_id": move_line["currency_id"][0]
156
165
  if move_line["currency_id"]
@@ -163,12 +172,12 @@ class OpenItemsReport(models.AbstractModel):
163
172
 
164
173
  # Open Items Move Lines Data
165
174
  if acc_id not in open_items_move_lines_data.keys():
166
- open_items_move_lines_data[acc_id] = {prt_id: [move_line]}
175
+ open_items_move_lines_data[acc_id] = {group_id: [move_line]}
167
176
  else:
168
- if prt_id not in open_items_move_lines_data[acc_id].keys():
169
- open_items_move_lines_data[acc_id][prt_id] = [move_line]
177
+ if group_id not in open_items_move_lines_data[acc_id].keys():
178
+ open_items_move_lines_data[acc_id][group_id] = [move_line]
170
179
  else:
171
- open_items_move_lines_data[acc_id][prt_id].append(move_line)
180
+ open_items_move_lines_data[acc_id][group_id].append(move_line)
172
181
  journals_data = self._get_journals_data(list(journals_ids))
173
182
  accounts_data = self._get_accounts_data(open_items_move_lines_data.keys())
174
183
  return (
@@ -197,11 +206,18 @@ class OpenItemsReport(models.AbstractModel):
197
206
 
198
207
  @api.model
199
208
  def _order_open_items_by_date(
200
- self, open_items_move_lines_data, show_partner_details
209
+ self,
210
+ open_items_move_lines_data,
211
+ show_partner_details,
212
+ partners_data,
213
+ accounts_data,
201
214
  ):
215
+ # We need to order by account code, partner_name and date
216
+ accounts_data_sorted = sorted(accounts_data.items(), key=lambda x: x[1]["code"])
217
+ account_ids_sorted = [account[0] for account in accounts_data_sorted]
202
218
  new_open_items = {}
203
219
  if not show_partner_details:
204
- for acc_id in open_items_move_lines_data.keys():
220
+ for acc_id in account_ids_sorted:
205
221
  new_open_items[acc_id] = {}
206
222
  move_lines = []
207
223
  for prt_id in open_items_move_lines_data[acc_id]:
@@ -210,18 +226,24 @@ class OpenItemsReport(models.AbstractModel):
210
226
  move_lines = sorted(move_lines, key=lambda k: (k["date"]))
211
227
  new_open_items[acc_id] = move_lines
212
228
  else:
213
- for acc_id in open_items_move_lines_data.keys():
229
+ for acc_id in account_ids_sorted:
214
230
  new_open_items[acc_id] = {}
215
- for prt_id in open_items_move_lines_data[acc_id]:
231
+ for prt_id in sorted(
232
+ open_items_move_lines_data[acc_id],
233
+ key=lambda i: partners_data[i]["name"],
234
+ ):
216
235
  new_open_items[acc_id][prt_id] = {}
217
236
  move_lines = []
218
237
  for move_line in open_items_move_lines_data[acc_id][prt_id]:
219
238
  move_lines += [move_line]
220
- move_lines = sorted(move_lines, key=lambda k: (k["date"]))
239
+ move_lines = sorted(
240
+ move_lines, key=lambda k: (k["date"], k["partner_id"])
241
+ )
221
242
  new_open_items[acc_id][prt_id] = move_lines
222
243
  return new_open_items
223
244
 
224
245
  def _get_report_values(self, docids, data):
246
+ res = super()._get_report_values(docids, data)
225
247
  wizard_id = data["wizard_id"]
226
248
  company = self.env["res.company"].browse(data["company_id"])
227
249
  company_id = data["company_id"]
@@ -232,7 +254,7 @@ class OpenItemsReport(models.AbstractModel):
232
254
  date_from = data["date_from"]
233
255
  only_posted_moves = data["only_posted_moves"]
234
256
  show_partner_details = data["show_partner_details"]
235
-
257
+ grouped_by = data["grouped_by"]
236
258
  (
237
259
  move_lines_data,
238
260
  partners_data,
@@ -246,26 +268,47 @@ class OpenItemsReport(models.AbstractModel):
246
268
  only_posted_moves,
247
269
  company_id,
248
270
  date_from,
271
+ grouped_by,
249
272
  )
250
273
 
251
274
  total_amount = self._calculate_amounts(open_items_move_lines_data)
252
275
  open_items_move_lines_data = self._order_open_items_by_date(
253
- open_items_move_lines_data, show_partner_details
276
+ open_items_move_lines_data,
277
+ show_partner_details,
278
+ partners_data,
279
+ accounts_data,
280
+ )
281
+ res.update(
282
+ {
283
+ "doc_ids": [wizard_id],
284
+ "doc_model": "open.items.report.wizard",
285
+ "docs": self.env["open.items.report.wizard"].browse(wizard_id),
286
+ "foreign_currency": data["foreign_currency"],
287
+ "show_partner_details": data["show_partner_details"],
288
+ "company_name": company.display_name,
289
+ "currency_name": company.currency_id.name,
290
+ "date_at": date_at_object.strftime("%d/%m/%Y"),
291
+ "hide_account_at_0": data["hide_account_at_0"],
292
+ "target_move": data["target_move"],
293
+ "journals_data": journals_data,
294
+ "partners_data": partners_data,
295
+ "accounts_data": accounts_data,
296
+ "total_amount": total_amount,
297
+ "Open_Items": open_items_move_lines_data,
298
+ "grouped_by": grouped_by,
299
+ }
254
300
  )
255
- return {
256
- "doc_ids": [wizard_id],
257
- "doc_model": "open.items.report.wizard",
258
- "docs": self.env["open.items.report.wizard"].browse(wizard_id),
259
- "foreign_currency": data["foreign_currency"],
260
- "show_partner_details": data["show_partner_details"],
261
- "company_name": company.display_name,
262
- "currency_name": company.currency_id.name,
263
- "date_at": date_at_object.strftime("%d/%m/%Y"),
264
- "hide_account_at_0": data["hide_account_at_0"],
265
- "target_move": data["target_move"],
266
- "journals_data": journals_data,
267
- "partners_data": partners_data,
268
- "accounts_data": accounts_data,
269
- "total_amount": total_amount,
270
- "Open_Items": open_items_move_lines_data,
271
- }
301
+ return res
302
+
303
+ def _get_ml_fields(self):
304
+ return self.COMMON_ML_FIELDS + [
305
+ "amount_residual",
306
+ "reconciled",
307
+ "currency_id",
308
+ "credit",
309
+ "date_maturity",
310
+ "amount_residual_currency",
311
+ "debit",
312
+ "amount_currency",
313
+ "move_name",
314
+ ]
@@ -16,7 +16,7 @@ class OpenItemsXslx(models.AbstractModel):
16
16
  report_name = _("Open Items")
17
17
  if company_id:
18
18
  company = self.env["res.company"].browse(company_id)
19
- suffix = " - {} - {}".format(company.name, company.currency_id.name)
19
+ suffix = f" - {company.name} - {company.currency_id.name}"
20
20
  report_name = report_name + suffix
21
21
  return report_name
22
22
 
@@ -101,11 +101,126 @@ class OpenItemsXslx(models.AbstractModel):
101
101
  def _get_col_pos_final_balance_label(self):
102
102
  return 5
103
103
 
104
- def _generate_report_content(self, workbook, report, data, report_data):
105
- res_data = self.env[
106
- "report.account_financial_report.open_items"
107
- ]._get_report_values(report, data)
108
- # For each account
104
+ def _calculate_amounts_by_partner(self, account_id, open_items_move_lines_data):
105
+ total_amount = {}
106
+ for line in open_items_move_lines_data:
107
+ partner_id_key = line["partner_id"]
108
+ if account_id not in total_amount:
109
+ total_amount[account_id] = {}
110
+ if partner_id_key not in total_amount[account_id]:
111
+ total_amount[account_id][partner_id_key] = {"residual": 0.0}
112
+ total_amount[account_id][partner_id_key]["residual"] += line[
113
+ "amount_residual"
114
+ ]
115
+ return total_amount
116
+
117
+ def _generate_report_content_by_salesperson(
118
+ self, workbook, report, data, report_data, res_data
119
+ ):
120
+ Open_items = res_data["Open_Items"]
121
+ accounts_data = res_data["accounts_data"]
122
+ partners_data = res_data["partners_data"]
123
+ journals_data = res_data["journals_data"]
124
+ total_amount = res_data["total_amount"]
125
+
126
+ for partner_id in partners_data.keys():
127
+ # Create a new sheet for each partner
128
+ partner_totals = {}
129
+ partner_name = partners_data[partner_id]["name"]
130
+ new_sheet = workbook.add_worksheet(partner_name[:31])
131
+ report_data["sheet"] = new_sheet
132
+ report_data["row_pos"] = 0
133
+
134
+ for account_id in Open_items.keys():
135
+ if partner_id in Open_items[account_id]:
136
+ self.write_array_title(
137
+ accounts_data[account_id]["code"]
138
+ + " - "
139
+ + accounts_data[account_id]["name"],
140
+ report_data,
141
+ )
142
+
143
+ # For each partner
144
+ if Open_items[account_id]:
145
+ type_object = "partner"
146
+ # Write partner title
147
+ self.write_array_title(
148
+ partners_data[partner_id]["name"], report_data
149
+ )
150
+
151
+ # Calculate totals by partner_id
152
+ partner_totals = self._calculate_amounts_by_partner(
153
+ account_id, Open_items[account_id][partner_id]
154
+ )
155
+ # Display array header for move lines
156
+ self.write_array_header(report_data)
157
+ # Display account move lines
158
+ has_lines = False
159
+ for partner_id_key, total_amount_dict in partner_totals.get(
160
+ account_id, {}
161
+ ).items():
162
+ for line in Open_items[account_id][partner_id]:
163
+ if line["partner_id"] == partner_id_key:
164
+ line.update(
165
+ {
166
+ "account": accounts_data[account_id][
167
+ "code"
168
+ ],
169
+ "journal": journals_data[
170
+ line["journal_id"]
171
+ ]["code"],
172
+ }
173
+ )
174
+ self.write_line_from_dict(line, report_data)
175
+ has_lines = True
176
+ if has_lines:
177
+ partner = self.env["res.partner"].browse(partner_id_key)
178
+ # Display ending balance line for partner
179
+ partner_data = {
180
+ "id": partner_id_key,
181
+ "name": partner.name
182
+ if partner
183
+ else _("Missing Partner"),
184
+ "currency_id": accounts_data[account_id][
185
+ "currency_id"
186
+ ],
187
+ "currency_name": accounts_data[account_id][
188
+ "currency_name"
189
+ ],
190
+ "residual": total_amount_dict,
191
+ }
192
+ self.write_ending_balance_from_dict(
193
+ partner_data,
194
+ "partner_subtotal",
195
+ partner_totals,
196
+ report_data,
197
+ account_id=account_id,
198
+ partner_id=partner_id_key,
199
+ )
200
+ has_lines = False
201
+ # Display ending balance line for salesperson
202
+ partners_data[partner_id].update(
203
+ {
204
+ "currency_id": accounts_data[account_id]["currency_id"],
205
+ "currency_name": accounts_data[account_id][
206
+ "currency_name"
207
+ ],
208
+ }
209
+ )
210
+ self.write_ending_balance_from_dict(
211
+ partners_data[partner_id],
212
+ type_object,
213
+ total_amount,
214
+ report_data,
215
+ account_id=account_id,
216
+ partner_id=partner_id,
217
+ )
218
+ # Line break
219
+ report_data["row_pos"] += 1
220
+
221
+ def _generate_report_content_by_partner(
222
+ self, workbook, report, data, report_data, res_data
223
+ ):
109
224
  Open_items = res_data["Open_Items"]
110
225
  accounts_data = res_data["accounts_data"]
111
226
  partners_data = res_data["partners_data"]
@@ -120,7 +235,6 @@ class OpenItemsXslx(models.AbstractModel):
120
235
  + accounts_data[account_id]["name"],
121
236
  report_data,
122
237
  )
123
-
124
238
  # For each partner
125
239
  if Open_items[account_id]:
126
240
  if show_partner_details:
@@ -180,18 +294,33 @@ class OpenItemsXslx(models.AbstractModel):
180
294
  )
181
295
  self.write_line_from_dict(line, report_data)
182
296
 
183
- # Display ending balance line for account
184
- type_object = "account"
185
- self.write_ending_balance_from_dict(
186
- accounts_data[account_id],
187
- type_object,
188
- total_amount,
189
- report_data,
190
- account_id=account_id,
191
- )
297
+ # Display ending balance line for account
298
+ type_object = "account"
299
+ self.write_ending_balance_from_dict(
300
+ accounts_data[account_id],
301
+ type_object,
302
+ total_amount,
303
+ report_data,
304
+ account_id=account_id,
305
+ )
306
+
307
+ # 2 lines break
308
+ report_data["row_pos"] += 2
192
309
 
193
- # 2 lines break
194
- report_data["row_pos"] += 2
310
+ def _generate_report_content(self, workbook, report, data, report_data):
311
+ res_data = self.env[
312
+ "report.account_financial_report.open_items"
313
+ ]._get_report_values(report, data)
314
+ show_partner_details = res_data["show_partner_details"]
315
+ grouped_by = res_data["grouped_by"]
316
+ if grouped_by == "salesperson" and show_partner_details:
317
+ return self._generate_report_content_by_salesperson(
318
+ workbook, report, data, report_data, res_data
319
+ )
320
+ else:
321
+ return self._generate_report_content_by_partner(
322
+ workbook, report, data, report_data, res_data
323
+ )
195
324
 
196
325
  def write_ending_balance_from_dict(
197
326
  self,
@@ -211,6 +340,10 @@ class OpenItemsXslx(models.AbstractModel):
211
340
  name = my_object["code"] + " - " + my_object["name"]
212
341
  my_object["residual"] = total_amount[account_id]["residual"]
213
342
  label = _("Ending balance")
214
- return super(OpenItemsXslx, self).write_ending_balance_from_dict(
343
+ elif type_object == "partner_subtotal":
344
+ name = my_object["name"]
345
+ my_object["residual"] = total_amount[account_id][partner_id]["residual"]
346
+ label = _("Ending balance")
347
+ return super().write_ending_balance_from_dict(
215
348
  my_object, name, label, report_data
216
349
  )