From 29cc7cb23a2d2ccc0eaa1b589fa4ec0e9cad76a9 Mon Sep 17 00:00:00 2001 From: sbejaoui Date: Wed, 13 Nov 2019 11:29:18 +0100 Subject: [PATCH] [12.0][IMP] - Add an action for contracts manual invoicing It happen that a company has to trigger the invoicing action to generate invoices before the scheduled date (to print and prepare invoices documents, check invoices, etc.). This requires technical access for end users with the risk that this represents. This commit adds a new wizard to run the invoicing action for a given date with a helper to see and check the contract that will be invoiced. When the manual action is called, the system displays all created invoices. [12.0][IMP] - log the manual invoice action in contract chatter [IMP] - Add alink to the invoice in contract message at manual invoicing [IMP] - Improve code [FIX] - log message for invoice creation only when there is an invoice [IMP] - split the manual invoice menu into to menus sale & purhcase [IMP] - hide invoice button if there is nothing to invoice --- contract/__manifest__.py | 1 + contract/models/contract.py | 21 +++-- contract/tests/test_contract.py | 33 ++++++++ contract/wizards/__init__.py | 1 + .../contract_manually_create_invoice.py | 66 ++++++++++++++++ .../contract_manually_create_invoice.xml | 79 +++++++++++++++++++ 6 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 contract/wizards/contract_manually_create_invoice.py create mode 100644 contract/wizards/contract_manually_create_invoice.xml diff --git a/contract/__manifest__.py b/contract/__manifest__.py index a29196d64..3d93c989d 100644 --- a/contract/__manifest__.py +++ b/contract/__manifest__.py @@ -29,6 +29,7 @@ 'data/contract_renew_cron.xml', 'data/mail_template.xml', 'wizards/contract_line_wizard.xml', + 'wizards/contract_manually_create_invoice.xml', 'views/abstract_contract_line.xml', 'views/contract.xml', 'views/contract_line.xml', diff --git a/contract/models/contract.py b/contract/models/contract.py index 3592a28ae..7b16dafd6 100644 --- a/contract/models/contract.py +++ b/contract/models/contract.py @@ -457,7 +457,17 @@ class ContractContract(models.Model): This method triggers the creation of the next invoices of the contracts even if their next invoicing date is in the future. """ - return self._recurring_create_invoice() + invoice = self._recurring_create_invoice() + if invoice: + self.message_post( + body=_( + 'Contract manually invoiced: ' + 'Invoice' + '' + ) + % (invoice._name, invoice.id) + ) + return invoice @api.multi def _recurring_create_invoice(self, date_ref=False): @@ -465,8 +475,9 @@ class ContractContract(models.Model): return self._finalize_and_create_invoices(invoices_values) @api.model - def cron_recurring_create_invoice(self): - domain = self._get_contracts_to_invoice_domain() + def cron_recurring_create_invoice(self, date_ref=None): + if not date_ref: + date_ref = fields.Date.context_today(self) + domain = self._get_contracts_to_invoice_domain(date_ref) contracts_to_invoice = self.search(domain) - date_ref = fields.Date.context_today(contracts_to_invoice) - contracts_to_invoice._recurring_create_invoice(date_ref) + return contracts_to_invoice._recurring_create_invoice(date_ref) diff --git a/contract/tests/test_contract.py b/contract/tests/test_contract.py index 6e59ab640..9f613de8c 100644 --- a/contract/tests/test_contract.py +++ b/contract/tests/test_contract.py @@ -1737,6 +1737,39 @@ class TestContract(TestContractBase): len(invoice_lines), ) + def test_contract_manually_create_invoice(self): + self.acct_line.date_start = '2018-01-01' + self.acct_line.recurring_invoicing_type = 'post-paid' + self.acct_line.date_end = '2018-03-15' + self.acct_line._onchange_date_start() + self.contract2.unlink() + contracts = self.contract + for i in range(10): + contracts |= self.contract.copy() + wizard = self.env['contract.manually.create.invoice'].create({ + 'invoice_date': self.today + }) + wizard.action_show_contract_to_invoice() + contract_to_invoice_count = wizard.contract_to_invoice_count + self.assertEqual( + contracts, + self.env['contract.contract'].search( + wizard.action_show_contract_to_invoice()['domain'] + ), + ) + action = wizard.create_invoice() + invoice_lines = self.env['account.invoice.line'].search( + [('contract_line_id', 'in', + contracts.mapped('contract_line_ids').ids)] + ) + self.assertEqual( + len(contracts.mapped('contract_line_ids')), + len(invoice_lines), + ) + invoices = self.env['account.invoice'].search(action['domain']) + self.assertEqual(invoice_lines.mapped('invoice_id'), invoices) + self.assertEqual(len(invoices), contract_to_invoice_count) + def test_get_period_to_invoice_monthlylastday_postpaid(self): self.acct_line.date_start = '2018-01-05' self.acct_line.recurring_invoicing_type = 'post-paid' diff --git a/contract/wizards/__init__.py b/contract/wizards/__init__.py index 146dcc66d..1fa21bcc9 100644 --- a/contract/wizards/__init__.py +++ b/contract/wizards/__init__.py @@ -1 +1,2 @@ from . import contract_line_wizard +from . import contract_manually_create_invoice diff --git a/contract/wizards/contract_manually_create_invoice.py b/contract/wizards/contract_manually_create_invoice.py new file mode 100644 index 000000000..6531d3352 --- /dev/null +++ b/contract/wizards/contract_manually_create_invoice.py @@ -0,0 +1,66 @@ +# Copyright 2019 ACSONE SA/NV +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, fields, models, _ + + +class ContractManuallyCreateInvoice(models.TransientModel): + + _name = 'contract.manually.create.invoice' + _description = 'Contract Manually Create Invoice Wizard' + + invoice_date = fields.Date(string="Invoice Date", required=True) + contract_to_invoice_count = fields.Integer( + compute="_compute_contract_to_invoice_ids" + ) + contract_to_invoice_ids = fields.Many2many( + comodel_name="contract.contract", + compute="_compute_contract_to_invoice_ids", + ) + contract_type = fields.Selection( + selection=[('sale', 'Customer'), ('purchase', 'Supplier')], + default='sale', + required=True, + ) + + @api.depends('invoice_date') + def _compute_contract_to_invoice_ids(self): + if not self.invoice_date: + # trick to show no invoice when no date has been entered yet + contract_to_invoice_domain = [('id', '=', False)] + else: + contract_to_invoice_domain = self.env[ + 'contract.contract' + ]._get_contracts_to_invoice_domain(self.invoice_date) + self.contract_to_invoice_ids = self.env['contract.contract'].search( + contract_to_invoice_domain + + [('contract_type', '=', self.contract_type)] + ) + self.contract_to_invoice_count = len(self.contract_to_invoice_ids) + + @api.multi + def action_show_contract_to_invoice(self): + self.ensure_one() + return { + "type": "ir.actions.act_window", + "name": _("Contracts to invoice"), + "res_model": "contract.contract", + "domain": [('id', 'in', self.contract_to_invoice_ids.ids)], + "view_mode": "tree,form", + "context": self.env.context, + } + + @api.multi + def create_invoice(self): + self.ensure_one() + invoices = self.env['account.invoice'] + for contract in self.contract_to_invoice_ids: + invoices |= contract.recurring_create_invoice() + return { + "type": "ir.actions.act_window", + "name": _("Invoices"), + "res_model": "account.invoice", + "domain": [('id', 'in', invoices.ids)], + "view_mode": "tree,form", + "context": self.env.context, + } diff --git a/contract/wizards/contract_manually_create_invoice.xml b/contract/wizards/contract_manually_create_invoice.xml new file mode 100644 index 000000000..cd396f894 --- /dev/null +++ b/contract/wizards/contract_manually_create_invoice.xml @@ -0,0 +1,79 @@ + + + + + + + contract.manually.create.invoice + +
+ + + + + + + + + +
+
+
+
+
+ + + Manually Invoice Sale Contracts + contract.manually.create.invoice + form + {'default_contract_type': 'sale'} + new + + + + Manually Invoice Sale Contracts + + + + + + + + Manually Invoice Purchase Contracts + contract.manually.create.invoice + form + {'default_contract_type': 'purchase'} + new + + + + Manually Invoice Purchase Contracts + + + + + +