diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py index e117b31346d..5b653e4c61f 100644 --- a/addons/account/__openerp__.py +++ b/addons/account/__openerp__.py @@ -47,7 +47,19 @@ You could use this simplified accounting in case you work with an (external) acc 'report/account_invoice_report_view.xml', 'report/inherited_layouts.xml', 'views/account_journal_dashboard_view.xml', + 'views/report_overdue.xml', 'views/web_planner_data.xml', + 'views/report_overdue.xml', + 'wizard/account_report_common_view.xml', + 'wizard/account_report_general_ledger_view.xml', + 'views/report_generalledger.xml', + 'wizard/account_report_trial_balance_view.xml', + 'views/report_trialbalance.xml', + 'views/account_financial_report_data.xml', + 'wizard/account_financial_report_view.xml', + 'views/report_financial.xml', + 'wizard/account_report_aged_partner_balance_view.xml', + 'views/report_agedpartnerbalance.xml', ], 'demo': [ 'demo/account_demo.xml', diff --git a/addons/account/models/company.py b/addons/account/models/company.py index d329003480b..1a5e8ff5551 100644 --- a/addons/account/models/company.py +++ b/addons/account/models/company.py @@ -35,7 +35,15 @@ class ResCompany(models.Model): property_stock_account_output_categ_id = fields.Many2one('account.account', oldname="property_stock_account_output_categ") property_stock_valuation_account_id = fields.Many2one('account.account') bank_journal_ids = fields.One2many('account.journal', 'company_id', domain=[('type', '=', 'bank')], string='Bank Journals') + overdue_msg = fields.Text(string='Overdue Payments Message', translate=True, + default='''Dear Sir/Madam, +Our records indicate that some payments on your account are still due. Please find details below. +If the amount has already been paid, please disregard this notice. Otherwise, please forward us the total amount stated below. +If you have any queries regarding your account, Please contact us. + +Thank you in advance for your cooperation. +Best Regards,''') @api.multi def compute_fiscalyear_dates(self, date): diff --git a/addons/account/report/__init__.py b/addons/account/report/__init__.py index e6d7f3e0c9c..95c6abf0dcf 100644 --- a/addons/account/report/__init__.py +++ b/addons/account/report/__init__.py @@ -3,3 +3,8 @@ import account_financial_report import account_invoice_report +import account_overdue_report +import account_general_ledger +import account_balance +import account_report_financial +import account_aged_partner_balance diff --git a/addons/account/report/account_aged_partner_balance.py b/addons/account/report/account_aged_partner_balance.py new file mode 100644 index 00000000000..d7670f2f621 --- /dev/null +++ b/addons/account/report/account_aged_partner_balance.py @@ -0,0 +1,299 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +class ReportAgedPartnerBalance(models.AbstractModel): + + _name = 'report.account.report_agedpartnerbalance' + + def _get_partner_move_lines(self, form, account_type, date_from, target_move): + res = [] + self.total_account = [] + cr = self.env.cr + move_state = ['draft', 'posted'] + if target_move == 'posted': + move_state = ['posted'] + cr.execute('SELECT DISTINCT res_partner.id AS id,\ + res_partner.name AS name \ + FROM res_partner,account_move_line AS l, account_account, account_move am\ + WHERE (l.account_id = account_account.id) \ + AND (l.move_id = am.id) \ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND l.reconciled IS FALSE\ + AND (l.partner_id = res_partner.id)\ + AND (l.date <= %s)\ + ORDER BY res_partner.name', (tuple(move_state), tuple(account_type), date_from)) + + partners = cr.dictfetchall() + # put a total of 0 + for i in range(7): + self.total_account.append(0) + + # Build a string like (1,2,3) for easy use in SQL query + partner_ids = [partner['id'] for partner in partners] + if not partner_ids: + return [] + + # This dictionary will store the debit-credit for all partners, using partner_id as key. + totals = {} + cr.execute('SELECT l.partner_id, SUM(l.debit-l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) \ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND (l.partner_id IN %s)\ + AND (l.date <= %s)\ + GROUP BY l.partner_id ', (tuple(move_state), tuple(account_type), tuple(partner_ids), date_from,)) + partner_totals = cr.fetchall() + for partner_id, amount in partner_totals: + totals[partner_id] = amount + + # This dictionary will store the future or past of all partners + future_past = {} + cr.execute('SELECT l.partner_id, SUM(l.debit - l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND (COALESCE(l.date_maturity,l.date) > %s)\ + AND (l.partner_id IN %s)\ + AND l.reconciled IS FALSE\ + AND (l.date <= %s)\ + GROUP BY l.partner_id', (tuple(move_state), tuple(account_type), date_from, tuple(partner_ids), date_from,)) + partner_totals = cr.fetchall() + for partner_id, amount in partner_totals: + future_past[partner_id] = amount + + # Use one query per period and store results in history (a list variable) + # Each history will contain: history[1] = {'': } + history = [] + for i in range(5): + args_list = (tuple(move_state), tuple(account_type), tuple(partner_ids),) + dates_query = '(COALESCE(l.date_maturity,l.date)' + + if form[str(i)]['start'] and form[str(i)]['stop']: + dates_query += ' BETWEEN %s AND %s)' + args_list += (form[str(i)]['start'], form[str(i)]['stop']) + elif form[str(i)]['start']: + dates_query += ' >= %s)' + args_list += (form[str(i)]['start'],) + else: + dates_query += ' <= %s)' + args_list += (form[str(i)]['stop'],) + args_list += (date_from,) + + cr.execute('''SELECT l.partner_id, SUM(l.debit - l.credit), l.id + FROM account_move_line AS l, account_account, account_move am + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id) + AND (am.state IN %s) + AND (account_account.internal_type IN %s) + AND (l.partner_id IN %s) + AND l.reconciled IS FALSE + AND ''' + dates_query + ''' + AND (l.date <= %s) + GROUP BY l.partner_id, l.id''', args_list) + partners_partial = cr.fetchall() + partners_amount = dict((partner_id, 0) for partner_id, amount, line_id in partners_partial) + + for partner_id, amount, line_id in partners_partial: + partial_reconcile_ids = [] + line = self.env['account.move.line'].browse(line_id) + for partial_line in (line.matched_debit_ids + line.matched_credit_ids): + if not partial_line.credit_move_id.id in partial_reconcile_ids: + partial_reconcile_ids.append(partial_line.credit_move_id.id) + if not partial_line.debit_move_id.id in partial_reconcile_ids: + partial_reconcile_ids.append(partial_line.debit_move_id.id) + if partial_reconcile_ids: + # in case of partial reconciliation, we want to keep the left amount in the oldest period + cr.execute('''SELECT MIN(COALESCE(date_maturity, date)) from account_move_line where id = %s''', (line_id,)) + date = cr.fetchall() + partial = False + if 'BETWEEN' in dates_query: + partial = date and args_list[-3] <= date[0][0] <= args_list[-2] + elif '>=' in dates_query: + partial = date and date[0][0] >= form[str(i)]['start'] + else: + partial = date and date[0][0] <= form[str(i)]['stop'] + if partial: + # partial reconcilation + limit_date = 'COALESCE(l.date_maturity, l.date) <= %s' + cr.execute('''SELECT SUM(l.debit - l.credit) + FROM account_move_line AS l, account_move AS am + WHERE l.move_id = am.id AND am.state IN %s + AND l.id IN %s + AND ''' + limit_date, (tuple(move_state), tuple(partial_reconcile_ids), date_from)) + unreconciled_amount = cr.fetchall() + partners_amount[partner_id] += unreconciled_amount[0][0] + else: + partners_amount[partner_id] += amount + history.append(partners_amount) + + for partner in partners: + values = {} + # Query here is replaced by one query which gets the all the partners their 'after' value + after = False + if future_past.has_key(partner['id']): # Making sure this partner actually was found by the query + after = [ future_past[partner['id']] ] + + self.total_account[6] = self.total_account[6] + (after and after[0] or 0.0) + values['direction'] = after and after[0] or 0.0 + + for i in range(5): + during = False + if history[i].has_key(partner['id']): + during = [ history[i][partner['id']] ] + # Adding counter + self.total_account[(i)] = self.total_account[(i)] + (during and during[0] or 0) + values[str(i)] = during and during[0] or 0.0 + total = False + if totals.has_key( partner['id'] ): + total = [ totals[partner['id']] ] + values['total'] = total and total[0] or 0.0 + ## Add for total + self.total_account[(i+1)] = self.total_account[(i+1)] + (total and total[0] or 0.0) + values['name'] = partner['name'] + + res.append(values) + + total = 0.0 + totals = {} + for r in res: + total += float(r['total'] or 0.0) + for i in range(5)+['direction']: + totals.setdefault(str(i), 0.0) + totals[str(i)] += float(r[str(i)] or 0.0) + return res + + def _get_move_lines_with_out_partner(self, form, account_type, date_from, target_move): + res = [] + cr = self.env.cr + move_state = ['draft', 'posted'] + if target_move == 'posted': + move_state = ['posted'] + + ## put a total of 0 + for i in range(7): + self.total_account.append(0) + totals = {} + cr.execute('SELECT SUM(l.debit - l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (l.partner_id IS NULL)\ + AND (account_account.internal_type IN %s)\ + AND l.reconciled IS FALSE \ + AND (l.date <= %s)\ + ',(tuple(move_state), tuple(account_type), date_from,)) + total_amount = cr.fetchall() + for amount in total_amount: + totals['Unknown Partner'] = amount[0] + future_past = {} + cr.execute('SELECT SUM(l.debit-l.credit) \ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (l.partner_id IS NULL)\ + AND (account_account.internal_type IN %s)\ + AND (COALESCE(l.date_maturity,l.date) > %s)\ + AND l.reconciled IS FALSE\ + ', (tuple(move_state), tuple(account_type), date_from,)) + total_amount = cr.fetchall() + for amount in total_amount: + future_past['Unknown Partner'] = amount[0] + + history = [] + for i in range(5): + args_list = (tuple(move_state), tuple(account_type)) + dates_query = '(COALESCE(l.date_maturity,l.date)' + if form[str(i)]['start'] and form[str(i)]['stop']: + dates_query += ' BETWEEN %s AND %s)' + args_list += (form[str(i)]['start'], form[str(i)]['stop']) + elif form[str(i)]['start']: + dates_query += ' > %s)' + args_list += (form[str(i)]['start'],) + else: + dates_query += ' < %s)' + args_list += (form[str(i)]['stop'],) + args_list += (date_from,) + cr.execute('SELECT SUM(l.debit - l.credit)\ + FROM account_move_line AS l, account_account, account_move am \ + WHERE (l.account_id = account_account.id) AND (l.move_id = am.id)\ + AND (am.state IN %s)\ + AND (account_account.internal_type IN %s)\ + AND (l.partner_id IS NULL)\ + AND l.reconciled IS FALSE\ + AND ' + dates_query + '\ + AND (l.date <= %s)\ + GROUP BY l.partner_id', args_list) + total_amount = cr.fetchall() + history_data = {} + for amount in total_amount: + history_data['Unknown Partner'] = amount[0] + history.append(history_data) + + values = {} + after = False + if future_past.has_key('Unknown Partner'): + after = [ future_past['Unknown Partner'] ] + self.total_account[6] = self.total_account[6] + (after and after[0] or 0.0) + values['direction'] = after and after[0] or 0.0 + + for i in range(5): + during = False + if history[i].has_key('Unknown Partner'): + during = [ history[i]['Unknown Partner'] ] + self.total_account[(i)] = self.total_account[(i)] + (during and during[0] or 0) + values[str(i)] = during and during[0] or 0.0 + + total = False + if totals.has_key( 'Unknown Partner' ): + total = [ totals['Unknown Partner'] ] + values['total'] = total and total[0] or 0.0 + ## Add for total + self.total_account[(i+1)] = self.total_account[(i+1)] + (total and total[0] or 0.0) + values['name'] = 'Unknown Partner' + + if values['total']: + res.append(values) + + total = 0.0 + totals = {} + for r in res: + total += float(r['total'] or 0.0) + for i in range(5)+['direction']: + totals.setdefault(str(i), 0.0) + totals[str(i)] += float(r[str(i)] or 0.0) + return res + + @api.multi + def render_html(self, data): + self.total_account = [] + model = self.env.context.get('active_model') + docs = self.env[model].browse(self.env.context.get('active_id')) + + target_move = data['form'].get('target_move', 'all') + date_from = data['form'].get('date_from', time.strftime('%Y-%m-%d')) + + if data['form']['result_selection'] == 'customer': + account_type = ['receivable'] + elif data['form']['result_selection'] == 'supplier': + account_type = ['payable'] + else: + account_type = ['payable','receivable'] + + without_partner_movelines = self._get_move_lines_with_out_partner(data['form'], account_type, date_from, target_move) + partner_movelines = self._get_partner_move_lines(data['form'], account_type, date_from, target_move) + movelines = partner_movelines + without_partner_movelines + docargs = { + 'doc_ids': self.ids, + 'doc_model': model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'get_partner_lines': movelines, + 'get_direction': self.total_account, + } + return self.env['report'].render('account.report_agedpartnerbalance', docargs) diff --git a/addons/account/report/account_balance.py b/addons/account/report/account_balance.py new file mode 100644 index 00000000000..825b978931c --- /dev/null +++ b/addons/account/report/account_balance.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +class ReportTrialBalance(models.AbstractModel): + _name = 'report.account.report_trialbalance' + + def _get_accounts(self, accounts, display_account): + """ compute the balance, debit and credit for the provided accounts + :Arguments: + `accounts`: list of accounts record, + `display_account`: it's used to display either all accounts or those accounts which balance is > 0 + :Returns a list of dictionary of Accounts with following key and value + `name`: Account name, + `code`: Account code, + `credit`: total amount of credit, + `debit`: total amount of debit, + `balance`: total amount of balance, + """ + + account_result = {} + # Prepare sql query base on selected parameters from wizard + tables, where_clause, where_params = self.env['account.move.line']._query_get() + tables = tables.replace('"','') + if not tables: + tables = 'account_move_line' + wheres = [""] + if where_clause.strip(): + wheres.append(where_clause.strip()) + filters = " AND ".join(wheres) + # compute the balance, debit and credit for the provided accounts + request = ("SELECT account_id AS id, SUM(debit) AS debit, SUM(credit) AS credit, (SUM(debit) - SUM(credit)) AS balance" +\ + " 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(): + account_result[row.pop('id')] = row + + account_res = [] + for account in accounts: + res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance']) + currency = account.currency_id and account.currency_id or account.company_id.currency_id + res['code'] = account.code + res['name'] = account.name + if account.id in account_result.keys(): + res['debit'] = account_result[account.id].get('debit') + res['credit'] = account_result[account.id].get('credit') + res['balance'] = account_result[account.id].get('balance') + if display_account == 'all': + account_res.append(res) + if display_account in ['movement', 'not_zero'] and not currency.is_zero(res['balance']): + account_res.append(res) + return account_res + + + @api.multi + def render_html(self, data): + self.model = self.env.context.get('active_model') + docs = self.env[self.model].browse(self.env.context.get('active_id')) + display_account = data['form'].get('display_account') + accounts = self.env['account.account'].search([]) + account_res = self.with_context(data['form'].get('used_context'))._get_accounts(accounts, display_account) + + docargs = { + 'doc_ids': self.ids, + 'doc_model': self.model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'Accounts': account_res, + } + return self.env['report'].render('account.report_trialbalance', docargs) diff --git a/addons/account/report/account_general_ledger.py b/addons/account/report/account_general_ledger.py new file mode 100644 index 00000000000..363a52bfe72 --- /dev/null +++ b/addons/account/report/account_general_ledger.py @@ -0,0 +1,133 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +class ReportGeneralLedger(models.AbstractModel): + _name = 'report.account.report_generalledger' + + def _get_account_move_entry(self, accounts, init_balance, sortby, display_account): + """ + :param: + accounts: the recordset of accounts + init_balance: boolean value of initial_balance + sortby: sorting by date or partner and journal + display_account: type of account(receivable, payable and both) + + Returns a dictionary of accounts with following key and value { + 'code': account code, + 'name': account name, + 'debit': sum of total debit amount, + 'credit': sum of total credit amount, + 'balance': total balance, + 'amount_currency': sum of amount_currency, + 'move_lines': list of move line + } + """ + cr = self.env.cr + MoveLine = self.env['account.move.line'] + move_lines = dict(map(lambda x: (x, []), accounts.ids)) + + # Prepare initial sql query and Get the initial move lines + if init_balance: + init_tables, init_where_clause, init_where_params = MoveLine.with_context(date_to=self.env.context.get('date_from'), date_from=False)._query_get() + init_wheres = [""] + if init_where_clause.strip(): + init_wheres.append(init_where_clause.strip()) + init_filters = " AND ".join(init_wheres) + filters = init_filters.replace('account_move_line__move_id', 'm').replace('account_move_line', 'l') + sql = ("SELECT 0 AS lid, l.account_id AS account_id, '' AS ldate, '' AS lcode, NULL AS amount_currency, '' AS lref, 'Initial Balance' AS lname, COALESCE(SUM(l.debit),0.0) AS debit, COALESCE(SUM(l.credit),0.0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) as balance, '' AS lpartner_id,\ + '' AS move_name, '' AS mmove_id, '' AS currency_code,\ + NULL AS currency_id,\ + '' AS invoice_id, '' AS invoice_type, '' AS invoice_number,\ + '' AS partner_name\ + FROM account_move_line l\ + LEFT JOIN account_move m ON (l.move_id=m.id)\ + LEFT JOIN res_currency c ON (l.currency_id=c.id)\ + LEFT JOIN res_partner p ON (l.partner_id=p.id)\ + LEFT JOIN account_invoice i ON (m.id =i.move_id)\ + JOIN account_journal j ON (l.journal_id=j.id)\ + WHERE l.account_id IN %s" + filters + ' GROUP BY l.account_id') + params = (tuple(accounts.ids),) + tuple(init_where_params) + cr.execute(sql, params) + for row in cr.dictfetchall(): + move_lines[row.pop('account_id')].append(row) + + sql_sort = 'l.date, l.move_id' + if sortby == 'sort_journal_partner': + sql_sort = 'j.code, p.name, l.move_id' + + # Prepare sql query base on selected parameters from wizard + tables, where_clause, where_params = MoveLine._query_get() + wheres = [""] + if where_clause.strip(): + wheres.append(where_clause.strip()) + filters = " AND ".join(wheres) + filters = filters.replace('account_move_line__move_id', 'm').replace('account_move_line', 'l') + + # Get move lines base on sql query and Calculate the total balance of move lines + sql = ('SELECT l.id AS lid, l.account_id AS account_id, l.date AS ldate, j.code AS lcode, l.currency_id, l.amount_currency, l.ref AS lref, l.name AS lname, COALESCE(l.debit,0) AS debit, COALESCE(l.credit,0) AS credit, COALESCE(SUM(l.debit),0) - COALESCE(SUM(l.credit), 0) AS balance,\ + m.name AS move_name, c.symbol AS currency_code, p.name AS partner_name\ + FROM account_move_line l\ + JOIN account_move m ON (l.move_id=m.id)\ + LEFT JOIN res_currency c ON (l.currency_id=c.id)\ + LEFT JOIN res_partner p ON (l.partner_id=p.id)\ + JOIN account_journal j ON (l.journal_id=j.id)\ + JOIN account_account acc ON (l.account_id = acc.id) \ + WHERE l.account_id IN %s ' + filters + ' GROUP BY l.id, l.account_id, l.date, j.code, l.currency_id, l.amount_currency, l.ref, l.name, m.name, c.symbol, p.name ORDER BY ' + sql_sort) + params = (tuple(accounts.ids),) + tuple(where_params) + cr.execute(sql, params) + + for row in cr.dictfetchall(): + balance = 0 + for line in move_lines.get(row['account_id']): + balance += line['debit'] - line['credit'] + row['balance'] += balance + move_lines[row.pop('account_id')].append(row) + + # Calculate the debit, credit and balance for Accounts + account_res = [] + for account in accounts: + currency = account.currency_id and account.currency_id or account.company_id.currency_id + res = dict((fn, 0.0) for fn in ['credit', 'debit', 'balance']) + res['code'] = account.code + res['name'] = account.name + res['move_lines'] = move_lines[account.id] + for line in res.get('move_lines'): + res['debit'] += line['debit'] + res['credit'] += line['credit'] + res['balance'] = line['balance'] + if display_account == 'all': + account_res.append(res) + if display_account == 'movement' and res.get('move_lines'): + account_res.append(res) + if display_account == 'not_zero' and not currency.is_zero(res['balance']): + account_res.append(res) + + return account_res + + @api.multi + def render_html(self, data): + self.model = self.env.context.get('active_model') + docs = self.env[self.model].browse(self.env.context.get('active_id')) + + init_balance = data['form'].get('initial_balance', True) + sortby = data['form'].get('sortby', 'sort_date') + display_account = data['form']['display_account'] + codes = [] + if data['form'].get('journal_ids', False): + codes = [journal.code for journal in self.env['account.journal'].search([('id', 'in', data['form']['journal_ids'])])] + + accounts = self.env['account.account'].search([]) + accounts_res = self.with_context(data['form'].get('used_context',{}))._get_account_move_entry(accounts, init_balance, sortby, display_account) + docargs = { + 'doc_ids': self.ids, + 'doc_model': self.model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'Accounts': accounts_res, + 'print_journal': codes, + } + return self.env['report'].render('account.report_generalledger', docargs) diff --git a/addons/account/report/account_overdue_report.py b/addons/account/report/account_overdue_report.py new file mode 100644 index 00000000000..6cfd79b1bbb --- /dev/null +++ b/addons/account/report/account_overdue_report.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, fields, models + + +class ReportOverdue(models.AbstractModel): + _name = 'report.account.report_overdue' + + def _get_account_move_lines(self, partner_ids): + res = dict(map(lambda x:(x,[]), partner_ids)) + self.env.cr.execute("SELECT m.name AS move_id, l.date, l.name, l.ref, l.date_maturity, l.partner_id, l.blocked, l.amount_currency, l.currency_id, " + "CASE WHEN at.type = 'receivable' " + "THEN SUM(l.debit) " + "ELSE SUM(l.credit * -1) " + "END AS debit, " + "CASE WHEN at.type = 'receivable' " + "THEN SUM(l.credit) " + "ELSE SUM(l.debit * -1) " + "END AS credit, " + "CASE WHEN l.date_maturity < %s " + "THEN SUM(l.debit - l.credit) " + "ELSE 0 " + "END AS mat " + "FROM account_move_line l " + "JOIN account_account_type at ON (l.user_type_id = at.id) " + "JOIN account_move m ON (l.move_id = m.id) " + "WHERE l.partner_id IN %s AND at.type IN ('receivable', 'payable') GROUP BY l.date, l.name, l.ref, l.date_maturity, l.partner_id, at.type, l.blocked, l.amount_currency, l.currency_id, l.move_id, m.name", (((fields.date.today(), ) + (tuple(partner_ids),)))) + for row in self.env.cr.dictfetchall(): + res[row.pop('partner_id')].append(row) + return res + + @api.multi + def render_html(self, data): + totals = {} + lines = self._get_account_move_lines(self.ids) + lines_to_display = {} + company_currency = self.env.user.company_id.currency_id + for partner_id in self.ids: + lines_to_display[partner_id] = {} + totals[partner_id] = {} + for line_tmp in lines[partner_id]: + line = line_tmp.copy() + currency = line['currency_id'] and self.env['res.currency'].browse(line['currency_id']) or company_currency + if currency not in lines_to_display[partner_id]: + lines_to_display[partner_id][currency] = [] + totals[partner_id][currency] = dict((fn, 0.0) for fn in ['due', 'paid', 'mat', 'total']) + if line['debit'] and line['currency_id']: + line['debit'] = line['amount_currency'] + if line['credit'] and line['currency_id']: + line['credit'] = line['amount_currency'] + if line['mat'] and line['currency_id']: + line['mat'] = line['amount_currency'] + lines_to_display[partner_id][currency].append(line) + if not line['blocked']: + totals[partner_id][currency]['due'] += line['debit'] + totals[partner_id][currency]['paid'] += line['credit'] + totals[partner_id][currency]['mat'] += line['mat'] + totals[partner_id][currency]['total'] += line['debit'] - line['credit'] + docargs = { + 'doc_ids': self.ids, + 'doc_model': 'res.partner', + 'docs': self.env['res.partner'].browse(self.ids), + 'time': time, + 'Lines': lines_to_display, + 'Totals': totals, + 'Date': fields.date.today(), + } + return self.env['report'].render('account.report_overdue', values=docargs) diff --git a/addons/account/report/account_report_financial.py b/addons/account/report/account_report_financial.py new file mode 100644 index 00000000000..c5139dadd98 --- /dev/null +++ b/addons/account/report/account_report_financial.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- + +import time +from openerp import api, models + + +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((fn, 0.0) for fn in mapping.keys()) + 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'] * 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'] * 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'): + 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'] * 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'] * report.sign + if not account.company_id.currency_id.is_zero(vals['balance_cmp']): + flag = True + if flag: + lines.append(vals) + return lines + + @api.multi + def render_html(self, data): + 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')) + docargs = { + 'doc_ids': self.ids, + 'doc_model': self.model, + 'data': data['form'], + 'docs': docs, + 'time': time, + 'get_account_lines': report_lines, + } + return self.env['report'].render('account.report_financial', docargs) diff --git a/addons/account/test/account_report.yml b/addons/account/test/account_report.yml index 3383bfcc93a..1ca246e6ce7 100644 --- a/addons/account/test/account_report.yml +++ b/addons/account/test/account_report.yml @@ -72,18 +72,10 @@ from openerp.tools import test_reports test_reports.try_report_action(cr, uid, 'action_account_general_journal',wiz_data=data_dict, context=ctx, our_module='account') - - Print the General Ledger Report in Normal Mode + Print the General Ledger Report (in Landscape Mode) - !python {model: account.account}: | ctx={} - data_dict = {'chart_account_id':ref('account.chart0'),'landscape':False} - from openerp.tools import test_reports - test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu',wiz_data=data_dict, context=ctx, our_module='account') -- - Print the General Ledger Report in Landscape Mode -- - !python {model: account.account}: | - ctx={'landscape': True} data_dict = {'chart_account_id':ref('account.chart0')} from openerp.tools import test_reports test_reports.try_report_action(cr, uid, 'action_account_general_ledger_menu',wiz_data=data_dict, context=ctx, our_module='account') diff --git a/addons/account/views/account_financial_report_data.xml b/addons/account/views/account_financial_report_data.xml new file mode 100644 index 00000000000..fc224a0f1b5 --- /dev/null +++ b/addons/account/views/account_financial_report_data.xml @@ -0,0 +1,68 @@ + + + + + + Profit and Loss + + sum + + + + Income + + + detail_with_hierarchy + account_type + + + + + Expense + + + detail_with_hierarchy + account_type + + + + + Balance Sheet + sum + + + + Assets + + detail_with_hierarchy + account_type + + + + + Liability + + no_detail + sum + + + + Liability + + detail_with_hierarchy + account_type + + + + + Profit (Loss) to report + + no_detail + account_report + + + + + diff --git a/addons/account/views/account_menuitem.xml b/addons/account/views/account_menuitem.xml index f01ad344c3e..732a9e956d3 100644 --- a/addons/account/views/account_menuitem.xml +++ b/addons/account/views/account_menuitem.xml @@ -27,6 +27,9 @@ + + + diff --git a/addons/account/views/account_report.xml b/addons/account/views/account_report.xml index 49137185597..0b601b0a655 100644 --- a/addons/account/views/account_report.xml +++ b/addons/account/views/account_report.xml @@ -23,5 +23,51 @@ attachment_use="False" /> + + + + + + + + + + diff --git a/addons/account/views/account_view.xml b/addons/account/views/account_view.xml index 27196e9d72f..f6621a6197d 100644 --- a/addons/account/views/account_view.xml +++ b/addons/account/views/account_view.xml @@ -1798,6 +1798,99 @@ parent="menu_finance_payables" action="base.action_partner_supplier_form" sequence="100"/> + + + + account.financial.report.form + account.financial.report + +
+ + + + + + + + + + + + + + + + + + +
+
+
+ + + account.financial.report.tree + account.financial.report + + + + + + + + + + + + account.financial.report.search + account.financial.report + + + + + + + + + + + + + + + Financial Reports + ir.actions.act_window + account.financial.report + form + tree,form + + + + + + + + account.report.hierarchy + account.financial.report + children_ids + + + + + + + + + + + + Financial Reports Hierarchy + account.financial.report + tree + + [('parent_id','=',False)] + + + diff --git a/addons/account/views/company_view.xml b/addons/account/views/company_view.xml index 98753231cda..06e1648b4a3 100644 --- a/addons/account/views/company_view.xml +++ b/addons/account/views/company_view.xml @@ -14,6 +14,12 @@ + + + + + + diff --git a/addons/account/views/report_agedpartnerbalance.xml b/addons/account/views/report_agedpartnerbalance.xml new file mode 100644 index 00000000000..e4e3a8451b3 --- /dev/null +++ b/addons/account/views/report_agedpartnerbalance.xml @@ -0,0 +1,95 @@ + + + + diff --git a/addons/account/views/report_financial.xml b/addons/account/views/report_financial.xml new file mode 100644 index 00000000000..2647ed10fa7 --- /dev/null +++ b/addons/account/views/report_financial.xml @@ -0,0 +1,110 @@ + + + + diff --git a/addons/account/views/report_generalledger.xml b/addons/account/views/report_generalledger.xml new file mode 100644 index 00000000000..9e2300098b1 --- /dev/null +++ b/addons/account/views/report_generalledger.xml @@ -0,0 +1,107 @@ + + + + + diff --git a/addons/account/views/report_overdue.xml b/addons/account/views/report_overdue.xml new file mode 100644 index 00000000000..d92a5c8c67d --- /dev/null +++ b/addons/account/views/report_overdue.xml @@ -0,0 +1,88 @@ + + + + + + diff --git a/addons/account/views/report_trialbalance.xml b/addons/account/views/report_trialbalance.xml new file mode 100644 index 00000000000..5470f6385ed --- /dev/null +++ b/addons/account/views/report_trialbalance.xml @@ -0,0 +1,68 @@ + + + + diff --git a/addons/account/wizard/__init__.py b/addons/account/wizard/__init__.py index 185cab9ac96..b5eadcd620f 100644 --- a/addons/account/wizard/__init__.py +++ b/addons/account/wizard/__init__.py @@ -9,3 +9,10 @@ import account_invoice_state import account_validate_account_move import pos_box import account_move_reversal +import account_report_common +import account_report_common_account +import account_report_common_partner +import account_report_general_ledger +import account_report_trial_balance +import account_financial_report +import account_report_aged_partner_balance diff --git a/addons/account/wizard/account_financial_report.py b/addons/account/wizard/account_financial_report.py new file mode 100644 index 00000000000..040093a4531 --- /dev/null +++ b/addons/account/wizard/account_financial_report.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- + +from openerp import api, fields, models + + +class AccountingReport(models.TransientModel): + _name = "accounting.report" + _inherit = "account.common.report" + _description = "Accounting Report" + + @api.model + def _get_account_report(self): + reports = [] + if self._context.get('active_id'): + menu = self.env['ir.ui.menu'].browse(self._context.get('active_id')).name + reports = self.env['account.financial.report'].search([('name', 'ilike', menu)]) + return reports and reports[0] or False + + enable_filter = fields.Boolean(string='Enable Comparison') + account_report_id = fields.Many2one('account.financial.report', string='Account Reports', required=True, default=_get_account_report) + label_filter = fields.Char(string='Column Label', help="This label will be displayed on report to show the balance computed for the given comparison filter.") + filter_cmp = fields.Selection([('filter_no', 'No Filters'), ('filter_date', 'Date')], string='Filter by', required=True, default='filter_no') + date_from_cmp = fields.Date(string='Start Date') + date_to_cmp = fields.Date(string='End Date') + debit_credit = fields.Boolean(string='Display Debit/Credit Columns', help="This option allows you to get more details about the way your balances are computed. Because it is space consuming, we do not allow to use it while doing a comparison.") + + def _build_comparison_context(self, data): + result = {} + result['journal_ids'] = 'journal_ids' in data['form'] and data['form']['journal_ids'] or False + result['state'] = 'target_move' in data['form'] and data['form']['target_move'] or '' + if data['form']['filter_cmp'] == 'filter_date': + result['date_from'] = data['form']['date_from_cmp'] + result['date_to'] = data['form']['date_to_cmp'] + result['strict_range'] = True + return result + + @api.multi + def check_report(self): + res = super(AccountingReport, self).check_report() + data = {} + data['form'] = self.read(['account_report_id', 'date_from_cmp', 'date_to_cmp', 'journal_ids', 'filter_cmp', 'target_move'])[0] + for field in ['account_report_id']: + if isinstance(data['form'][field], tuple): + data['form'][field] = data['form'][field][0] + comparison_context = self._build_comparison_context(data) + res['data']['form']['comparison_context'] = comparison_context + return res + + def _print_report(self, data): + data['form'].update(self.read(['date_from_cmp', 'debit_credit', 'date_to_cmp', 'filter_cmp', 'account_report_id', 'enable_filter', 'label_filter', 'target_move'])[0]) + return self.env['report'].get_action(self, 'account.report_financial', data=data) diff --git a/addons/account/wizard/account_financial_report_view.xml b/addons/account/wizard/account_financial_report_view.xml new file mode 100644 index 00000000000..395b65331bd --- /dev/null +++ b/addons/account/wizard/account_financial_report_view.xml @@ -0,0 +1,72 @@ + + + + + Accounting Report + accounting.report + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Balance Sheet + accounting.report + ir.actions.act_window + form + form + + new + + + + + + + Profit and Loss + accounting.report + ir.actions.act_window + form + form + + new + + + + + + + Financial Reports + accounting.report + ir.actions.act_window + form + form + + new + + + + + diff --git a/addons/account/wizard/account_report_aged_partner_balance.py b/addons/account/wizard/account_report_aged_partner_balance.py new file mode 100644 index 00000000000..c5579a32a56 --- /dev/null +++ b/addons/account/wizard/account_report_aged_partner_balance.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- + +import time +from datetime import datetime +from dateutil.relativedelta import relativedelta +from openerp import api, fields, models, _ +from openerp.exceptions import UserError + + +class AccountAgedTrialBalance(models.TransientModel): + + _name = 'account.aged.trial.balance' + _inherit = 'account.common.partner.report' + _description = 'Account Aged Trial balance Report' + + period_length = fields.Integer(string='Period Length (days)', required=True, default=30) + journal_ids = fields.Many2many('account.journal', string='Journals', required=True) + date_from = fields.Date(default=lambda *a: time.strftime('%Y-%m-%d')) + + def _print_report(self, data): + res = {} + data = self.pre_print_report(data) + data['form'].update(self.read(['period_length'])[0]) + period_length = data['form']['period_length'] + if period_length<=0: + raise UserError(_('You must set a period length greater than 0.')) + if not data['form']['date_from']: + raise UserError(_('You must set a start date.')) + + start = datetime.strptime(data['form']['date_from'], "%Y-%m-%d") + + for i in range(5)[::-1]: + stop = start - relativedelta(days=period_length) + res[str(i)] = { + 'name': (i!=0 and (str((5-(i+1)) * period_length) + '-' + str((5-i) * period_length)) or ('+'+str(4 * period_length))), + 'stop': start.strftime('%Y-%m-%d'), + 'start': (i!=0 and stop.strftime('%Y-%m-%d') or False), + } + start = stop - relativedelta(days=1) + data['form'].update(res) + return self.env['report'].with_context(landscape=True).get_action(self, 'account.report_agedpartnerbalance', data=data) diff --git a/addons/account/wizard/account_report_aged_partner_balance_view.xml b/addons/account/wizard/account_report_aged_partner_balance_view.xml new file mode 100644 index 00000000000..133f20c0347 --- /dev/null +++ b/addons/account/wizard/account_report_aged_partner_balance_view.xml @@ -0,0 +1,44 @@ + + + + + Aged Partner Balance + account.aged.trial.balance + +
+ +
+ + + Aged Partner Balance + account.aged.trial.balance + ir.actions.act_window + form + tree,form + + {} + new + + + + +
diff --git a/addons/account/wizard/account_report_common.py b/addons/account/wizard/account_report_common.py new file mode 100644 index 00000000000..a11404a34bd --- /dev/null +++ b/addons/account/wizard/account_report_common.py @@ -0,0 +1,39 @@ +# -*- coding: utf-8 -*- + +from openerp import api, fields, models, _ + + +class AccountCommonReport(models.TransientModel): + _name = "account.common.report" + _description = "Account Common Report" + + company_id = fields.Many2one('res.company', string='Company', readonly=True, default=lambda self: self.env.user.company_id) + journal_ids = fields.Many2many('account.journal', string='Journals', required=True, default=lambda self: self.env['account.journal'].search([])) + date_from = fields.Date(string='Start Date') + date_to = fields.Date(string='End Date') + target_move = fields.Selection([('posted', 'All Posted Entries'), + ('all', 'All Entries'), + ], string='Target Moves', required=True, default='posted') + + def _build_contexts(self, data): + result = {} + result['journal_ids'] = 'journal_ids' in data['form'] and data['form']['journal_ids'] or False + result['state'] = 'target_move' in data['form'] and data['form']['target_move'] or '' + result['date_from'] = data['form']['date_from'] or False + result['date_to'] = data['form']['date_to'] or False + result['strict_range'] = True if result['date_from'] else False + return result + + def _print_report(self, data): + raise (_('Error!'), _('Not implemented.')) + + @api.multi + def check_report(self): + self.ensure_one() + data = {} + data['ids'] = self.env.context.get('active_ids', []) + data['model'] = self.env.context.get('active_model', 'ir.ui.menu') + data['form'] = self.read(['date_from', 'date_to', 'journal_ids', 'target_move'])[0] + used_context = self._build_contexts(data) + data['form']['used_context'] = dict(used_context, lang=self.env.context.get('lang', 'en_US')) + return self._print_report(data) diff --git a/addons/account/wizard/account_report_common_account.py b/addons/account/wizard/account_report_common_account.py new file mode 100644 index 00000000000..e483b408d8b --- /dev/null +++ b/addons/account/wizard/account_report_common_account.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from openerp import api, fields, models + + +class AccountCommonAccountReport(models.TransientModel): + _name = 'account.common.account.report' + _description = 'Account Common Account Report' + _inherit = "account.common.report" + + display_account = fields.Selection([('all','All'), ('movement','With movements'), + ('not_zero','With balance is not equal to 0'),], + string='Display Accounts', required=True, default='movement') + + @api.multi + def pre_print_report(self, data): + data['form'].update(self.read(['display_account'])[0]) + return data diff --git a/addons/account/wizard/account_report_common_partner.py b/addons/account/wizard/account_report_common_partner.py new file mode 100644 index 00000000000..c4ca6e8dad2 --- /dev/null +++ b/addons/account/wizard/account_report_common_partner.py @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- + +from openerp import fields, models + + +class AccountingCommonPartnerReport(models.TransientModel): + _name = 'account.common.partner.report' + _description = 'Account Common Partner Report' + _inherit = "account.common.report" + + result_selection = fields.Selection([('customer', 'Receivable Accounts'), + ('supplier', 'Payable Accounts'), + ('customer_supplier', 'Receivable and Payable Accounts') + ], string="Partner's", required=True, default='customer') + + def pre_print_report(self, data): + data['form'].update(self.read(['result_selection'])[0]) + return data diff --git a/addons/account/wizard/account_report_common_view.xml b/addons/account/wizard/account_report_common_view.xml new file mode 100644 index 00000000000..5f210eff9e7 --- /dev/null +++ b/addons/account/wizard/account_report_common_view.xml @@ -0,0 +1,36 @@ + + + + + Common Report + account.common.report + +
+ + + + + + + + + +
+
+ +
+
+ + + Common Report + account.common.report + form + form + + new + + +
diff --git a/addons/account/wizard/account_report_general_ledger.py b/addons/account/wizard/account_report_general_ledger.py new file mode 100644 index 00000000000..0f9d959c7f7 --- /dev/null +++ b/addons/account/wizard/account_report_general_ledger.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from openerp import fields, models, _ +from openerp.exceptions import UserError + + +class AccountReportGeneralLedger(models.TransientModel): + _inherit = "account.common.account.report" + _name = "account.report.general.ledger" + _description = "General Ledger Report" + + initial_balance = fields.Boolean(string='Include Initial Balances', + help='If you selected date, this field allow you to add a row to display the amount of debit/credit/balance that precedes the filter you\'ve set.') + sortby = fields.Selection([('sort_date', 'Date'), ('sort_journal_partner', 'Journal & Partner')], string='Sort by', required=True, default='sort_date') + journal_ids = fields.Many2many('account.journal', 'account_report_general_ledger_journal_rel', 'account_id', 'journal_id', string='Journals', required=True) + + def _print_report(self, data): + data = self.pre_print_report(data) + data['form'].update(self.read(['initial_balance', 'sortby'])[0]) + if data['form'].get('initial_balance') and not data['form'].get('date_from'): + raise UserError(_("You must define a Start Date")) + return self.env['report'].with_context(landscape=True).get_action(self, 'account.report_generalledger', data=data) diff --git a/addons/account/wizard/account_report_general_ledger_view.xml b/addons/account/wizard/account_report_general_ledger_view.xml new file mode 100644 index 00000000000..91fbdc9cb6b --- /dev/null +++ b/addons/account/wizard/account_report_general_ledger_view.xml @@ -0,0 +1,47 @@ + + + + + General Ledger + account.report.general.ledger + + + + + + + + + + + + + + + General Ledger + ir.actions.act_window + account.report.general.ledger + form + form + + new + + + + + General Ledger + client_print_multi + + action + account.account + + + + + diff --git a/addons/account/wizard/account_report_trial_balance.py b/addons/account/wizard/account_report_trial_balance.py new file mode 100644 index 00000000000..251c8c09dbc --- /dev/null +++ b/addons/account/wizard/account_report_trial_balance.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- + +from openerp import fields, models + + +class AccountBalanceReport(models.TransientModel): + _inherit = "account.common.account.report" + _name = 'account.balance.report' + _description = 'Trial Balance Report' + + journal_ids = fields.Many2many('account.journal', 'account_balance_report_journal_rel', 'account_id', 'journal_id', string='Journals', required=True, default=[]) + + def _print_report(self, data): + data = self.pre_print_report(data) + return self.env['report'].get_action(self, 'account.report_trialbalance', data=data) diff --git a/addons/account/wizard/account_report_trial_balance_view.xml b/addons/account/wizard/account_report_trial_balance_view.xml new file mode 100644 index 00000000000..a610d5e863d --- /dev/null +++ b/addons/account/wizard/account_report_trial_balance_view.xml @@ -0,0 +1,44 @@ + + + + + + Trial Balance + account.balance.report + + + + + + + + + + + + + + Trial Balance + ir.actions.act_window + account.balance.report + form + form + + new + + + + + + + Trial Balance + client_print_multi + + action + account.account + + +