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 + + + + + +