1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
# -*- coding: utf-8 -*-
######################################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2020-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Technologies (odoo@cybrosys.com)
#
# This program is under the terms of the Odoo Proprietary License v1.0 (OPL-1)
# It is forbidden to publish, distribute, sublicense, or sell copies of the Software
# or modified copies of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
# DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
########################################################################################
import time
from odoo import api, models, _
from odoo.exceptions import UserError
class ReportFinancial(models.AbstractModel):
_name = 'report.account.report_financial'
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([('user_type_id', 'in', report.account_type_ids.ids)])
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'] * int(report.sign),
'type': 'report',
'level': bool(report.style_overwrite) and 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'] * int(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'] * int(report.sign) or 0.0,
'type': 'account',
'level': report.display_detail == 'detail_with_hierarchy' and 4,
'account_type': account.internal_type,
}
if data['debit_credit']:
vals['debit'] = value['debit']
vals['credit'] = value['credit']
if not account.company_id.currency_id.is_zero(vals['debit']) or not account.company_id.currency_id.is_zero(vals['credit']):
flag = True
if not account.company_id.currency_id.is_zero(vals['balance']):
flag = True
if data['enable_filter']:
vals['balance_cmp'] = value['comp_bal'] * int(report.sign)
if not account.company_id.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."))
self.model = self.env.context.get('active_model')
docs = self.env[self.model].browse(self.env.context.get('active_id'))
report_lines = self.get_account_lines(data.get('form'))
return {
'doc_ids': self.ids,
'doc_model': self.model,
'data': data['form'],
'docs': docs,
'time': time,
'get_account_lines': report_lines,
}
|