1
0
forked from Mapan/odoo17e
odoo17e-kedaikipas58/addons/l10n_co_reports/models/general_ledger.py
2024-12-10 09:04:09 +07:00

336 lines
18 KiB
Python

from odoo import api, models, _
class GeneralLedgerCustomHandler(models.AbstractModel):
_inherit = 'account.general.ledger.report.handler'
def _dynamic_lines_generator(self, report, options, all_column_groups_expression_totals, warnings=None):
if not options.get('l10n_co_reports_groupby_partner_id'):
return super()._dynamic_lines_generator(report, options, all_column_groups_expression_totals, warnings)
lines_groupby_account, total_line = self._l10n_co_reports_get_lines_group_by_account_and_partner(report, options)
# Order lines by account code
sorted_lines = [
line
for account_key in sorted(lines_groupby_account, key=lambda account: account.code)
for line in lines_groupby_account[account_key]
]
sorted_lines.append(total_line)
return [(0, line) for line in sorted_lines]
def _l10n_co_reports_get_lines_group_by_account_and_partner(self, report, options):
# Returns
# - A dict representing the lines that need to be added to the report, grouped by account
# - The final line with the total amounts
# Note: All moves without partner are grouped into a single line at the end of each list
def custom_sort_key(line):
# Order lines alphabetically by partner name, with the parent line on top and the line without partner at the bottom
custom_partner_id = line['l10n_co_partner_id']
custom_partner_id = 0 if custom_partner_id else 1
return not line['is_parent'], custom_partner_id, line['l10n_co_partner_name']
lines_groupby_account = {}
for (account, partner_id), column_group_results in self._l10n_co_reports_query_values(report, options):
eval_dict = {}
partner_name = ''
partner_vat = ''
for column_group_key, results in column_group_results.items():
account_sum = results.get('sum', {})
account_un_earn = results.get('unaffected_earnings', {})
if not partner_name:
partner_name = account_sum.get('partner_name', '') or account_un_earn.get('partner_name', '')
if not partner_vat:
partner_vat = account_sum.get('partner_vat', '') or account_un_earn.get('partner_vat', '')
eval_dict[column_group_key] = {
'amount_currency': account_sum.get('amount_currency', 0.0) + account_un_earn.get('amount_currency', 0.0),
'debit': account_sum.get('debit', 0.0) + account_un_earn.get('debit', 0.0),
'credit': account_sum.get('credit', 0.0) + account_un_earn.get('credit', 0.0),
'balance': account_sum.get('balance', 0.0) + account_un_earn.get('balance', 0.0),
}
lines_groupby_account.setdefault(account, []).append(
self._l10n_co_reports_get_account_title_line(report, options, account, partner_id, partner_name, partner_vat, eval_dict)
)
total_amounts = [0] * len(options['columns'])
for account, partner_lines in lines_groupby_account.items():
parent_line_col_values = [
sum(partner_line['columns'][i]['no_format'] or 0.0 for partner_line in partner_lines)
for i in range(len(options['columns']))
]
parent_line = self._l10n_co_reports_get_empty_parent_line(report, options, account, parent_line_col_values)
parent_line['id'] = report._get_generic_line_id('account.account', account.id)
for partner_line in partner_lines:
partner_line['parent_id'] = parent_line['id']
total_amounts = [x + y for x, y in zip(total_amounts, parent_line_col_values)]
partner_lines.append(parent_line)
partner_lines.sort(key=custom_sort_key)
total_line = self._l10n_co_reports_get_total_line(report, options, total_amounts)
return lines_groupby_account, total_line
@api.model
def _l10n_co_reports_get_empty_parent_line(self, report, options, account, parent_line_col_values):
line_columns = []
for i, column in enumerate(options['columns']):
if column['expression_label'] == 'partner_name':
line_columns.append({'name': '', 'no_format': 0.0, 'class': ''})
continue
if column['expression_label'] == 'partner_vat':
line_columns.append({'name': '', 'no_format': 0.0, 'class': ''})
continue
col_value = parent_line_col_values[i]
formatted_value = report.format_value(options, col_value, figure_type=column['figure_type'], blank_if_zero=True)
line_columns.append({
'name': formatted_value,
'no_format': col_value,
'class': 'number',
})
return {
'name': f'{account.code} {account.name}',
'search_key': account.code,
'columns': line_columns,
'level': 1,
'unfoldable': False,
'unfolded': False,
'l10n_co_partner_name': '',
'l10n_co_partner_id': '',
'is_parent': True,
}
@api.model
def _l10n_co_reports_get_account_title_line(self, report, options, account, partner_id, partner_name, partner_vat, eval_dict):
line_columns = []
for column in options['columns']:
if column['expression_label'] == 'partner_name':
line_columns.append({
'name': partner_name if partner_id else _('(None)'),
'no_format': 0.0,
})
continue
if column['expression_label'] == 'partner_vat':
line_columns.append({
'name': partner_vat,
'no_format': 0.0,
})
continue
col_value = eval_dict[column['column_group_key']].get(column['expression_label'])
formatted_value = report.format_value(options, col_value, figure_type=column['figure_type'], blank_if_zero=True)
line_columns.append({
'name': formatted_value,
'no_format': col_value,
'class': 'number',
})
line_id = report._get_generic_line_id('res.partner', partner_id, markup='account_id:' + str(account.id))
return {
'id': line_id,
'name': f'{account.code} {account.name}',
'search_key': account.code,
'columns': line_columns,
'level': 3,
'unfoldable': False,
'unfolded': False,
'l10n_co_partner_name': partner_name,
'l10n_co_partner_id': partner_id,
'is_parent': False,
}
@api.model
def _l10n_co_reports_get_total_line(self, report, options, total_amounts):
total_line_columns = []
for i, column in enumerate(options['columns']):
if column['expression_label'] in ('partner_name', 'partner_vat'):
total_line_columns.append({})
continue
col_value = total_amounts[i]
formatted_value = report.format_value(options, col_value, blank_if_zero=False, figure_type='monetary')
total_line_columns.append({
'name': formatted_value,
'no_format': col_value,
'class': 'number',
})
return {
'id': report._get_generic_line_id(None, None, markup='total'),
'name': _('Total'),
'class': 'total',
'level': 1,
'columns': total_line_columns,
}
def _l10n_co_reports_query_values(self, report, options):
accounts_partners_keys = set()
accounts_partners_map = {}
companies_map = {} # Changed from companies_partners_map
aml_query, aml_params = self._l10n_co_reports_get_query_amls(report, options)
self._cr.execute(aml_query, aml_params)
for res in self._cr.dictfetchall():
column_group_key = res['column_group_key']
key = res['key']
partner_id = res['partner_id']
res['partner_vat'] = res['partner_vat'] or ''
if key == 'sum':
if res['account_type'] == 'equity_unaffected':
partner_id = None # Remove partner details for unaffected earnings
res['partner_vat'] = ''
account_id = res['groupby']
groupby_key = (account_id, partner_id)
accounts_partners_keys.add(groupby_key)
accounts_partners_map.setdefault(groupby_key, {col_group_key: {} for col_group_key in options['column_groups']})
accounts_partners_map[groupby_key][column_group_key][key] = res
elif key == 'unaffected_earnings':
company_id = res['groupby']
companies_map.setdefault(company_id, {col_group_key: {} for col_group_key in options['column_groups']})
companies_map[company_id][column_group_key] = res
# Converts the unaffected earnings of the query to the proper unaffected account of the company.
# The subgroup per partner no longer applies for unaffected earnings
if companies_map:
company_unaffected_account_map = {
account.company_id.id: account
for account in self.env['account.account'].search([
('account_type', '=', 'equity_unaffected'),
('company_id', 'in', list(companies_map.keys())),
])
}
for company_id, company_data in companies_map.items():
account = company_unaffected_account_map[company_id]
groupby_key = (account.id, None) # Use None instead of partner_id
accounts_partners_map.setdefault(groupby_key, {col_group_key: {} for col_group_key in options['column_groups']})
for column_group_key in options['column_groups']:
if 'unaffected_earnings' not in accounts_partners_map[groupby_key][column_group_key]:
accounts_partners_map[groupby_key][column_group_key]['unaffected_earnings'] = companies_map[company_id][column_group_key]
accounts_partners_keys.add(groupby_key)
account_partner_keys = {(self.env['account.account'].browse(account_id), partner_id) for account_id, partner_id in accounts_partners_keys}
return [(account_partner_key, accounts_partners_map[account_partner_key[0].id, account_partner_key[1]]) for account_partner_key in account_partner_keys]
def _l10n_co_reports_get_query_amls(self, report, options):
options_by_column_group = report._split_options_per_column_group(options)
params = []
queries = []
# Create the currency table.
# As the currency table is the same whatever the comparisons, create it only once.
ct_query = report._get_query_currency_table(options)
# ===============================================================
# 1) Get sums for all (accounts, partners) existing combinations
# ===============================================================
for column_group_key, options_group in options_by_column_group.items():
if not options.get('general_ledger_strict_range'):
options_group = self._get_options_sum_balance(options_group)
# Sum is computed including the initial balance of the accounts configured to do so, unless a special option key is used
sum_date_scope = 'strict_range' if options_group.get('general_ledger_strict_range') else 'normal'
query_domain = []
if options.get('filter_search_bar'):
query_domain.append(('account_id', 'ilike', options['filter_search_bar']))
# Exclude move lines with P&L accounts from initial balance if they belong to a previous fiscal year
if options_group.get('include_current_year_in_unaff_earnings'):
query_domain += [('account_id.include_initial_balance', '=', True)]
tables, where_clause, where_params = report._query_get(options_group, sum_date_scope, domain=query_domain)
params.append(column_group_key)
params += where_params
queries.append(f"""
SELECT
account.id AS groupby,
account.account_type AS account_type,
partner.id AS partner_id,
'sum' AS key,
MAX(account_move_line.date) AS max_date,
%s AS column_group_key,
COALESCE(SUM(account_move_line.amount_currency), 0.0) AS amount_currency,
SUM(ROUND(account_move_line.debit * currency_table.rate, currency_table.precision)) AS debit,
SUM(ROUND(account_move_line.credit * currency_table.rate, currency_table.precision)) AS credit,
SUM(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) AS balance,
account.code AS account_code,
account.name AS account_name,
partner.name AS partner_name,
partner.vat AS partner_vat
FROM {tables}
LEFT JOIN res_company company ON company.id = account_move_line.company_id
LEFT JOIN res_partner partner ON partner.id = account_move_line.partner_id
LEFT JOIN account_account account ON account.id = account_move_line.account_id
LEFT JOIN account_journal journal ON journal.id = account_move_line.journal_id
LEFT JOIN account_full_reconcile full_rec ON full_rec.id = account_move_line.full_reconcile_id
LEFT JOIN {ct_query} ON currency_table.company_id = account_move_line.company_id
WHERE {where_clause}
GROUP BY account.id, partner.id
""")
# ============================================
# 2) Unaffected earnings.
# ============================================
if not options_group.get('general_ledger_strict_range'):
# Apply to initial balance and end balance and only focus on unaffected earnings
unaff_earnings_domain = [('account_id.include_initial_balance', '=', False)]
# The period domain is expressed as:
# [
# ('date' <= fiscalyear['date_from'] - 1),
# ('account_id.include_initial_balance', '=', False),
# ]
new_options = self._get_options_unaffected_earnings(options_group)
tables, where_clause, where_params = report._query_get(new_options, 'strict_range', domain=unaff_earnings_domain)
params.append(column_group_key)
params += where_params
queries.append(f"""
SELECT
company.id AS groupby,
NULL AS account_type,
NULL AS partner_id,
'unaffected_earnings' AS key,
NULL AS max_date,
%s AS column_group_key,
COALESCE(SUM(account_move_line.amount_currency), 0.0) AS amount_currency,
SUM(ROUND(account_move_line.debit * currency_table.rate, currency_table.precision)) AS debit,
SUM(ROUND(account_move_line.credit * currency_table.rate, currency_table.precision)) AS credit,
SUM(ROUND(account_move_line.balance * currency_table.rate, currency_table.precision)) AS balance,
NULL AS account_code,
NULL AS account_name,
NULL AS partner_name,
NULL AS partner_vat
FROM {tables}
LEFT JOIN res_company company ON company.id = account_move_line.company_id
LEFT JOIN res_partner partner ON partner.id = account_move_line.partner_id
LEFT JOIN account_account account ON account.id = account_move_line.account_id
LEFT JOIN account_journal journal ON journal.id = account_move_line.journal_id
LEFT JOIN account_full_reconcile full_rec ON full_rec.id = account_move_line.full_reconcile_id
LEFT JOIN {ct_query} ON currency_table.company_id = account_move_line.company_id
WHERE {where_clause}
GROUP BY company.id
""")
return ' UNION ALL '.join(queries), params