· 4 years ago · Jun 18, 2021, 10:04 PM
1from odoo import models, api, fields, _
2from odoo.tools.misc import format_date
3from dateutil.relativedelta import relativedelta
4from odoo.tools import float_is_zero
5from datetime import datetime
6
7
8class ReportAccountAgedPartner(models.AbstractModel):
9 _inherit = "account.aged.partner"
10
11 filter_account = True
12
13 ####################################################
14 # OPTIONS: journals
15 ####################################################
16
17 @api.model
18 def _get_filter_account(self, account_type=None):
19 return self.env['account.account'].with_context(active_test=False).search([
20 ('company_id', 'in', self.env.user.company_ids.ids or [self.env.company.id]),
21 ('internal_type', '=', account_type)
22 ], order="company_id, name")
23
24 @api.model
25 def _init_filter_account(self, options, previous_options=None):
26 if self.filter_account is None:
27 return
28
29 if previous_options and previous_options.get('account'):
30 account_map = dict((opt['id'], opt['selected']) for opt in previous_options['account'] if
31 'selected' in opt)
32 else:
33 account_map = {}
34 options['account'] = []
35
36 for j in self._get_filter_account():
37 options['account'].append({
38 'id': j.id,
39 'name': j.name,
40 'code': j.code,
41 'selected': account_map.get(j.id),
42 })
43
44 @api.model
45 def _get_options_account(self, options):
46 return [
47 account for account in options.get('account', []) if account['selected']
48 ]
49
50 @api.model
51 def _get_options_account_domain(self, options):
52 # Make sure to return an empty array when nothing selected to handle archived journals.
53 selected_account = self._get_options_account(options)
54 return selected_account and [('account_id', 'in', [j['id'] for j in selected_account])] or []
55
56 @api.model
57 def _get_options_domain(self, options):
58 domain = super(ReportAccountAgedPartner, self)._get_options_domain(options)
59 domain += self._get_options_account_domain(options)
60 return domain
61
62 def _set_context(self, options):
63 ctx = super(ReportAccountAgedPartner, self)._set_context(options)
64 if options.get('account'):
65 ctx['account_ids'] = [j.get('id') for j in options.get('account') if j.get('selected')]
66 return ctx
67
68 def get_report_informations(self, options):
69 '''
70 return a dictionary of informations that will be needed by the js widget, manager_id, footnotes, html of report and searchview, ...
71 '''
72 options = self._get_options(options)
73
74 searchview_dict = {'options': options, 'context': self.env.context}
75 # Check if report needs analytic
76 if options.get('analytic_accounts') is not None:
77 options['selected_analytic_account_names'] = [self.env['account.analytic.account'].browse(int(account)).name for account in options['analytic_accounts']]
78 if options.get('analytic_tags') is not None:
79 options['selected_analytic_tag_names'] = [self.env['account.analytic.tag'].browse(int(tag)).name for tag in options['analytic_tags']]
80 if options.get('partner'):
81 options['selected_partner_ids'] = [self.env['res.partner'].browse(int(partner)).name for partner in options['partner_ids']]
82 options['selected_partner_categories'] = [self.env['res.partner.category'].browse(int(category)).name for category in (options.get('partner_categories') or [])]
83
84 # Check whether there are unposted entries for the selected period or not (if the report allows it)
85 if options.get('date') and options.get('all_entries') is not None:
86 date_to = options['date'].get('date_to') or options['date'].get('date') or fields.Date.today()
87 period_domain = [('state', '=', 'draft'), ('date', '<=', date_to)]
88 options['unposted_in_period'] = bool(self.env['account.move'].search_count(period_domain))
89
90 if options.get('journals'):
91 account_selected = set(account['id'] for account in options['account'] if account.get('selected'))
92
93 report_manager = self._get_report_manager(options)
94 info = {'options': options,
95 'context': self.env.context,
96 'report_manager_id': report_manager.id,
97 'footnotes': [{'id': f.id, 'line': f.line, 'text': f.text} for f in report_manager.footnotes_ids],
98 'buttons': self._get_reports_buttons_in_sequence(),
99 'main_html': self.get_html(options),
100 'searchview_html': self.env['ir.ui.view']._render_template(self._get_templates().get('search_template', 'account_report.search_template'), values=searchview_dict),
101 }
102 return info
103
104 def _get_columns_name(self, options):
105 columns = super(ReportAccountAgedPartner, self)._get_columns_name(options)
106 columns.append({'name': _("Porcentaje"), 'style': 'white-space:nowrap;', 'class': 'text-center'})
107 columns.append({'name': _("Fecha"), 'style': 'white-space:nowrap;', 'class': 'text-center'})
108 return columns
109
110 @api.model
111 def _get_lines(self, options, line_id=None):
112 self = self.with_context(report_options=options)
113
114 line_dict = self._get_values(options=options, line_id=line_id)
115 if line_id: # prune the empty tree and keep only the wanted branch
116 for key, value in self._parse_line_id(line_id):
117 line_dict = line_dict['children'][(key, value)]
118 if not line_dict['values']:
119 return []
120
121 lines = []
122 self._append_grouped(
123 lines=lines,
124 current=self._parse_line_id(line_id),
125 line_dict=line_dict,
126 value_getters=[d.getter for d in self._get_column_details(options)[1:]],
127 value_formatters=[d.formatter for d in self._get_column_details(options)[1:]],
128 options=options,
129 hidden_lines={},
130 )
131
132 if line_id:
133 del options['headers']
134 options['unfolded_lines'] = []
135 line_dict = self._get_values(options=options, line_id=None)
136 all_lines = []
137 self._append_grouped(
138 lines=all_lines,
139 current=self._parse_line_id(None),
140 line_dict=line_dict,
141 value_getters=[d.getter for d in self._get_column_details(options)[1:]],
142 value_formatters=[d.formatter for d in self._get_column_details(options)[1:]],
143 options=options,
144 hidden_lines={},
145 )
146 # Percentages per invoice removed because client asked for
147 total = all_lines[0]['columns'][-1]['no_format']
148 print(total)
149 for i, line in enumerate(lines):
150 if i > 0:
151 lines[i]['columns'].append({
152 'name': "",
153 'class': 'text-center'
154 })
155 lines[i]['columns'].append({
156 'name': "Fecha",
157 'class': 'text-center'
158 })
159 # Only add percentage to total line
160 percent = 100 * lines[0]['columns'][-1]['no_format'] / total
161 lines[0]['columns'].append({
162 'name': "{}%".format(round(percent, 2)),
163 'no_format': percent,
164 'class': 'text-center'
165 })
166 if options.get('lines_offset', 0):
167 return lines[1:-1] # TODO remove total line depending on param
168 return lines # No need to handle the total as we already only have pruned the tree
169 if lines:
170 # put the total line at the end or remove it
171 total = lines[0]['columns'][-1]['no_format']
172 for i, line in enumerate(lines):
173 if not line['parent_id']:
174 percent = 100 * line['columns'][-1]['no_format'] / total
175 lines[i]['columns'].append({
176 'name': "{}%".format(round(percent, 2)),
177 'no_format': percent,
178 'class': 'text-center'
179 })
180 else:
181 lines[i]['columns'].append({
182 'name': '',
183 'class': 'text-center'
184 })
185 lines[i]['columns'].append({
186 'name': 'Fecha',
187 'class': 'text-center'
188 })
189 return lines[1:] + (self.total_line and [{**lines[0], 'name': _('Total')}] or [])
190 return []
191
192
193class AccountingReport(models.AbstractModel):
194 _inherit = 'account.accounting.report'
195
196 def _append_grouped(self, lines, current, line_dict, value_getters, value_formatters, options, hidden_lines):
197 """Append the current line and all of its children recursively.
198
199 :param lines (list<dict>): the list of report lines to send to the client
200 :param current (list<tuple>): list of tuple(grouping_key, id)
201 :param line_dict: the current hierarchy to unpack
202 :param value_getters (list<function>): list of getter to retrieve each column's data.
203 The parameter passed to the getter is the result of the read_group
204 :param value_formatters (list<functions>): list of the value formatters.
205 The parameter passed to the setter is the result of the getter.
206 :param options (dict): report options.
207 :param hidden_lines (dict): mapping between the lines hidden and their parent.
208 """
209 if line_dict['values'].get('__count', 1) == 0:
210 return
211 line = self._format_line(line_dict['values'], value_getters, value_formatters, current, options)
212 if line['parent_id'] in hidden_lines:
213 line['parent_id'] = hidden_lines[line['parent_id']]
214
215 if self._show_line(line, line_dict['values'], current, options):
216 lines.append(line)
217 else:
218 hidden_lines[line['id']] = hidden_lines.get('parent_id') or line['parent_id']
219 # Add children recursively
220 for key in line_dict['children']:
221 self._append_grouped(
222 lines=lines,
223 current=current + [key],
224 line_dict=line_dict['children'][key],
225 value_getters=value_getters,
226 value_formatters=value_formatters,
227 options=options,
228 hidden_lines=hidden_lines,
229 )
230
231 # Handle load more
232 offset = line['offset'] = len(line_dict['children']) + int(options.get('lines_offset', 0))
233 if (
234 current and self._get_hierarchy_details(options)[len(current)-1].lazy
235 and len(line_dict['children']) >= self.MAX_LINES and line_dict['children']
236 ):
237 load_more_line = self._get_load_more_line(
238 line_dict=line_dict,
239 value_getters=value_getters,
240 value_formatters=value_formatters,
241 current=current,
242 options=options,
243 offset=offset,
244 )
245 lines.append(load_more_line)
246
247 # Handle section total line
248 if (
249 current and self._get_hierarchy_details(options)[len(current)-1].section_total
250 and line_dict['children']
251 and lines[-1] != line
252 ):
253 total_line = self._format_line(
254 value_dict=line_dict['values'],
255 value_getters=value_getters,
256 value_formatters=value_formatters,
257 current=current,
258 options=options,
259 total=True,
260 )
261 if self._show_line(total_line, line_dict['values'], current, options):
262 lines.append(total_line)
263
264
265class ReportAccountAgedReceivable(models.AbstractModel):
266 _inherit = "account.aged.receivable"
267
268 def _get_filter_account(self, account_type='receivable'):
269 return super(ReportAccountAgedReceivable, self)._get_filter_account(account_type)
270
271
272class ReportAccountAgedPayable(models.AbstractModel):
273 _inherit = "account.aged.payable"
274
275 def _get_filter_account(self, account_type='payable'):
276 return super(ReportAccountAgedPayable, self)._get_filter_account(account_type)
277