# Copyright 2026 - Today Criptomart # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). """ Test suite for Phase 3 refactoring of confirm_eskaera(). Tests the 3 helper methods created in Phase 3: - _validate_confirm_json(): Validates JSON request data - _process_cart_items(): Processes cart items into sale.order lines - _build_confirmation_message(): Builds localized confirmation messages Includes tests for: - Request validation with various error conditions - Cart item processing with product context - Multi-language message building (ES, EU, CA, GL, PT, FR, IT) - Pickup vs delivery date handling - Edge cases and error handling """ import json from datetime import date from datetime import timedelta from types import SimpleNamespace from unittest.mock import patch from odoo.tests.common import TransactionCase from odoo.addons.website_sale_aplicoop.controllers.website_sale import ( AplicoopWebsiteSale, ) REQUEST_PATCH_TARGET = ( "odoo.addons.website_sale_aplicoop.controllers.website_sale.request" ) def _make_json_response(data, headers=None, status=200): """Build a lightweight HTTP-like response object for controller tests.""" raw = data.encode("utf-8") if isinstance(data, str) else data return SimpleNamespace(data=raw, status=status, headers=headers or []) def _build_request_mock(env, payload=None, website=None): """Build a request mock compatible with the controller helpers/routes. Args: env: Odoo Environment to use as request.env. payload: dict that will be JSON-encoded as request.httprequest.data. website: Optional real website record. When not provided a minimal SimpleNamespace stub is used (sufficient for tests that do not call pricing helpers). """ if website is None: website = SimpleNamespace( _get_current_pricelist=lambda: False, show_line_subtotals_tax_selection="tax_excluded", fiscal_position_id=False, company_id=False, ) request_mock = SimpleNamespace( env=env, make_response=_make_json_response, website=website, ) if payload is not None: request_mock.httprequest = SimpleNamespace( data=json.dumps(payload).encode("utf-8") ) return request_mock class TestValidateConfirmJson(TransactionCase): """Test _validate_confirm_json() helper method.""" def setUp(self): super().setUp() self.controller = AplicoopWebsiteSale() self.group_1 = self.env["res.partner"].create( { "name": "Consumer Group 1", "is_company": True, "is_group": True, } ) self.group_2 = self.env["res.partner"].create( { "name": "Consumer Group 2", "is_company": True, "is_group": True, } ) self.partner = self.env["res.partner"].create( { "name": "Phase 3 Member", "email": "phase3-member@test.com", } ) self.group_2.member_ids = [(4, self.partner.id)] self.user = self.env["res.users"].create( { "name": "Phase 3 User", "login": "phase3-user@test.com", "email": "phase3-user@test.com", "partner_id": self.partner.id, } ) # Create test group order self.group_order = self.env["group.order"].create( { "name": "Test Order Phase 3", "state": "open", "group_ids": [(6, 0, [self.group_1.id, self.group_2.id])], "start_date": date.today(), "end_date": date.today() + timedelta(days=7), "cutoff_day": "3", # Thursday "pickup_day": "5", # Saturday } ) def test_validate_confirm_json_success(self): """Test successful validation of confirm JSON data.""" request_mock = _build_request_mock(self.env(user=self.user)) data = { "order_id": self.group_order.id, "items": [{"product_id": 1, "quantity": 2, "product_price": 10.0}], "is_delivery": False, } with patch(REQUEST_PATCH_TARGET, request_mock): order_id, group_order, current_user, items, is_delivery = ( self.controller._validate_confirm_json(data) ) self.assertEqual(order_id, self.group_order.id) self.assertEqual(group_order.id, self.group_order.id) self.assertEqual(current_user.id, self.user.id) self.assertEqual(len(items), 1) self.assertFalse(is_delivery) def test_validate_confirm_json_missing_order_id(self): """Test validation fails without order_id.""" request_mock = _build_request_mock(self.env(user=self.user)) data = {"items": [{"product_id": 1, "quantity": 2}]} with patch(REQUEST_PATCH_TARGET, request_mock): with self.assertRaises(ValueError) as context: self.controller._validate_confirm_json(data) self.assertIn("order_id is required", str(context.exception)) def test_validate_confirm_json_order_not_exists(self): """Test validation fails with non-existent order.""" request_mock = _build_request_mock(self.env(user=self.user)) data = { "order_id": 99999, # Non-existent ID "items": [{"product_id": 1, "quantity": 2}], } with patch(REQUEST_PATCH_TARGET, request_mock): with self.assertRaises(ValueError) as context: self.controller._validate_confirm_json(data) self.assertIn("Order", str(context.exception)) def test_validate_confirm_json_no_items(self): """Test validation fails without items in cart.""" request_mock = _build_request_mock(self.env(user=self.user)) data = { "order_id": self.group_order.id, "items": [], } with patch(REQUEST_PATCH_TARGET, request_mock): with self.assertRaises(ValueError) as context: self.controller._validate_confirm_json(data) self.assertIn("No items in cart", str(context.exception)) def test_validate_confirm_json_with_delivery_flag(self): """Test validation correctly handles is_delivery flag.""" request_mock = _build_request_mock(self.env(user=self.user)) data = { "order_id": self.group_order.id, "items": [{"product_id": 1, "quantity": 1}], "is_delivery": True, } with patch(REQUEST_PATCH_TARGET, request_mock): _, _, _, _, is_delivery = self.controller._validate_confirm_json(data) self.assertTrue(is_delivery) def test_validate_confirm_json_user_without_matching_group(self): """Validation must fail if user is not in any allowed consumer group.""" other_partner = self.env["res.partner"].create( { "name": "Partner without matching group", "email": "nogroup@test.com", } ) other_user = self.env["res.users"].create( { "name": "User without matching group", "login": "nogroup-user@test.com", "email": "nogroup-user@test.com", "partner_id": other_partner.id, } ) request_mock = _build_request_mock(self.env(user=other_user)) data = { "order_id": self.group_order.id, "items": [{"product_id": 1, "quantity": 1}], } with patch(REQUEST_PATCH_TARGET, request_mock): with self.assertRaises(ValueError) as context: self.controller._validate_confirm_json(data) self.assertIn( "User is not a member of any consumer group in this order", str(context.exception), ) class TestConsumerGroupResolution(TransactionCase): """Tests for consumer group selection in multi-group orders.""" def setUp(self): super().setUp() self.controller = AplicoopWebsiteSale() self.group_1 = self.env["res.partner"].create( { "name": "Group A", "is_company": True, "is_group": True, } ) self.group_2 = self.env["res.partner"].create( { "name": "Group B", "is_company": True, "is_group": True, } ) self.group_3 = self.env["res.partner"].create( { "name": "Group C", "is_company": True, "is_group": True, } ) self.partner = self.env["res.partner"].create( { "name": "Member B", "email": "memberb@test.com", } ) self.group_2.member_ids = [(4, self.partner.id)] self.user = self.env["res.users"].create( { "name": "Member B User", "login": "memberb-user@test.com", "email": "memberb-user@test.com", "partner_id": self.partner.id, } ) self.product = self.env["product.product"].create( { "name": "Group Resolution Product", "type": "consu", "list_price": 10.0, } ) self.group_order = self.env["group.order"].create( { "name": "Multi-group order", "state": "open", "group_ids": [(6, 0, [self.group_1.id, self.group_2.id])], "start_date": date.today(), "end_date": date.today() + timedelta(days=7), "cutoff_day": "1", "pickup_day": "2", } ) self.sale_order_lines = [ ( 0, 0, { "product_id": self.product.id, "name": "Test line", "product_uom_qty": 1, "price_unit": 10.0, }, ) ] def test_get_consumer_group_for_user_returns_matching_group(self): """Should resolve the user's own consumer group, not the first order group.""" consumer_group_id = self.controller._get_consumer_group_for_user( self.group_order, self.user ) self.assertEqual(consumer_group_id, self.group_2.id) def test_get_consumer_group_for_user_uses_first_matching_order_group(self): """If user belongs to multiple valid groups, use the first in group_order.""" self.group_1.member_ids = [(4, self.partner.id)] group_order = self.env["group.order"].create( { "name": "Multi-match order", "state": "open", "group_ids": [ (6, 0, [self.group_1.id, self.group_2.id, self.group_3.id]) ], } ) consumer_group_id = self.controller._get_consumer_group_for_user( group_order, self.user ) self.assertEqual(consumer_group_id, self.group_1.id) def test_create_or_update_sale_order_assigns_user_consumer_group(self): """Created sale.order must use the consumer group that matches the user.""" request_mock = _build_request_mock(self.env(user=self.user)) with patch(REQUEST_PATCH_TARGET, request_mock): sale_order = self.controller._create_or_update_sale_order( self.group_order, self.user, self.sale_order_lines, is_delivery=False, ) self.assertEqual(sale_order.consumer_group_id.id, self.group_2.id) class TestProcessCartItems(TransactionCase): """Test _process_cart_items() helper method.""" def setUp(self): super().setUp() self.controller = AplicoopWebsiteSale() # Create test products self.product1 = self.env["product.product"].create( { "name": "Test Product 1", "list_price": 15.0, "type": "consu", } ) self.product2 = self.env["product.product"].create( { "name": "Test Product 2", "list_price": 25.0, "type": "consu", } ) self.group = self.env["res.partner"].create( { "name": "Cart Test Group", "is_company": True, "is_group": True, } ) # Create test group order self.group_order = self.env["group.order"].create( { "name": "Test Order for Cart", "state": "open", "group_ids": [(6, 0, [self.group.id])], "start_date": date.today(), "end_date": date.today() + timedelta(days=7), } ) def test_process_cart_items_success(self): """Test successful cart item processing.""" request_mock = _build_request_mock(self.env.with_context(lang="es_ES")) items = [ { "product_id": self.product1.id, "quantity": 2, "product_price": 15.0, }, { "product_id": self.product2.id, "quantity": 1, "product_price": 25.0, }, ] with patch(REQUEST_PATCH_TARGET, request_mock): result = self.controller._process_cart_items(items, self.group_order) self.assertEqual(len(result), 2) self.assertEqual(result[0][0], 0) # Command (0, 0, vals) self.assertEqual(result[0][1], 0) self.assertIn("product_id", result[0][2]) self.assertEqual(result[0][2]["product_uom_qty"], 2) self.assertEqual(result[0][2]["price_unit"], 15.0) def test_process_cart_items_uses_list_price_fallback(self): """Test cart processing uses list_price when product_price is 0.""" request_mock = _build_request_mock(self.env.with_context(lang="es_ES")) items = [ { "product_id": self.product1.id, "quantity": 1, "product_price": 0, # Should fallback to list_price } ] with patch(REQUEST_PATCH_TARGET, request_mock): result = self.controller._process_cart_items(items, self.group_order) self.assertEqual(len(result), 1) # Should use product.list_price as fallback self.assertEqual(result[0][2]["price_unit"], self.product1.list_price) def test_process_cart_items_skips_invalid_product(self): """Test cart processing skips non-existent products.""" request_mock = _build_request_mock(self.env.with_context(lang="es_ES")) items = [ { "product_id": 99999, # Non-existent "quantity": 1, "product_price": 10.0, }, { "product_id": self.product1.id, "quantity": 2, "product_price": 15.0, }, ] with patch(REQUEST_PATCH_TARGET, request_mock): result = self.controller._process_cart_items(items, self.group_order) # Should only process the valid product self.assertEqual(len(result), 1) self.assertEqual(result[0][2]["product_id"], self.product1.id) def test_process_cart_items_empty_after_filtering(self): """Test cart processing raises error when no valid items remain.""" request_mock = _build_request_mock(self.env.with_context(lang="es_ES")) items = [{"product_id": 99999, "quantity": 1, "product_price": 10.0}] with patch(REQUEST_PATCH_TARGET, request_mock): with self.assertRaises(ValueError) as context: self.controller._process_cart_items(items, self.group_order) self.assertIn("No valid items", str(context.exception)) def test_process_cart_items_translates_product_name(self): """Test cart processing uses translated product names.""" request_mock = _build_request_mock(self.env.with_context(lang="eu_ES")) # Add translation for product name self.env["ir.translation"].create( { "type": "model", "name": "product.product,name", "module": "website_sale_aplicoop", "lang": "eu_ES", "res_id": self.product1.id, "src": "Test Product 1", "value": "Proba Produktua 1", "state": "translated", } ) items = [ { "product_id": self.product1.id, "quantity": 1, "product_price": 15.0, } ] with patch(REQUEST_PATCH_TARGET, request_mock): result = self.controller._process_cart_items(items, self.group_order) # Product name should be in Basque context product_name = result[0][2]["name"] self.assertIsNotNone(product_name) # In real test, would be "Proba Produktua 1" but translation may not work in test class TestBuildConfirmationMessage(TransactionCase): """Test _build_confirmation_message() helper method.""" def setUp(self): super().setUp() self.controller = AplicoopWebsiteSale() self.user = self.env.ref("base.user_admin") self.partner = self.env.ref("base.partner_admin") self.group = self.env["res.partner"].create( { "name": "Message Test Group", "is_company": True, "is_group": True, } ) # Create test group order with dates self.group_order = self.env["group.order"].create( { "name": "Test Order Messages", "state": "open", "group_ids": [(6, 0, [self.group.id])], "start_date": date.today(), "end_date": date.today() + timedelta(days=7), "cutoff_day": "3", "pickup_day": "5", # Saturday (0=Monday) } ) # Create test sale order self.sale_order = self.env["sale.order"].create( { "partner_id": self.partner.id, "group_order_id": self.group_order.id, } ) @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_pickup(self, mock_request): """Test confirmation message for pickup (not delivery).""" mock_request.env = self.env.with_context(lang="es_ES") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) self.assertIn("message", result) self.assertIn("pickup_day", result) self.assertIn("pickup_date", result) self.assertIn("pickup_day_index", result) # Should contain "Thank you" text (or translation) self.assertIn("Thank you", result["message"]) # Should contain order reference self.assertIn(self.sale_order.name, result["message"]) # Should have pickup day index self.assertEqual(result["pickup_day_index"], 5) @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_delivery(self, mock_request): """Test confirmation message for home delivery.""" mock_request.env = self.env.with_context(lang="es_ES") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=True ) self.assertIn("message", result) # Should contain "Delivery date" label (or translation) # and should use delivery_date, not pickup_date message = result["message"] self.assertIsNotNone(message) # Delivery day should be next day after pickup (Saturday -> Sunday) # pickup_day_index=5 (Saturday), delivery should be 6 (Sunday) # Note: _get_day_names would need to be mocked for exact day name @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_no_dates(self, mock_request): """Test confirmation message when no pickup date is set.""" mock_request.env = self.env.with_context(lang="es_ES") # Create order without dates group_order_no_dates = self.env["group.order"].create( { "name": "Order No Dates", "state": "open", "group_ids": [(6, 0, [self.group.id])], } ) sale_order_no_dates = self.env["sale.order"].create( { "partner_id": self.partner.id, "group_order_id": group_order_no_dates.id, } ) result = self.controller._build_confirmation_message( sale_order_no_dates, group_order_no_dates, is_delivery=False ) # Should still build message without dates self.assertIn("message", result) self.assertIn("Thank you", result["message"]) # Date fields should be empty self.assertEqual(result["pickup_date"], "") @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_formats_date(self, mock_request): """Test confirmation message formats dates correctly (DD/MM/YYYY).""" mock_request.env = self.env.with_context(lang="es_ES") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) # Should have date in DD/MM/YYYY format pickup_date_str = result["pickup_date"] self.assertIsNotNone(pickup_date_str) # Verify format with regex date_pattern = r"\d{2}/\d{2}/\d{4}" self.assertRegex(pickup_date_str, date_pattern) @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_multilang_es(self, mock_request): """Test confirmation message in Spanish (es_ES).""" mock_request.env = self.env.with_context(lang="es_ES") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) message = result["message"] # Should contain translated strings (if translations loaded) self.assertIsNotNone(message) # In real scenario, would check for "¡Gracias!" or similar @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_multilang_eu(self, mock_request): """Test confirmation message in Basque (eu_ES).""" mock_request.env = self.env.with_context(lang="eu_ES") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) message = result["message"] self.assertIsNotNone(message) # In real scenario, would check for "Eskerrik asko!" or similar @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_multilang_ca(self, mock_request): """Test confirmation message in Catalan (ca_ES).""" mock_request.env = self.env.with_context(lang="ca_ES") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) message = result["message"] self.assertIsNotNone(message) # In real scenario, would check for "Gràcies!" or similar @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_multilang_gl(self, mock_request): """Test confirmation message in Galician (gl_ES).""" mock_request.env = self.env.with_context(lang="gl_ES") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) message = result["message"] self.assertIsNotNone(message) # In real scenario, would check for "Grazas!" or similar @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_multilang_pt(self, mock_request): """Test confirmation message in Portuguese (pt_PT).""" mock_request.env = self.env.with_context(lang="pt_PT") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) message = result["message"] self.assertIsNotNone(message) # In real scenario, would check for "Obrigado!" or similar @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_multilang_fr(self, mock_request): """Test confirmation message in French (fr_FR).""" mock_request.env = self.env.with_context(lang="fr_FR") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) message = result["message"] self.assertIsNotNone(message) # In real scenario, would check for "Merci!" or similar @patch(REQUEST_PATCH_TARGET) def test_build_confirmation_message_multilang_it(self, mock_request): """Test confirmation message in Italian (it_IT).""" mock_request.env = self.env.with_context(lang="it_IT") result = self.controller._build_confirmation_message( self.sale_order, self.group_order, is_delivery=False ) message = result["message"] self.assertIsNotNone(message) # In real scenario, would check for "Grazie!" or similar class TestConfirmEskaera_Integration(TransactionCase): """Integration tests for confirm_eskaera() with all 3 helpers.""" def setUp(self): super().setUp() self.controller = AplicoopWebsiteSale() self.consumer_group = self.env["res.partner"].create( { "name": "Integration Consumer Group", "is_company": True, "is_group": True, } ) self.partner = self.env["res.partner"].create( { "name": "Integration Member", "email": "integration-member@test.com", } ) self.consumer_group.member_ids = [(4, self.partner.id)] self.user = self.env["res.users"].create( { "name": "Integration User", "login": "integration-user@test.com", "email": "integration-user@test.com", "partner_id": self.partner.id, } ) # Create test product self.product = self.env["product.product"].create( { "name": "Integration Test Product", "list_price": 20.0, "type": "consu", } ) # Create test group order self.group_order = self.env["group.order"].create( { "name": "Integration Test Order", "state": "open", "group_ids": [(6, 0, [self.consumer_group.id])], "start_date": date.today(), "end_date": date.today() + timedelta(days=7), "cutoff_day": "3", "pickup_day": "5", "home_delivery": True, } ) # Use the real website so pricing helpers can resolve company/fiscal pos self.website = self.env["website"].search([], limit=1) def test_confirm_eskaera_full_flow_pickup(self): """Test full confirm_eskaera flow for pickup order.""" data = { "order_id": self.group_order.id, "items": [ { "product_id": self.product.id, "quantity": 3, "product_price": 20.0, } ], "is_delivery": False, } mock_request = _build_request_mock( self.env(user=self.user, context=dict(self.env.context, lang="es_ES")), data, website=self.website, ) with patch(REQUEST_PATCH_TARGET, mock_request): response = self.controller.confirm_eskaera.__wrapped__(self.controller) # Verify response self.assertIsNotNone(response) response_data = json.loads(response.data.decode("utf-8")) self.assertTrue(response_data.get("success")) self.assertIn("message", response_data) self.assertIn("sale_order_id", response_data) # Verify sale.order was created sale_order_id = response_data["sale_order_id"] sale_order = self.env["sale.order"].browse(sale_order_id) self.assertTrue(sale_order.exists()) self.assertEqual(sale_order.partner_id.id, self.partner.id) self.assertEqual(sale_order.group_order_id.id, self.group_order.id) self.assertEqual(len(sale_order.order_line), 1) self.assertEqual(sale_order.order_line[0].product_uom_qty, 3) self.assertFalse(sale_order.home_delivery) self.assertEqual( sale_order.commitment_date.date(), self.group_order.pickup_date, ) def test_confirm_eskaera_full_flow_delivery(self): """Test full confirm_eskaera flow for delivery order.""" # Add delivery_date to group order self.group_order.delivery_date = self.group_order.pickup_date + timedelta( days=1 ) data = { "order_id": self.group_order.id, "items": [ { "product_id": self.product.id, "quantity": 2, "product_price": 20.0, } ], "is_delivery": True, } mock_request = _build_request_mock( self.env(user=self.user, context=dict(self.env.context, lang="es_ES")), data, website=self.website, ) with patch(REQUEST_PATCH_TARGET, mock_request): response = self.controller.confirm_eskaera.__wrapped__(self.controller) # Verify response response_data = json.loads(response.data.decode("utf-8")) self.assertTrue(response_data.get("success")) # Verify sale.order has delivery flag sale_order_id = response_data["sale_order_id"] sale_order = self.env["sale.order"].browse(sale_order_id) self.assertTrue(sale_order.home_delivery) # commitment_date should be delivery_date self.assertEqual( sale_order.commitment_date.date(), self.group_order.delivery_date ) def test_confirm_eskaera_updates_existing_draft(self): """Test confirm_eskaera updates existing draft order instead of creating new.""" # Create existing draft order existing_order = self.env["sale.order"].create( { "partner_id": self.partner.id, "group_order_id": self.group_order.id, "state": "draft", # pickup_date must match group_order.pickup_date so # _find_recent_draft_order can locate this draft "pickup_date": self.group_order.pickup_date, "order_line": [ ( 0, 0, { "product_id": self.product.id, "product_uom_qty": 1, "price_unit": 20.0, }, ) ], } ) existing_order_id = existing_order.id data = { "order_id": self.group_order.id, "items": [ { "product_id": self.product.id, "quantity": 5, # Different quantity "product_price": 20.0, } ], "is_delivery": False, } mock_request = _build_request_mock( self.env(user=self.user, context=dict(self.env.context, lang="es_ES")), data, website=self.website, ) with patch(REQUEST_PATCH_TARGET, mock_request): response = self.controller.confirm_eskaera.__wrapped__(self.controller) response_data = json.loads(response.data.decode("utf-8")) # Should update existing order, not create new self.assertEqual(response_data["sale_order_id"], existing_order_id) # Verify order was updated existing_order.invalidate_recordset() self.assertEqual(len(existing_order.order_line), 1) self.assertEqual(existing_order.order_line[0].product_uom_qty, 5) def test_confirm_eskaera_ignores_old_period_draft(self): """Old draft from previous pickup_date must not be reused.""" old_draft = self.env["sale.order"].create( { "partner_id": self.partner.id, "group_order_id": self.group_order.id, "state": "draft", "pickup_date": date.today() - timedelta(days=7), "order_line": [ ( 0, 0, { "product_id": self.product.id, "product_uom_qty": 1, "price_unit": 20.0, }, ) ], } ) data = { "order_id": self.group_order.id, "items": [ { "product_id": self.product.id, "quantity": 4, "product_price": 20.0, } ], "is_delivery": False, } mock_request = _build_request_mock( self.env(user=self.user, context=dict(self.env.context, lang="es_ES")), data, website=self.website, ) with patch(REQUEST_PATCH_TARGET, mock_request): response = self.controller.confirm_eskaera.__wrapped__(self.controller) response_data = json.loads(response.data.decode("utf-8")) self.assertTrue(response_data.get("success")) self.assertNotEqual(response_data["sale_order_id"], old_draft.id) old_draft.invalidate_recordset() self.assertEqual(old_draft.state, "draft") self.assertEqual(old_draft.order_line[0].product_uom_qty, 1)