Skip to content

Commit 517d791

Browse files
committed
fix(v3-ref-seller): filter media_buy_ids + preserve buyer creative_id
get_media_buys now narrows to the requested media_buy_ids when the buyer supplies them — without the filter, the response leaks every advertiser-scoped buy and the storyboard's media_buys[0] lookup hits a different scenario's order. Adds a bidirectional buyer-creative-id ↔ upstream-creative-id map so sync_creatives can echo the buyer's id on list_creatives and update_media_buy can translate before attach_creative (the upstream mints cr_<uuid> regardless of client_request_id).
1 parent b167835 commit 517d791

1 file changed

Lines changed: 30 additions & 3 deletions

File tree

examples/v3_reference_seller/src/platform.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,13 @@ def __init__(
555555
# Monotonic per-buy revision counter (update_media_buy's
556556
# optimistic-concurrency token).
557557
self._buy_revisions: dict[str, int] = {}
558+
# Bidirectional buyer-creative-id ↔ upstream-creative-id map.
559+
# The upstream mints ``cr_<uuid>`` on every upload regardless of
560+
# ``client_request_id``, so the seller has to track the mapping
561+
# to (a) echo the buyer's id in ``list_creatives`` and (b)
562+
# translate before calling ``attach_creative`` upstream.
563+
self._creative_id_map: dict[str, str] = {} # buyer_id → upstream_id
564+
self._creative_id_reverse: dict[str, str] = {} # upstream_id → buyer_id
558565
# AccountStore is always wired. ``app.main`` passes the
559566
# MOCK_AD_SERVER_URL env so resolved accounts route at the JS
560567
# mock-server fixture. Tests that bypass the AccountStore (by
@@ -1111,12 +1118,17 @@ async def update_media_buy(
11111118
continue
11121119
if creative_id in seen_creative_ids:
11131120
continue
1121+
# Translate buyer's creative_id to the upstream id
1122+
# before issuing attach_creative. Pass through unchanged
1123+
# when no mapping is known (the upstream will surface
1124+
# a 404 → CREATIVE_NOT_FOUND).
1125+
upstream_creative_id = self._creative_id_map.get(creative_id, creative_id)
11141126
await upstream_helpers.attach_creative(
11151127
client,
11161128
network_code=network_code,
11171129
order_id=media_buy_id,
11181130
line_item_id=pkg_id,
1119-
creative_id=creative_id,
1131+
creative_id=upstream_creative_id,
11201132
)
11211133
existing_assignments.append(
11221134
ca.model_dump(mode="json", exclude_none=True)
@@ -1199,9 +1211,13 @@ async def sync_creatives(
11991211
snippet = getattr(creative, "snippet", None)
12001212
if snippet is not None:
12011213
payload["snippet"] = str(snippet)
1202-
await upstream_helpers.upload_creative(
1214+
upstream_resp = await upstream_helpers.upload_creative(
12031215
client, network_code=network_code, payload=payload
12041216
)
1217+
upstream_id = str(upstream_resp.get("creative_id") or "")
1218+
if upstream_id:
1219+
self._creative_id_map[creative.creative_id] = upstream_id
1220+
self._creative_id_reverse[upstream_id] = creative.creative_id
12051221
results.append(
12061222
SyncCreativeResult.model_validate(
12071223
{
@@ -1348,6 +1364,14 @@ async def get_media_buys(
13481364
upstream_orders = [
13491365
o for o in payload.get("orders", []) if o.get("advertiser_id") == advertiser_id
13501366
]
1367+
# Narrow to the requested media_buy_ids when the buyer supplied
1368+
# them. Storyboards chain get_media_buys after create with the
1369+
# captured media_buy_id; without this filter the response leaks
1370+
# every advertiser-scoped buy and the buyer's ``media_buys[0]``
1371+
# lookup hits a different scenario's order.
1372+
if getattr(req, "media_buy_ids", None):
1373+
wanted_ids = {str(x) for x in req.media_buy_ids}
1374+
upstream_orders = [o for o in upstream_orders if o.get("order_id") in wanted_ids]
13511375
page = upstream_orders[offset : offset + limit]
13521376
media_buys: list[dict[str, Any]] = []
13531377
for order in page:
@@ -1546,7 +1570,10 @@ async def list_creatives(
15461570
page = upstream_creatives[offset : offset + limit]
15471571
creatives = [
15481572
{
1549-
"creative_id": c["creative_id"],
1573+
# Surface the buyer's original creative_id when the seller
1574+
# owns the mapping; falls back to the upstream id when the
1575+
# creative was synced outside this seller instance.
1576+
"creative_id": self._creative_id_reverse.get(c["creative_id"], c["creative_id"]),
15501577
"name": c["name"],
15511578
"format_id": {"agent_url": agent_url, "id": c.get("format_id", "")},
15521579
"status": _project_creative_status(c.get("status", "active")),

0 commit comments

Comments
 (0)