# Copyright 2018 Tecnativa - Sergio Teruel # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import Command from odoo.tests import Form, tagged from odoo.addons.account.tests.common import AccountTestInvoicingCommon @tagged("post_install", "-at_install") class TestSaleElaboration(AccountTestInvoicingCommon): @classmethod def setUpClass(cls): super().setUpClass() cls.Elaboration = cls.env["product.elaboration"] cls.ElaborationProfile = cls.env["product.elaboration.profile"] cls.category_1 = cls.env["product.category"].create({"name": "Meat"}) cls.category_2 = cls.env["product.category"].create({"name": "Fish"}) cls.product = cls.env["product.product"].create( {"name": "test", "tracking": "none", "list_price": 1000} ) cls.product_2 = cls.env["product.product"].create( {"name": "test 2", "tracking": "none", "list_price": 1000} ) cls.product_3 = cls.env["product.product"].create( {"name": "test 2", "tracking": "none", "list_price": 1000} ) cls.product.categ_id = cls.category_1 cls.product_2.categ_id = cls.category_2 cls.product_3.categ_id = cls.category_1 cls.product_elaboration_A = cls.env["product.product"].create( { "name": "Product Elaboration A", "type": "service", "list_price": 50.0, "invoice_policy": "order", "is_elaboration": True, } ) cls.product_elaboration_B = cls.env["product.product"].create( { "name": "Product Elaboration B", "type": "service", "list_price": 25.0, "invoice_policy": "order", "is_elaboration": True, } ) cls.pricelist = cls.env["product.pricelist"].create( { "name": "Test pricelist", "item_ids": [ ( 0, 0, { "applied_on": "3_global", "compute_price": "formula", "base": "list_price", }, ) ], } ) cls.partner = cls.env["res.partner"].create( {"name": "test - partner", "property_product_pricelist": cls.pricelist.id} ) cls.elaboration_a = cls.Elaboration.create( { "code": "AA", "name": "Elaboration A", "product_id": cls.product_elaboration_A.id, } ) cls.elaboration_b = cls.Elaboration.create( { "code": "BB", "name": "Elaboration B", "product_id": cls.product_elaboration_B.id, } ) cls.elaboration_profile_a = cls.ElaborationProfile.create( { "name": "Elaboration Profile A", "elaboration_ids": [ Command.set([cls.elaboration_a.id, cls.elaboration_b.id]) ], } ) cls.elaboration_profile_b = cls.ElaborationProfile.create( { "name": "Elaboration Profile B", "elaboration_ids": [Command.set(cls.elaboration_a.ids)], } ) cls.product.elaboration_profile_id = cls.elaboration_profile_a cls.order = cls._create_sale_order( cls, [(cls.product, 10, [cls.elaboration_a])] ) cls.category_1.elaboration_profile_id = cls.elaboration_profile_b def _create_sale_order(self, products_info): order_form = Form(self.env["sale.order"]) order_form.partner_id = self.partner for product, qty, elaborations in products_info: with order_form.order_line.new() as line_form: line_form.product_id = product line_form.product_uom_qty = qty for elaboration in elaborations: line_form.elaboration_ids.add(elaboration) return order_form.save() def test_search_elaboration(self): elaboration = self.Elaboration.name_search("Elaboration") self.assertEqual(len(elaboration), 2) elaboration = self.Elaboration.name_search("AA") self.assertEqual(len(elaboration), 1) def test_sale_elaboration_doesnt_change(self): self.order.order_line.elaboration_note = "Some details" self.order.order_line.elaboration_ids = self.elaboration_b self.assertEqual(self.order.order_line.elaboration_note, "Some details") def test_sale_elaboration(self): self.order.action_confirm() self.order.picking_ids.move_ids.quantity = 10.0 self.order.picking_ids._action_done() elaboration_lines = self.order.order_line.filtered("is_elaboration") self.assertEqual(len(elaboration_lines), 1) self.assertEqual(elaboration_lines.price_unit, 50.0) def test_sale_elaboration_multi(self): self.order.order_line.create( { "order_id": self.order.id, "product_id": self.product_elaboration_A.id, "product_uom_qty": 1.0, "price_unit": 50.0, "is_elaboration": True, } ) self.order.action_confirm() self.order.picking_ids.move_ids.quantity = 10.0 self.order.picking_ids._action_done() elaboration_lines = self.order.order_line.filtered("is_elaboration") self.assertEqual(len(elaboration_lines), 1) self.assertEqual(elaboration_lines.product_uom_qty, 11.0) def test_invoice_elaboration(self): self.order = self._create_sale_order( [ (self.product_elaboration_A, 1, []), (self.product_elaboration_B, 1, []), ] ) self.order.order_line.filtered( lambda line: line.product_id == self.product_elaboration_B ).is_elaboration = False self.order.action_confirm() invoice = self.order._create_invoices() so_line_elaboration = self.order.order_line.filtered("is_elaboration") so_line_no_elaboration = self.order.order_line - so_line_elaboration inv_line_elaboration = invoice.invoice_line_ids.filtered( lambda x: x.sale_line_ids == so_line_elaboration ) inv_line_no_elaboration = invoice.invoice_line_ids.filtered( lambda x: x.sale_line_ids == so_line_no_elaboration ) self.assertEqual( inv_line_elaboration.name, f"{self.order.name} - {so_line_elaboration.name}", ) self.assertNotEqual( inv_line_no_elaboration.name, f"{self.order.name} - {so_line_no_elaboration.name}", ) def test_sale_elaboration_change_product(self): self.order.order_line.product_id = self.product_elaboration_A self.assertTrue(self.order.order_line.is_elaboration) self.order.order_line.product_id = self.product self.assertFalse(self.order.order_line.is_elaboration) def test_multi_elaboration_per_line(self): product2 = self.env["product.product"].create({"name": "product 2"}) with Form(self.order) as order_form: with order_form.order_line.new() as line_form: line_form.product_id = product2 line_form.product_uom_qty = 1 line_form.elaboration_ids.add(self.elaboration_a) line_form.elaboration_ids.add(self.elaboration_b) self.order.action_confirm() move_ids = self.order.picking_ids.move_ids move_line_a = move_ids.filtered(lambda r: r.product_id == self.product) move_line_a.quantity = 10.0 move_line_b = move_ids.filtered(lambda r: r.product_id == product2) move_line_b.quantity = 1.0 self.order.picking_ids._action_done() elaboration_lines = self.order.order_line.filtered("is_elaboration") self.assertEqual(len(elaboration_lines), 2) self.assertEqual(sum(elaboration_lines.mapped("product_uom_qty")), 12.0) def test_propagation_from_sale_order_to_stock_move(self): with Form(self.order) as order_f: # Edit order's line to add custom elaboration note with order_f.order_line.edit(0) as line_f: line_f.elaboration_note = "Custom note 1" # Add a new line with a custom elaboration note, but without elaborations with order_f.order_line.new() as line_f: line_f.product_id = self.product line_f.product_uom_qty = 1 line_f.elaboration_note = "Custom note 2" self.order.action_confirm() # Check that the custom elaboration notes are propagated to the stock moves self.assertRecordValues( self.order.picking_ids.move_ids, [ { "product_id": self.product.id, "elaboration_ids": self.elaboration_a.ids, "elaboration_note": "Custom note 1", }, { "product_id": self.product.id, "elaboration_ids": [], "elaboration_note": "Custom note 2", }, ], )