diff --git a/sale_project_fixed_price_task_completed_invoicing/models/project_task.py b/sale_project_fixed_price_task_completed_invoicing/models/project_task.py index f9b4a5350ad..507bb047d6d 100644 --- a/sale_project_fixed_price_task_completed_invoicing/models/project_task.py +++ b/sale_project_fixed_price_task_completed_invoicing/models/project_task.py @@ -21,7 +21,9 @@ def toggle_invoiceable(self): for task in self: # We dont' want to modify when the related SOLine is invoiced if (not task.sale_line_id or - task.sale_line_id.state in ('done', 'cancel')): + task.sale_line_id.state in ('done', 'cancel') or + task.sale_line_id.invoice_status in ('to invoice', + 'invoiced')): raise UserError(_("You cannot modify the status if there is " "no Sale Order Line or if it has been " "invoiced.")) @@ -38,6 +40,7 @@ def write(self, vals): ) return super(ProjectTask, self).write(vals) + @api.model def create(self, vals): SOLine = self.env['sale.order.line'] so_line = SOLine.browse(vals.get('sale_line_id')) diff --git a/sale_project_fixed_price_task_completed_invoicing/models/sale_order_line.py b/sale_project_fixed_price_task_completed_invoicing/models/sale_order_line.py index abfeac6b24d..bc57524fc25 100644 --- a/sale_project_fixed_price_task_completed_invoicing/models/sale_order_line.py +++ b/sale_project_fixed_price_task_completed_invoicing/models/sale_order_line.py @@ -15,6 +15,7 @@ def create(self, vals): if (line.state == 'sale' and not line.order_id.project_id and line.product_id.track_service in ('completed_task', )): line.order_id._create_analytic_account() + return line @api.constrains('product_id') def _onchange_product_id(self): diff --git a/sale_project_fixed_price_task_completed_invoicing/tests/__init__.py b/sale_project_fixed_price_task_completed_invoicing/tests/__init__.py index e69de29bb2d..6524ec69da9 100644 --- a/sale_project_fixed_price_task_completed_invoicing/tests/__init__.py +++ b/sale_project_fixed_price_task_completed_invoicing/tests/__init__.py @@ -0,0 +1,2 @@ +# -*- coding: utf-8 -*- +from . import test_sale_project_fixed_price_task_completed_invoicing diff --git a/sale_project_fixed_price_task_completed_invoicing/tests/test_sale_project_fixed_price_task_completed_invoicing.py b/sale_project_fixed_price_task_completed_invoicing/tests/test_sale_project_fixed_price_task_completed_invoicing.py new file mode 100644 index 00000000000..f46d5ca931c --- /dev/null +++ b/sale_project_fixed_price_task_completed_invoicing/tests/test_sale_project_fixed_price_task_completed_invoicing.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo.addons.sale.tests.test_sale_common import TestSale +from odoo.exceptions import UserError # , ValidationError + + +class TestSaleProjectFixedPrice(TestSale): + + def test_sale_project_fixed_price(self): + # The product comes from 'sale_timesheet' the only modification to add + # is for the track_service + prod_task = self.env.ref('product.product_product_1') + prd_vals = { + 'track_service': 'completed_task', + } + prod_task.write(prd_vals) + so_vals = { + 'partner_id': self.partner.id, + 'partner_invoice_id': self.partner.id, + 'partner_shipping_id': self.partner.id, + 'order_line': [(0, 0, {'name': prod_task.name, + 'product_id': prod_task.id, + 'product_uom_qty': 1, + 'product_uom': prod_task.uom_id.id, + 'price_unit': prod_task.list_price})], + 'pricelist_id': self.env.ref('product.list0').id, + } + so = self.env['sale.order'].create(so_vals) + so.action_confirm() + + # check task creation + project = self.env.ref('sale_timesheet.project_GAP') + task = project.task_ids.filtered( + lambda t: t.name == '%s:%s' % (so.name, prod_task.name)) + self.assertTrue(task, 'Sale Service: task is not created') + self.assertEqual(task.partner_id, so.partner_id, + 'Sale Service: customer should be the same on task ' + 'and on SO') + self.assertTrue(task.fixed_price) + + # check Task validation. It should update the delivered quantity + line = so.order_line + self.assertFalse(line.product_uom_qty == line.qty_delivered, + 'Sale Service: line should be invoiced completely') + task.toggle_invoiceable() + self.assertTrue(task.invoiceable, 'The task should be invoiceable') + self.assertTrue(line.product_uom_qty == line.qty_delivered, + 'Sale Service: line should be invoiced completely') + + # Impossible to change task invoicable after validation of soline + so.action_invoice_create() + self.assertEqual(so.invoice_status, + 'invoiced', 'SO should be invoiced') + with self.assertRaises(UserError): + task.toggle_invoiceable()