From 28f1eff98ed69a379c36739673e06937b8baee69 Mon Sep 17 00:00:00 2001 From: Yehonatan Zecharia Date: Thu, 9 Jul 2026 12:00:04 +0300 Subject: [PATCH 1/2] Align conformance tests after https://github.com/Universal-Commerce-Protocol/python-sdk/pull/48 --- business_logic_test.py | 43 +++++++++++++++++++++--------------------- fulfillment_test.py | 6 +++--- invalid_input_test.py | 2 +- protocol_test.py | 5 ++++- 4 files changed, 30 insertions(+), 26 deletions(-) diff --git a/business_logic_test.py b/business_logic_test.py index 3b892e5..6db8f4a 100644 --- a/business_logic_test.py +++ b/business_logic_test.py @@ -68,10 +68,10 @@ def test_totals_calculation_on_create(self): # Verify Line Item Calculations line_item = checkout_obj.line_items[0] li_subtotal = next( - (t.amount for t in line_item.totals if t.type == "subtotal"), 0 + (t.amount.root for t in line_item.totals if t.type == "subtotal"), 0 ) li_total = next( - (t.amount for t in line_item.totals if t.type == "total"), 0 + (t.amount.root for t in line_item.totals if t.type == "total"), 0 ) self.assertEqual( @@ -87,22 +87,22 @@ def test_totals_calculation_on_create(self): # Verify Totals Breakdown subtotal = next( - (t for t in checkout_obj.totals if t.type == "subtotal"), None + (t for t in checkout_obj.totals.root if t.type == "subtotal"), None ) total_obj = next( - (t for t in checkout_obj.totals if t.type == "total"), None + (t for t in checkout_obj.totals.root if t.type == "total"), None ) self.assertIsNotNone(subtotal, "Subtotal missing") self.assertEqual( - subtotal.amount, + subtotal.amount.root, expected_price, f"Subtotal amount should match DB price {expected_price}", ) self.assertIsNotNone(total_obj, "Total missing") self.assertEqual( - total_obj.amount, + total_obj.amount.root, expected_price, f"Total amount should match DB price {expected_price}", ) @@ -158,15 +158,15 @@ def test_totals_recalculation_on_update(self): updated_checkout = checkout.Checkout(**response.json()) total_obj = next( - (t for t in updated_checkout.totals if t.type == "total"), None + (t for t in updated_checkout.totals.root if t.type == "total"), None ) expected_total = expected_price * 2 self.assertEqual( - total_obj.amount, + total_obj.amount.root, expected_total, msg=( "Server did not correct totals on update. Expected" - f" {expected_total}, got {total_obj.amount}" + f" {expected_total}, got {total_obj.amount.root}" ), ) @@ -226,15 +226,15 @@ def test_discount_flow(self): expected_total = int(expected_price * 0.9) total_obj = next( - (t for t in discounted_checkout.totals if t.type == "total"), None + (t for t in discounted_checkout.totals.root if t.type == "total"), None ) self.assertIsNotNone(total_obj, "Total object missing") self.assertEqual( - total_obj.amount, + total_obj.amount.root, expected_total, msg=( f"Discount not applied correctly. Expected {expected_total}, got" - f" {total_obj.amount}" + f" {total_obj.amount.root}" ), ) @@ -284,13 +284,13 @@ def test_multiple_discounts_accepted(self): expected_total = int(int(expected_price * 0.9) * 0.8) total_obj = next( - (t for t in discounted_checkout.totals if t.type == "total"), None + (t for t in discounted_checkout.totals.root if t.type == "total"), None ) self.assertEqual( - total_obj.amount, + total_obj.amount.root, expected_total, f"Multiple discounts failed. Exp {expected_total}, " - f"got {total_obj.amount}", + f"got {total_obj.amount.root}", ) # Verify both applied discounts are present @@ -332,9 +332,9 @@ def test_multiple_discounts_one_rejected(self): expected_total = int(expected_price * 0.9) total_obj = next( - (t for t in discounted_checkout.totals if t.type == "total"), None + (t for t in discounted_checkout.totals.root if t.type == "total"), None ) - self.assertEqual(total_obj.amount, expected_total) + self.assertEqual(total_obj.amount.root, expected_total) # Verify only one applied discount is present discounts_data = getattr(discounted_checkout, "discounts", {}) @@ -373,14 +373,15 @@ def test_fixed_amount_discount(self): expected_total = expected_price - 500 total_obj = next( - (t for t in discounted_checkout.totals if t.type == "total"), None + (t for t in discounted_checkout.totals.root if t.type == "total"), None ) self.assertIsNotNone(total_obj, "Total object missing") self.assertEqual( - total_obj.amount, + total_obj.amount.root, expected_total, msg=( - f"Fixed discount failed. Exp {expected_total}, got {total_obj.amount}" + f"Fixed discount failed. Exp {expected_total}, got" + f" {total_obj.amount.root}" ), ) @@ -399,7 +400,7 @@ def test_fixed_amount_discount(self): "FIXED500", ) self.assertEqual( - discounts_obj.applied[0].amount, + discounts_obj.applied[0].amount.root, 500, ) diff --git a/fulfillment_test.py b/fulfillment_test.py index cc7cc2b..40b5943 100644 --- a/fulfillment_test.py +++ b/fulfillment_test.py @@ -121,15 +121,15 @@ def test_fulfillment_flow(self) -> None: expected_total = 3500 + option_cost # Base 3500 + shipping total_obj = next( - (t for t in final_checkout.totals if t.type == "total"), None + (t for t in final_checkout.totals.root if t.type == "total"), None ) self.assertIsNotNone(total_obj, "Total object missing") self.assertEqual( - total_obj.amount, + total_obj.amount.root, expected_total, msg=( f"Total not updated correctly. Expected {expected_total}, got" - f" {total_obj.amount}" + f" {total_obj.amount.root}" ), ) diff --git a/invalid_input_test.py b/invalid_input_test.py index d0d9e81..c1ac9e4 100644 --- a/invalid_input_test.py +++ b/invalid_input_test.py @@ -98,7 +98,7 @@ def test_unknown_discount_code(self): updated_checkout = checkout.Checkout(**resp_json) # Verify no discount applied discount_total = next( - (t for t in updated_checkout.totals if t.type == "discount"), None + (t for t in updated_checkout.totals.root if t.type == "discount"), None ) self.assertIsNone( discount_total, "Unknown discount code should not apply discount" diff --git a/protocol_test.py b/protocol_test.py index 4ac7d47..762260a 100644 --- a/protocol_test.py +++ b/protocol_test.py @@ -18,7 +18,10 @@ import integration_test_utils import httpx from pydantic import ValidationError -from ucp_sdk.models.schemas.ucp import BusinessSchema, ReverseDomainName +from ucp_sdk.models.schemas.ucp import BusinessSchema +from ucp_sdk.models.schemas.shopping.types.reverse_domain_name import ( + ReverseDomainName, +) from ucp_sdk.models.schemas.shopping import checkout as checkout from ucp_sdk.models.schemas.shopping.payment import ( Payment, From b04045703c9e473312e69bafb3a527a238d748d7 Mon Sep 17 00:00:00 2001 From: Yehonatan Zecharia Date: Thu, 9 Jul 2026 12:00:59 +0300 Subject: [PATCH 2/2] Fix shopping services extraction according to spec (take from .ucp.services, not .services) --- integration_test_utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration_test_utils.py b/integration_test_utils.py index d8728be..0f8d484 100644 --- a/integration_test_utils.py +++ b/integration_test_utils.py @@ -393,7 +393,7 @@ def shopping_service_endpoint(self) -> str: profile_data = discovery_resp.json() # UCP 01-23 validation changed dicts to lists - shopping_services = profile_data.get("services", {}).get( + shopping_services = profile_data.get("ucp", {}).get("services", {}).get( "dev.ucp.shopping", [] ) if not shopping_services: