From 76321d62c86815d1351e6364a172d9462c4045ae Mon Sep 17 00:00:00 2001 From: jcoux Date: Thu, 30 Jun 2016 15:46:38 +0200 Subject: [PATCH] Add OCA Open Invoice report --- account_financial_report_qweb/menuitems.xml | 9 +- .../report/open_invoice.py | 724 ++++++++++++++++-- .../report/templates/open_invoice_report.xml | 331 ++++---- account_financial_report_qweb/reports.xml | 34 +- .../wizard/open_invoice_wizard.py | 123 +-- .../wizard/open_invoice_wizard_view.xml | 47 +- 6 files changed, 922 insertions(+), 346 deletions(-) diff --git a/account_financial_report_qweb/menuitems.xml b/account_financial_report_qweb/menuitems.xml index ff8fd49c..55dfd119 100644 --- a/account_financial_report_qweb/menuitems.xml +++ b/account_financial_report_qweb/menuitems.xml @@ -33,9 +33,12 @@ - + + diff --git a/account_financial_report_qweb/report/open_invoice.py b/account_financial_report_qweb/report/open_invoice.py index 6f1d0e9c..c3dfc2f4 100644 --- a/account_financial_report_qweb/report/open_invoice.py +++ b/account_financial_report_qweb/report/open_invoice.py @@ -1,58 +1,674 @@ # -*- coding: utf-8 -*- -# Author: Andrea andrea4ever Gallina -# Author: Francesco OpenCode Apruzzese -# Author: Ciro CiroBoxHub Urselli -# Copyright 2016 Camptocamp SA +# © 2016 Julien Coux (Camptocamp) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +from openerp import models, fields, api -from openerp import models, api - - -class OpenInvoiceReport(models.AbstractModel): - - _name = 'report.account_financial_report_qweb.open_invoice_report_qweb' - - def _get_domain(self, data): - account_type = ('payable', 'receivable') - if data['form']['result_selection'] == 'customer': - account_type = ('receivable', ) - elif data['form']['result_selection'] == 'supplier': - account_type = ('payable', ) - domain = [ - ('company_id', '=', data['form']['company_id'][0]), - ('move_id.date', '<=', data['form']['at_date']), - ('account_id.user_type_id.type', 'in', account_type) - ] - if data['form']['target_move'] != 'all': - domain.append(('move_id.state', 'in', ('posted', )), ) - if data['form']['partner_ids']: - domain.append(('partner_id', 'in', - [p.id for p in data['form']['partner_ids']]), ) - return domain - - def _query(self, data): - - moves = self.env['account.move.line'].search( - self._get_domain(data), order='date asc') - if not moves: - return True # ----- Show a message here - return moves - - @api.multi - def render_html(self, data=None): - report_obj = self.env['report'] - moves = self._query(data) - docargs = { - 'doc_model': 'account.move.line', - 'doc_ids': data['ids'], - 'docs': moves, - 'header': data['header'], - 'account_obj': self.env['account.account'], - 'partner_obj': self.env['res.partner'], - 'currency_obj': self.env['res.currency'], - } - - return report_obj.render( - 'account_financial_report_qweb.open_invoice_report_qweb', - docargs) + +class OpenInvoiceReport(models.TransientModel): + """ Here, we just define class fields. + For methods, go more bottom at this file. + """ + + _name = 'report_open_invoice_qweb' + + date_at = fields.Date() + only_posted_moves = fields.Boolean() + hide_account_balance_at_0 = fields.Boolean() + company_id = fields.Many2one(comodel_name='res.company') + filter_account_ids = fields.Many2many(comodel_name='account.account') + filter_partner_ids = fields.Many2many(comodel_name='res.partner') + has_second_currency = fields.Boolean() + + account_ids = fields.One2many( + comodel_name='report_open_invoice_qweb_account', + inverse_name='report_id' + ) + + +class OpenInvoiceReportAccount(models.TransientModel): + + _name = 'report_open_invoice_qweb_account' + _order = 'code ASC' + + report_id = fields.Many2one( + comodel_name='report_open_invoice_qweb', + ondelete='cascade', + index=True + ) + account_id = fields.Many2one( + 'account.account', + index=True + ) + code = fields.Char() + name = fields.Char() + final_amount_residual = fields.Float(digits=(16, 2)) + + partner_ids = fields.One2many( + comodel_name='report_open_invoice_qweb_partner', + inverse_name='report_account_id' + ) + + +class OpenInvoiceReportPartner(models.TransientModel): + + _name = 'report_open_invoice_qweb_partner' + + report_account_id = fields.Many2one( + comodel_name='report_open_invoice_qweb_account', + ondelete='cascade', + index=True + ) + partner_id = fields.Many2one( + 'res.partner', + index=True + ) + name = fields.Char() + final_amount_residual = fields.Float(digits=(16, 2)) + + move_line_ids = fields.One2many( + comodel_name='report_open_invoice_qweb_move_line', + inverse_name='report_partner_id' + ) + + @api.model + def _generate_order_by(self, order_spec, query): + return """ +ORDER BY +CASE + WHEN "report_open_invoice_qweb_partner"."partner_id" IS NOT NULL + THEN 0 + ELSE 1 + END, +"report_open_invoice_qweb_partner"."name" + """ + + +class OpenInvoiceReportMoveLine(models.TransientModel): + + _name = 'report_open_invoice_qweb_move_line' + + report_partner_id = fields.Many2one( + comodel_name='report_open_invoice_qweb_partner', + ondelete='cascade', + index=True + ) + move_line_id = fields.Many2one('account.move.line') + date = fields.Date() + date_due = fields.Date() + entry = fields.Char() + journal = fields.Char() + account = fields.Char() + partner = fields.Char() + label = fields.Char() + amount_total_due = fields.Float(digits=(16, 2)) + amount_residual = fields.Float(digits=(16, 2)) + currency_name = fields.Char() + amount_total_due_currency = fields.Float(digits=(16, 2)) + amount_residual_currency = fields.Float(digits=(16, 2)) + + +class OpenInvoiceReportCompute(models.TransientModel): + + _inherit = 'report_open_invoice_qweb' + + @api.model + def print_report(self): + self.ensure_one() + self.compute_data_for_report() + return { + 'type': 'ir.actions.report.xml', + 'report_name': + 'account_financial_report_qweb.report_open_invoice_qweb', + 'datas': {'ids': [self.id]}, + } + + @api.model + def compute_data_for_report(self): + self.ensure_one() + + self.inject_account_values() + self.inject_partner_values() + self.inject_line_values() + self.inject_line_values(only_empty_partner_line=True) + self.clean_partners_and_accounts() + self.compute_partners_and_accounts_cumul() + if self.hide_account_balance_at_0: + self.clean_partners_and_accounts( + only_delete_account_balance_at_0=True + ) + self.compute_has_second_currency() + + def inject_account_values(self): + query_inject_account = """ +WITH + accounts AS + ( + SELECT + a.id, + a.code, + a.name, + a.user_type_id + FROM + account_account a + INNER JOIN + account_move_line ml ON a.id = ml.account_id AND ml.date <= %s + """ + if self.filter_partner_ids: + query_inject_account += """ + INNER JOIN + res_partner p ON ml.partner_id = p.id + """ + if self.only_posted_moves: + query_inject_account += """ + INNER JOIN + account_move m ON ml.move_id = m.id AND m.state = 'posted' + """ + query_inject_account += """ + WHERE + a.company_id = %s + AND a.internal_type IN ('payable', 'receivable') + """ + if self.filter_account_ids: + query_inject_account += """ + AND + a.id IN %s + """ + if self.filter_partner_ids: + query_inject_account += """ + AND + p.id IN %s + """ + query_inject_account += """ + GROUP BY + a.id + ) +INSERT INTO + report_open_invoice_qweb_account + ( + report_id, + create_uid, + create_date, + account_id, + code, + name + ) +SELECT + %s AS report_id, + %s AS create_uid, + NOW() AS create_date, + a.id AS account_id, + a.code, + a.name +FROM + accounts a + """ + query_inject_account_params = ( + self.date_at, + self.company_id.id, + ) + if self.filter_account_ids: + query_inject_account_params += ( + tuple(self.filter_account_ids.ids), + ) + if self.filter_partner_ids: + query_inject_account_params += ( + tuple(self.filter_partner_ids.ids), + ) + query_inject_account_params += ( + self.id, + self.env.uid, + ) + self.env.cr.execute(query_inject_account, query_inject_account_params) + + def inject_partner_values(self): + query_inject_partner = """ +WITH + accounts_partners AS + ( + SELECT + ra.id AS report_account_id, + a.id AS account_id, + at.include_initial_balance AS include_initial_balance, + p.id AS partner_id, + COALESCE( + CASE + WHEN + NULLIF(p.name, '') IS NOT NULL + AND NULLIF(p.ref, '') IS NOT NULL + THEN p.name || ' (' || p.ref || ')' + ELSE p.name + END, + 'No partner allocated' + ) AS partner_name + FROM + report_open_invoice_qweb_account ra + INNER JOIN + account_account a ON ra.account_id = a.id + INNER JOIN + account_account_type at ON a.user_type_id = at.id + INNER JOIN + account_move_line ml ON a.id = ml.account_id AND ml.date <= %s + """ + if self.only_posted_moves: + query_inject_partner += """ + INNER JOIN + account_move m ON ml.move_id = m.id AND m.state = 'posted' + """ + query_inject_partner += """ + LEFT JOIN + res_partner p ON ml.partner_id = p.id + WHERE + ra.report_id = %s + """ + if self.filter_partner_ids: + query_inject_partner += """ + AND + p.id IN %s + """ + query_inject_partner += """ + GROUP BY + ra.id, + a.id, + p.id, + at.include_initial_balance + ) +INSERT INTO + report_open_invoice_qweb_partner + ( + report_account_id, + create_uid, + create_date, + partner_id, + name + ) +SELECT + ap.report_account_id, + %s AS create_uid, + NOW() AS create_date, + ap.partner_id, + ap.partner_name +FROM + accounts_partners ap + """ + query_inject_partner_params = ( + self.date_at, + self.id, + ) + if self.filter_partner_ids: + query_inject_partner_params += ( + tuple(self.filter_partner_ids.ids), + ) + query_inject_partner_params += ( + self.env.uid, + ) + self.env.cr.execute(query_inject_partner, query_inject_partner_params) + + def inject_line_values(self, only_empty_partner_line=False): + query_inject_move_line = """ +WITH + move_lines_amount AS + ( + SELECT + ml.id, + ml.balance, + SUM( + CASE + WHEN ml_past.id IS NOT NULL + THEN pr.amount + ELSE NULL + END + ) AS partial_amount, + ml.amount_currency, + SUM( + CASE + WHEN ml_past.id IS NOT NULL + THEN pr.amount_currency + ELSE NULL + END + ) AS partial_amount_currency + FROM + report_open_invoice_qweb_partner rp + INNER JOIN + report_open_invoice_qweb_account ra + ON rp.report_account_id = ra.id + INNER JOIN + account_move_line ml + ON ra.account_id = ml.account_id + """ + if not only_empty_partner_line: + query_inject_move_line += """ + AND rp.partner_id = ml.partner_id + """ + elif only_empty_partner_line: + query_inject_move_line += """ + AND ml.partner_id IS NULL + """ + query_inject_move_line += """ + LEFT JOIN + account_partial_reconcile pr + ON ml.balance < 0 AND pr.credit_move_id = ml.id + OR ml.balance > 0 AND pr.debit_move_id = ml.id + LEFT JOIN + account_move_line ml_future + ON ( + ml.balance < 0 AND pr.debit_move_id = ml_future.id + OR ml.balance > 0 AND pr.credit_move_id = ml_future.id + ) + AND ml_future.date >= %s + LEFT JOIN + account_move_line ml_past + ON ( + ml.balance < 0 AND pr.debit_move_id = ml_past.id + OR ml.balance > 0 AND pr.credit_move_id = ml_past.id + ) + AND ml_past.date < %s + WHERE + ra.report_id = %s + GROUP BY + ml.id, + ml.balance, + ml.amount_currency + HAVING + ( + ml.full_reconcile_id IS NULL + OR MAX(ml_future.id) IS NOT NULL + ) + + ), + move_lines AS + ( + SELECT + id, + CASE + WHEN SUM(partial_amount) > 0 + THEN + CASE + WHEN balance > 0 + THEN balance - SUM(partial_amount) + ELSE balance + SUM(partial_amount) + END + ELSE balance + END AS amount_residual, + CASE + WHEN SUM(partial_amount_currency) > 0 + THEN + CASE + WHEN amount_currency > 0 + THEN amount_currency - SUM(partial_amount_currency) + ELSE amount_currency + SUM(partial_amount_currency) + END + ELSE amount_currency + END AS amount_residual_currency + FROM + move_lines_amount + GROUP BY + id, + balance, + amount_currency + ) +INSERT INTO + report_open_invoice_qweb_move_line + ( + report_partner_id, + create_uid, + create_date, + move_line_id, + date, + date_due, + entry, + journal, + account, + partner, + label, + amount_total_due, + amount_residual, + currency_name, + amount_total_due_currency, + amount_residual_currency + ) +SELECT + rp.id AS report_partner_id, + %s AS create_uid, + NOW() AS create_date, + ml.id AS move_line_id, + ml.date, + ml.date_maturity, + m.name AS entry, + j.code AS journal, + a.code AS account, + """ + if not only_empty_partner_line: + query_inject_move_line += """ + CASE + WHEN + NULLIF(p.name, '') IS NOT NULL + AND NULLIF(p.ref, '') IS NOT NULL + THEN p.name || ' (' || p.ref || ')' + ELSE p.name + END AS partner, + """ + elif only_empty_partner_line: + query_inject_move_line += """ + 'No partner allocated' AS partner, + """ + query_inject_move_line += """ + CONCAT_WS(' - ', NULLIF(ml.ref, ''), NULLIF(ml.name, '')) AS label, + ml.balance, + ml2.amount_residual, + c.name AS currency_name, + ml.amount_currency, + ml2.amount_residual_currency +FROM + report_open_invoice_qweb_partner rp +INNER JOIN + report_open_invoice_qweb_account ra ON rp.report_account_id = ra.id +INNER JOIN + account_move_line ml ON ra.account_id = ml.account_id +INNER JOIN + move_lines ml2 + ON ml.id = ml2.id + AND ml2.amount_residual IS NOT NULL + AND ml2.amount_residual != 0 +INNER JOIN + account_move m ON ml.move_id = m.id +INNER JOIN + account_journal j ON ml.journal_id = j.id +INNER JOIN + account_account a ON ml.account_id = a.id + """ + if not only_empty_partner_line: + query_inject_move_line += """ +INNER JOIN + res_partner p + ON ml.partner_id = p.id AND rp.partner_id = p.id + """ + query_inject_move_line += """ +LEFT JOIN + account_full_reconcile fr ON ml.full_reconcile_id = fr.id +LEFT JOIN + res_currency c ON a.currency_id = c.id +WHERE + ra.report_id = %s +AND + ml.date <= %s + """ + if self.only_posted_moves: + query_inject_move_line += """ +AND + m.state = 'posted' + """ + if only_empty_partner_line: + query_inject_move_line += """ +AND + ml.partner_id IS NULL +AND + rp.partner_id IS NULL + """ + if not only_empty_partner_line: + query_inject_move_line += """ +ORDER BY + a.code, p.name, ml.date, ml.id + """ + elif only_empty_partner_line: + query_inject_move_line += """ +ORDER BY + a.code, ml.date, ml.id + """ + self.env.cr.execute( + query_inject_move_line, + (self.date_at, + self.date_at, + self.id, + self.env.uid, + self.id, + self.date_at,) + ) + + def compute_partners_and_accounts_cumul(self): + query_compute_partners_cumul = """ +UPDATE + report_open_invoice_qweb_partner +SET + final_amount_residual = + ( + SELECT + SUM(rml.amount_residual) AS final_amount_residual + FROM + report_open_invoice_qweb_move_line rml + WHERE + rml.report_partner_id = report_open_invoice_qweb_partner.id + ) +WHERE + id IN + ( + SELECT + rp.id + FROM + report_open_invoice_qweb_account ra + INNER JOIN + report_open_invoice_qweb_partner rp + ON ra.id = rp.report_account_id + WHERE + ra.report_id = %s + ) + """ + params_compute_partners_cumul = (self.id,) + self.env.cr.execute(query_compute_partners_cumul, + params_compute_partners_cumul) + query_compute_accounts_cumul = """ +UPDATE + report_open_invoice_qweb_account +SET + final_amount_residual = + ( + SELECT + SUM(rp.final_amount_residual) AS final_amount_residual + FROM + report_open_invoice_qweb_partner rp + WHERE + rp.report_account_id = report_open_invoice_qweb_account.id + ) +WHERE + report_id = %s + """ + params_compute_accounts_cumul = (self.id,) + self.env.cr.execute(query_compute_accounts_cumul, + params_compute_accounts_cumul) + + def clean_partners_and_accounts(self, + only_delete_account_balance_at_0=False): + query_clean_partners = """ +DELETE FROM + report_open_invoice_qweb_partner +WHERE + id IN + ( + SELECT + DISTINCT rp.id + FROM + report_open_invoice_qweb_account ra + INNER JOIN + report_open_invoice_qweb_partner rp + ON ra.id = rp.report_account_id + LEFT JOIN + report_open_invoice_qweb_move_line rml + ON rp.id = rml.report_partner_id + WHERE + ra.report_id = %s + """ + if not only_delete_account_balance_at_0: + query_clean_partners += """ + AND rml.id IS NULL + """ + elif only_delete_account_balance_at_0: + query_clean_partners += """ + AND ( + rp.final_amount_residual IS NULL + OR rp.final_amount_residual = 0 + ) + """ + query_clean_partners += """ + ) + """ + params_clean_partners = (self.id,) + self.env.cr.execute(query_clean_partners, params_clean_partners) + query_clean_accounts = """ +DELETE FROM + report_open_invoice_qweb_account +WHERE + id IN + ( + SELECT + DISTINCT ra.id + FROM + report_open_invoice_qweb_account ra + LEFT JOIN + report_open_invoice_qweb_partner rp + ON ra.id = rp.report_account_id + WHERE + ra.report_id = %s + """ + if not only_delete_account_balance_at_0: + query_clean_accounts += """ + AND rp.id IS NULL + """ + elif only_delete_account_balance_at_0: + query_clean_accounts += """ + AND ( + ra.final_amount_residual IS NULL + OR ra.final_amount_residual = 0 + ) + """ + query_clean_accounts += """ + ) + """ + params_clean_accounts = (self.id,) + self.env.cr.execute(query_clean_accounts, params_clean_accounts) + + def compute_has_second_currency(self): + query_update_has_second_currency = """ +UPDATE + report_open_invoice_qweb +SET + has_second_currency = + ( + SELECT + TRUE + FROM + report_open_invoice_qweb_move_line l + INNER JOIN + report_open_invoice_qweb_partner p + ON l.report_partner_id = p.id + INNER JOIN + report_open_invoice_qweb_account a + ON p.report_account_id = a.id + WHERE + a.report_id = %s + AND l.currency_name IS NOT NULL + LIMIT 1 + ) +WHERE id = %s + """ + params = (self.id,) * 2 + self.env.cr.execute(query_update_has_second_currency, params) diff --git a/account_financial_report_qweb/report/templates/open_invoice_report.xml b/account_financial_report_qweb/report/templates/open_invoice_report.xml index dfa920f4..ac6a6d24 100644 --- a/account_financial_report_qweb/report/templates/open_invoice_report.xml +++ b/account_financial_report_qweb/report/templates/open_invoice_report.xml @@ -1,210 +1,163 @@ - - + - - - -