X-Git-Url: http://git.cyclocoop.org/?p=burette%2Faccount_financial_report_webkit.git;a=blobdiff_plain;f=report%2Fcommon_partner_balance_reports.py;fp=report%2Fcommon_partner_balance_reports.py;h=eeec0c53eadaec712c63b752061d6d58ee7e51bb;hp=0000000000000000000000000000000000000000;hb=cddef38e342c880228694525c45df3f7dd8c2148;hpb=bffd331c220385010fe9abad9e228fc2004a293a diff --git a/report/common_partner_balance_reports.py b/report/common_partner_balance_reports.py new file mode 100644 index 0000000..eeec0c5 --- /dev/null +++ b/report/common_partner_balance_reports.py @@ -0,0 +1,276 @@ +# -*- encoding: utf-8 -*- +############################################################################## +# +# Author: Guewen Baconnier +# Copyright Camptocamp SA 2011 +# SQL inspired from OpenERP original code +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +from collections import defaultdict +from operator import add + +from .common_balance_reports import CommonBalanceReportHeaderWebkit +from .common_partner_reports import CommonPartnersReportHeaderWebkit + + +class CommonPartnerBalanceReportHeaderWebkit(CommonBalanceReportHeaderWebkit, CommonPartnersReportHeaderWebkit): + """Define common helper for balance (trial balance, P&L, BS oriented financial report""" + + def _get_account_partners_details(self, account_by_ids, main_filter, target_move, start, + stop, initial_balance_mode, partner_filter_ids=False): + res = {} + filter_from = False + if main_filter in ('filter_period', 'filter_no', 'filter_opening'): + filter_from = 'period' + elif main_filter == 'filter_date': + filter_from = 'date' + + partners_init_balances_by_ids = {} + for account_id, account_details in account_by_ids.iteritems(): + partners_init_balances_by_ids.update(self._get_partners_initial_balances(account_id, + start, + initial_balance_mode, + partner_filter_ids=partner_filter_ids, + exclude_reconcile=False)) # we'll never exclude reconciled entries in the legal reports + opening_mode = 'exclude_opening' + if main_filter == 'filter_opening': + opening_mode = 'include_opening' + # get credit and debit for partner + details = self._get_partners_totals_account(filter_from, + account_id, + start, + stop, + target_move, + partner_filter_ids=partner_filter_ids, + mode=opening_mode) + + # merge initial balances in partner details + if partners_init_balances_by_ids.get(account_id): + for partner_id, initial_balances in partners_init_balances_by_ids[account_id].iteritems(): + if initial_balances.get('init_balance'): + details[partner_id].update({'init_balance': initial_balances['init_balance']}) + + # compute balance for the partner + for partner_id, partner_details in details.iteritems(): + details[partner_id]['balance'] = details[partner_id].get('init_balance', 0.0) +\ + details[partner_id].get('debit', 0.0) -\ + details[partner_id].get('credit', 0.0) + res[account_id] = details + + return res + + def _get_partners_initial_balances(self, account_ids, start_period, initial_balance_mode, partner_filter_ids=None, exclude_reconcile=False): + # we get the initial balance from the opening period (opening_balance) when the opening period is included in the start period and + # when there is at least one entry in the opening period. Otherwise we compute it from previous periods + if initial_balance_mode == 'opening_balance': + opening_period_selected = self.get_included_opening_period(start_period) + res = self._compute_partners_initial_balances(account_ids, start_period, partner_filter_ids, force_period_ids=opening_period_selected, exclude_reconcile=exclude_reconcile) + elif initial_balance_mode == 'initial_balance': + res = self._compute_partners_initial_balances(account_ids, start_period, partner_filter_ids, exclude_reconcile=exclude_reconcile) + else: + res = {} + return res + + def _get_partners_totals_account(self, filter_from, account_id, start, stop, target_move, partner_filter_ids=None, mode='exclude_opening'): + final_res = defaultdict(dict) + + sql_select = """ + SELECT account_move_line.partner_id, + sum(account_move_line.debit) AS debit, + sum(account_move_line.credit) AS credit + FROM account_move_line""" + sql_joins = '' + sql_where = "WHERE account_move_line.account_id = %(account_id)s AND account_move_line.state = 'valid' " + method = getattr(self, '_get_query_params_from_' + filter_from + 's') + sql_conditions, search_params = method(start, stop, mode=mode) + sql_where += sql_conditions + + if partner_filter_ids: + sql_where += " AND account_move_line.partner_id in %(partner_ids)s" + search_params.update({'partner_ids': tuple(partner_filter_ids)}) + + if target_move == 'posted': + sql_joins += "INNER JOIN account_move ON account_move_line.move_id = account_move.id" + sql_where += " AND account_move.state = %(target_move)s" + search_params.update({'target_move': target_move}) + + sql_groupby = "GROUP BY account_move_line.partner_id" + + search_params.update({'account_id': account_id}) + query = ' '.join((sql_select, sql_joins, sql_where, sql_groupby)) + + self.cursor.execute(query, search_params) + res = self.cursor.dictfetchall() + if res: + for row in res: + final_res[row['partner_id']] = row + return final_res + + def _get_filter_type(self, result_selection): + filter_type = ('payable', 'receivable') + if result_selection == 'customer': + filter_type = ('receivable',) + if result_selection == 'supplier': + filter_type = ('payable',) + return filter_type + + def _get_partners_comparison_details(self, data, account_ids, target_move, comparison_filter, index, partner_filter_ids=False): + """ + + @param data: data of the wizard form + @param account_ids: ids of the accounts to get details + @param comparison_filter: selected filter on the form for the comparison (filter_no, filter_year, filter_period, filter_date) + @param index: index of the fields to get (ie. comp1_fiscalyear_id where 1 is the index) + @param partner_filter_ids: list of ids of partners to select + @return: dict of account details (key = account id) + """ + fiscalyear = self._get_info(data, "comp%s_fiscalyear_id" % (index,), 'account.fiscalyear') + start_period = self._get_info(data, "comp%s_period_from" % (index,), 'account.period') + stop_period = self._get_info(data, "comp%s_period_to" % (index,), 'account.period') + start_date = self._get_form_param("comp%s_date_from" % (index,), data) + stop_date = self._get_form_param("comp%s_date_to" % (index,), data) + init_balance = self.is_initial_balance_enabled(comparison_filter) + + comp_params = {} + accounts_details_by_ids = defaultdict(dict) + if comparison_filter != 'filter_no': + start_period, stop_period, start, stop = \ + self._get_start_stop_for_filter(comparison_filter, fiscalyear, start_date, stop_date, start_period, stop_period) + details_filter = comparison_filter + if comparison_filter == 'filter_year': + details_filter = 'filter_no' + + initial_balance_mode = init_balance and self._get_initial_balance_mode(start) or False + + accounts_by_ids = self._get_account_details(account_ids, target_move, fiscalyear, details_filter, start, stop, initial_balance_mode) + + partner_details_by_ids = self._get_account_partners_details(accounts_by_ids, details_filter, + target_move, start, stop, initial_balance_mode, + partner_filter_ids=partner_filter_ids) + + for account_id in account_ids: + accounts_details_by_ids[account_id]['account'] = accounts_by_ids[account_id] + accounts_details_by_ids[account_id]['partners_amounts'] = partner_details_by_ids[account_id] + + comp_params = { + 'comparison_filter': comparison_filter, + 'fiscalyear': fiscalyear, + 'start': start, + 'stop': stop, + 'initial_balance_mode': initial_balance_mode, + } + + return accounts_details_by_ids, comp_params + + def compute_partner_balance_data(self, data, filter_report_type=None): + new_ids = data['form']['account_ids'] or data['form']['chart_account_id'] + max_comparison = self._get_form_param('max_comparison', data, default=0) + main_filter = self._get_form_param('filter', data, default='filter_no') + + comp_filters, nb_comparisons, comparison_mode = self._comp_filters(data, max_comparison) + + fiscalyear = self.get_fiscalyear_br(data) + + start_period = self.get_start_period_br(data) + stop_period = self.get_end_period_br(data) + target_move = self._get_form_param('target_move', data, default='all') + start_date = self._get_form_param('date_from', data) + stop_date = self._get_form_param('date_to', data) + chart_account = self._get_chart_account_id_br(data) + result_selection = self._get_form_param('result_selection', data) + partner_ids = self._get_form_param('partner_ids', data) + + filter_type = self._get_filter_type(result_selection) + + start_period, stop_period, start, stop = \ + self._get_start_stop_for_filter(main_filter, fiscalyear, start_date, stop_date, start_period, stop_period) + + initial_balance = self.is_initial_balance_enabled(main_filter) + initial_balance_mode = initial_balance and self._get_initial_balance_mode(start) or False + + # Retrieving accounts + account_ids = self.get_all_accounts(new_ids, only_type=filter_type, + filter_report_type=filter_report_type) + + # get details for each accounts, total of debit / credit / balance + accounts_by_ids = self._get_account_details(account_ids, target_move, fiscalyear, main_filter, start, stop, initial_balance_mode) + + partner_details_by_ids = self._get_account_partners_details(accounts_by_ids, + main_filter, + target_move, + start, + stop, + initial_balance_mode, + partner_filter_ids=partner_ids) + + comparison_params = [] + comp_accounts_by_ids = [] + for index in range(max_comparison): + if comp_filters[index] != 'filter_no': + comparison_result, comp_params = self._get_partners_comparison_details(data, account_ids, + target_move, comp_filters[index], + index, partner_filter_ids=partner_ids) + comparison_params.append(comp_params) + comp_accounts_by_ids.append(comparison_result) + objects = [] + + for account in self.pool.get('account.account').browse(self.cursor, self.uid, account_ids): + if not account.parent_id: # hide top level account + continue + account.debit = accounts_by_ids[account.id]['debit'] + account.credit = accounts_by_ids[account.id]['credit'] + account.balance = accounts_by_ids[account.id]['balance'] + account.init_balance = accounts_by_ids[account.id].get('init_balance', 0.0) + account.partners_amounts = partner_details_by_ids[account.id] + comp_accounts = [] + for comp_account_by_id in comp_accounts_by_ids: + values = comp_account_by_id.get(account.id) + + values['account'].update(self._get_diff(account.balance, values['account'].get('balance', 0.0))) + comp_accounts.append(values) + + for partner_id, partner_values in values['partners_amounts'].copy().iteritems(): + base_partner_balance = account.partners_amounts[partner_id]['balance'] if \ + account.partners_amounts.get(partner_id) else 0.0 + partner_values.update(self._get_diff(base_partner_balance, + partner_values.get('balance', 0.0))) + values['partners_amounts'][partner_id].update(partner_values) + + account.comparisons = comp_accounts + + all_partner_ids = reduce(add, [comp['partners_amounts'].keys() for comp in comp_accounts], + account.partners_amounts.keys()) + + account.partners_order = self._order_partners(all_partner_ids) + + objects.append(account) + + context_report_values = { + 'fiscalyear': fiscalyear, + 'start_date': start_date, + 'stop_date': stop_date, + 'start_period': start_period, + 'stop_period': stop_period, + 'chart_account': chart_account, + 'comparison_mode': comparison_mode, + 'nb_comparison': nb_comparisons, + 'comp_params': comparison_params, + 'initial_balance_mode': initial_balance_mode, + 'compute_diff': self._get_diff, + } + + return objects, new_ids, context_report_values