from odoo.tests import TransactionCase, tagged, Form from odoo import Command, fields from datetime import timedelta @tagged("post_install", "-at_install") class TestPurchaseOrder(TransactionCase): @classmethod def setUpClass(cls): super().setUpClass() cls.mto_route = cls.env.ref("stock.route_warehouse0_mto") cls.buy_route = cls.env.ref("purchase_stock.route_warehouse0_buy") cls.mto_route.active = True cls.supplier = cls.env.ref("base.res_partner_18") cls.client_1 = cls.env.ref("base.res_partner_2") cls.client_2 = cls.env.ref("base.res_partner_3") cls.client_3 = cls.env.ref("base.res_partner_4") cls.product_1 = cls.env["product.product"].create( { "name": "SuperProduct", "is_storable": True, "route_ids": [Command.set((cls.mto_route + cls.buy_route).ids)], "seller_ids": [ Command.create( { "partner_id": cls.supplier.id, "price": 3000, }, ) ], } ) cls.product_2 = cls.env["product.product"].create( { "name": "SuperProduct2", "is_storable": True, "route_ids": [Command.set((cls.mto_route + cls.buy_route).ids)], "seller_ids": [ Command.create( { "partner_id": cls.supplier.id, "price": 5000, }, ) ], } ) cls.agreement_1 = cls.env["purchase.requisition"].create( { "vendor_id": cls.supplier.id, "customer_ids": [Command.set([cls.client_1.id, cls.client_2.id])], "line_ids": [ Command.create( { "product_id": cls.product_1.id, "product_qty": 100, "price_unit": 1000, } ), Command.create( { "product_id": cls.product_2.id, "product_qty": 100, "price_unit": 2000, } ), ], "date_start": fields.Date.today() - timedelta(days=100), "date_end": fields.Date.today() + timedelta(days=265), } ) cls.agreement_1.action_confirm() cls.agreement_2 = cls.env["purchase.requisition"].create( { "vendor_id": cls.supplier.id, "customer_ids": [Command.set([cls.client_3.id])], "line_ids": [ Command.create( { "product_id": cls.product_1.id, "product_qty": 100, "price_unit": 1500, } ), ], "date_start": fields.Date.today() - timedelta(days=100), "date_end": fields.Date.today() + timedelta(days=265), } ) cls.agreement_2.action_confirm() def test_one_purchase_order_line_gets_correct_agreement(self): sale_order = self.env["sale.order"].create( { "partner_id": self.client_1.id, "order_line": [ Command.create( { "product_id": self.product_1.id, "product_uom_qty": 50, } ) ], } ) sale_order.action_confirm() self.assertTrue(sale_order._get_purchase_orders()) purchase_line = sale_order._get_purchase_orders()[0].order_line[0] self.assertEqual(purchase_line.order_id.partner_id, self.supplier) self.assertEqual(purchase_line.requisition_id, self.agreement_1) def test_competing_sale_orders_get_two_lines(self): purchase_order = self._generate_2_sales_1_purchase_clients_1_3() self.assertEqual(len(purchase_order.order_line), 2) self.assertEqual( purchase_order.order_line[0].requisition_id, self.agreement_1, f"PO line for Partner 1 should have requisition {self.agreement_1.name}, not {purchase_order.order_line[0].requisition_id.name}", ) self.assertEqual( purchase_order.order_line[1].requisition_id, self.agreement_2, f"PO line for Partner 2 should have requisition {self.agreement_2.name}, not {purchase_order.order_line[1].requisition_id.name}" f"PO line has sale order {purchase_order.order_line[1].sale_order_id} and sale line {purchase_order.order_line[1].sale_line_id}" f"PO has sales orders {purchase_order._get_sale_orders()}" f"PO has requisition {purchase_order.requisition_id}", ) def _generate_2_sales_1_purchase_clients_1_3(self): sale_order_1 = self.env["sale.order"].create( { "partner_id": self.client_1.id, "order_line": [ Command.create( { "product_id": self.product_1.id, "product_uom_qty": 50, } ) ], } ) sale_order_1.action_confirm() sale_order_2 = self.env["sale.order"].create( { "partner_id": self.client_3.id, "order_line": [ Command.create( { "product_id": self.product_1.id, "product_uom_qty": 50, } ) ], } ) sale_order_2.action_confirm() purchase_order = sale_order_1._get_purchase_orders()[0] return purchase_order def test_lines_from_multiple_sales_get_correct_pricing(self): purchase_order = self._generate_2_sales_1_purchase_clients_1_3() self.assertEqual(purchase_order.order_line[0].price_unit, 1000) self.assertEqual(purchase_order.order_line[1].price_unit, 1500) def test_removing_line_agreement_recomputes_pricing(self): purchase_order = self._generate_2_sales_1_purchase_clients_1_3() purchase_order.requisition_id = False line = purchase_order.order_line[0] line.requisition_id = False self.assertEqual(purchase_order.order_line[0].price_unit, 3000) def test_requisition_selection_state_and_validity(self): """Test that requisitions are only selected if they are confirmed and currently valid.""" # Create a draft requisition draft_agreement = self.env["purchase.requisition"].create( { "vendor_id": self.supplier.id, "customer_ids": [Command.set([self.client_1.id])], "line_ids": [ Command.create( { "product_id": self.product_1.id, "product_qty": 100, "price_unit": 4000, } ), ], "date_start": fields.Date.today() - timedelta(days=100), "date_end": fields.Date.today() + timedelta(days=265), } ) # Create an expired requisition expired_agreement = self.env["purchase.requisition"].create( { "vendor_id": self.supplier.id, "customer_ids": [Command.set([self.client_1.id])], "line_ids": [ Command.create( { "product_id": self.product_1.id, "product_qty": 100, "price_unit": 5000, } ), ], "date_start": fields.Date.today() - timedelta(days=200), "date_end": fields.Date.today() - timedelta(days=100), } ) expired_agreement.action_confirm() # Create a future requisition future_agreement = self.env["purchase.requisition"].create( { "vendor_id": self.supplier.id, "customer_ids": [Command.set([self.client_1.id])], "line_ids": [ Command.create( { "product_id": self.product_1.id, "product_qty": 100, "price_unit": 6000, } ), ], "date_start": fields.Date.today() + timedelta(days=100), "date_end": fields.Date.today() + timedelta(days=200), } ) future_agreement.action_confirm() # Create and confirm a sale order sale_order = self.env["sale.order"].create( { "partner_id": self.client_1.id, "order_line": [ Command.create( { "product_id": self.product_1.id, "product_uom_qty": 50, } ) ], } ) sale_order.action_confirm() # Verify that the purchase order line gets the correct agreement (agreement_1) purchase_order = sale_order._get_purchase_orders()[0] purchase_line = purchase_order.order_line[0] # Should select agreement_1 which is confirmed and currently valid self.assertEqual( purchase_line.requisition_id, self.agreement_1, "Purchase order line should select the confirmed and currently valid agreement", ) self.assertEqual( purchase_line.price_unit, 1000, "Purchase order line should have the price from the valid agreement", ) # The other agreements should not be selected because: # - draft_agreement is not confirmed # - expired_agreement is outside its validity dates # - future_agreement hasn't started yet self.assertNotEqual( purchase_line.requisition_id, draft_agreement, "Draft agreement should not be selected", ) self.assertNotEqual( purchase_line.requisition_id, expired_agreement, "Expired agreement should not be selected", ) self.assertNotEqual( purchase_line.requisition_id, future_agreement, "Future agreement should not be selected", )