Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions rest/python/server/integration_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1737,6 +1737,55 @@ def test_create_checkout_with_attribution(self) -> None:
stored.get("attribution", {}).get("campaign_id"), "18234567890"
)

def test_create_checkout_with_fulfillment_create_shape(self) -> None:
"""Fulfillment on create accepts the shape that omits server assigned ids.

`fulfillment_method.json` marks `id` as `create: omit`, `line_item_ids` as
`create: optional`, and `shipping_destination.json` marks `id` as optional,
so a platform composing the advertised schemas sends none of them. The
other fulfillment tests populate all three, which is what let the request
model regress to the response container without any test noticing.
"""
with self.client:
response = self.client.post(
"/checkout-sessions",
headers=self._get_headers(
idempotency_key="ful_create_min", request_id="ful_create_min"
),
json={
"line_items": [{"item": {"id": "rose"}, "quantity": 1}],
"fulfillment": {
"methods": [
{
"type": "shipping",
"destinations": [
{
"street_address": "1 Test Way",
"address_locality": "Springfield",
"address_region": "CA",
"address_country": "US",
"postal_code": "99999",
}
],
}
]
},
},
)
self.assertEqual(response.status_code, 201, f"Response: {response.text}")
body = response.json()

methods = body.get("fulfillment", {}).get("methods", [])
self.assertLen(methods, 1)
self.assertIsNotNone(methods[0].get("id"))
self.assertEqual(methods[0].get("type"), "shipping")

destinations = methods[0].get("destinations", [])
self.assertLen(destinations, 1)
self.assertIsNotNone(destinations[0].get("id"))
self.assertEqual(destinations[0].get("street_address"), "1 Test Way")
self.assertEqual(destinations[0].get("postal_code"), "99999")

def test_validation_failure_answers_with_ucp_envelope(self) -> None:
"""A validation failure answers with the UCP envelope, not detail."""
with self.client:
Expand Down
5 changes: 4 additions & 1 deletion rest/python/server/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
Checkout as FulfillmentCheckout,
Fulfillment,
)
from ucp_sdk.models.schemas.shopping.types.fulfillment_create_request import (
FulfillmentCreateRequest,
)

from ucp_sdk.models.schemas.shopping.order import Order
from ucp_sdk.models.schemas.shopping.order import PlatformSchema
Expand Down Expand Up @@ -93,7 +96,7 @@ class UnifiedCheckoutCreateRequest(CheckoutCreateRequest):
"""Create request model combining base fields and extensions."""

line_items: list[LineItemCreateRequest] | None = None
fulfillment: Fulfillment | None = None
fulfillment: FulfillmentCreateRequest | None = None
discounts: DiscountsObject | None = None
buyer_consent: Any | None = None
cart_id: str | None = None
Expand Down
Loading