From b04f780820e924edc1aae0d6f40b81157e1ad9a6 Mon Sep 17 00:00:00 2001 From: git_admin Date: Fri, 1 May 2026 14:20:18 +0000 Subject: [PATCH] Tower: upload accounting_pdf_reports 1.0.2 (via marketplace) --- .../report/report_financial.py | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 addons/accounting_pdf_reports/report/report_financial.py diff --git a/addons/accounting_pdf_reports/report/report_financial.py b/addons/accounting_pdf_reports/report/report_financial.py new file mode 100644 index 0000000..8d408c2 --- /dev/null +++ b/addons/accounting_pdf_reports/report/report_financial.py @@ -0,0 +1,163 @@ +import time +from odoo import api, models, _ +from odoo.exceptions import UserError + + +class ReportFinancial(models.AbstractModel): + _name = 'report.accounting_pdf_reports.report_financial' + _description = 'Financial Reports' + + def _compute_account_balance(self, accounts): + """ compute the balance, debit and credit for the provided accounts + """ + mapping = { + 'balance': "COALESCE(SUM(debit),0) - COALESCE(SUM(credit), 0) as balance", + 'debit': "COALESCE(SUM(debit), 0) as debit", + 'credit': "COALESCE(SUM(credit), 0) as credit", + } + + res = {} + for account in accounts: + res[account.id] = dict.fromkeys(mapping, 0.0) + if accounts: + tables, where_clause, where_params = self.env['account.move.line']._query_get() + tables = tables.replace('"', '') if tables else "account_move_line" + wheres = [""] + if where_clause.strip(): + wheres.append(where_clause.strip()) + filters = " AND ".join(wheres) + request = "SELECT account_id as id, " + ', '.join(mapping.values()) + \ + " FROM " + tables + \ + " WHERE account_id IN %s " \ + + filters + \ + " GROUP BY account_id" + params = (tuple(accounts._ids),) + tuple(where_params) + self.env.cr.execute(request, params) + for row in self.env.cr.dictfetchall(): + res[row['id']] = row + return res + + def _compute_report_balance(self, reports): + '''returns a dictionary with key=the ID of a record and value=the credit, debit and balance amount + computed for this record. If the record is of type : + 'accounts' : it's the sum of the linked accounts + 'account_type' : it's the sum of leaf accoutns with such an account_type + 'account_report' : it's the amount of the related report + 'sum' : it's the sum of the children of this record (aka a 'view' record)''' + res = {} + fields = ['credit', 'debit', 'balance'] + for report in reports: + if report.id in res: + continue + res[report.id] = dict((fn, 0.0) for fn in fields) + if report.type == 'accounts': + # it's the sum of the linked accounts + res[report.id]['account'] = self._compute_account_balance(report.account_ids) + for value in res[report.id]['account'].values(): + for field in fields: + res[report.id][field] += value.get(field) + elif report.type == 'account_type': + # it's the sum the leaf accounts with such an account type + accounts = self.env['account.account'].search( + [('account_type', 'in', report.account_type_ids.mapped('type'))]) + + res[report.id]['account'] = self._compute_account_balance(accounts) + for value in res[report.id]['account'].values(): + for field in fields: + res[report.id][field] += value.get(field) + elif report.type == 'account_report' and report.account_report_id: + # it's the amount of the linked report + res2 = self._compute_report_balance(report.account_report_id) + for key, value in res2.items(): + for field in fields: + res[report.id][field] += value[field] + elif report.type == 'sum': + # it's the sum of the children of this account.report + res2 = self._compute_report_balance(report.children_ids) + for key, value in res2.items(): + for field in fields: + res[report.id][field] += value[field] + return res + + def get_account_lines(self, data): + lines = [] + account_report = self.env['account.financial.report'].search( + [('id', '=', data['account_report_id'][0])]) + child_reports = account_report._get_children_by_order() + res = self.with_context(data.get('used_context'))._compute_report_balance(child_reports) + if data['enable_filter']: + comparison_res = self.with_context( + data.get('comparison_context'))._compute_report_balance( + child_reports) + for report_id, value in comparison_res.items(): + res[report_id]['comp_bal'] = value['balance'] + report_acc = res[report_id].get('account') + if report_acc: + for account_id, val in comparison_res[report_id].get('account').items(): + report_acc[account_id]['comp_bal'] = val['balance'] + for report in child_reports: + vals = { + 'name': report.name, + 'balance': res[report.id]['balance'] * float(report.sign), + 'type': 'report', + 'level': bool(report.style_overwrite) and report.style_overwrite or report.level, + 'account_type': report.type or False, #used to underline the financial report balances + } + if data['debit_credit']: + vals['debit'] = res[report.id]['debit'] + vals['credit'] = res[report.id]['credit'] + + if data['enable_filter']: + vals['balance_cmp'] = res[report.id]['comp_bal'] * float(report.sign) + + lines.append(vals) + if report.display_detail == 'no_detail': + #the rest of the loop is used to display the details of the financial report, so it's not needed here. + continue + if res[report.id].get('account'): + sub_lines = [] + for account_id, value in res[report.id]['account'].items(): + #if there are accounts to display, we add them to the lines with a level equals to their level in + #the COA + 1 (to avoid having them with a too low level that would conflicts with the level of data + #financial reports for Assets, liabilities...) + flag = False + account = self.env['account.account'].browse(account_id) + vals = { + 'name': account.code + ' ' + account.name, + 'balance': value['balance'] * float(report.sign) or 0.0, + 'type': 'account', + 'level': report.display_detail == 'detail_with_hierarchy' and 4, + 'account_type': account.account_type, + } + if data['debit_credit']: + vals['debit'] = value['debit'] + vals['credit'] = value['credit'] + if not self.env.company.currency_id.is_zero(vals['debit']) or not self.env.company.currency_id.is_zero(vals['credit']): + flag = True + if not self.env.company.currency_id.is_zero(vals['balance']): + flag = True + if data['enable_filter']: + vals['balance_cmp'] = value['comp_bal'] * float(report.sign) + if not self.env.company.currency_id.is_zero(vals['balance_cmp']): + flag = True + if flag: + sub_lines.append(vals) + lines += sorted(sub_lines, key=lambda sub_line: sub_line['name']) + return lines + + @api.model + def _get_report_values(self, docids, data=None): + if not data.get('form') or not self.env.context.get('active_model') or not self.env.context.get('active_id'): + raise UserError(_("Form content is missing, this report cannot be printed.")) + + model = self.env.context.get('active_model') + docs = self.env[model].browse(self.env.context.get('active_id')) + report_lines = self.get_account_lines(data.get('form')) + return { + 'doc_ids': self.ids, + 'doc_model': model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'get_account_lines': report_lines, + }