From 128c24549829fd8593359101cdc510016bf51b3f Mon Sep 17 00:00:00 2001 From: garvitkaushik-123 Date: Thu, 20 Aug 2026 01:15:30 +0530 Subject: [PATCH] fix: reject change requests for dealless orders --- src/ad_seller/services/order_service.py | 14 ++++++++++++-- tests/unit/test_change_request.py | 23 +++++++++++++++++++++++ tests/unit/test_order_endpoints.py | 1 + 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/ad_seller/services/order_service.py b/src/ad_seller/services/order_service.py index 9dc85376..f850cf32 100644 --- a/src/ad_seller/services/order_service.py +++ b/src/ad_seller/services/order_service.py @@ -43,7 +43,7 @@ async def create_order( machine = OrderStateMachine(order_id=order_id) order_data = machine.to_dict() - order_data["deal_id"] = deal_id + order_data["deal_id"] = deal_id or "" order_data["quote_id"] = quote_id order_data["created_at"] = datetime.utcnow().isoformat() + "Z" order_data["metadata"] = metadata or {} @@ -333,6 +333,16 @@ async def create_change_request(request: Any) -> dict[str, Any]: }, ) + deal_id = order.get("deal_id") + if not deal_id: + raise HTTPException( + status_code=400, + detail={ + "error": "deal_id_required", + "message": f"Order '{request.order_id}' has no deal_id and cannot be changed.", + }, + ) + # Build diffs diffs = [ FieldDiff(field=d.field, old_value=d.old_value, new_value=d.new_value) @@ -345,7 +355,7 @@ async def create_change_request(request: Any) -> dict[str, Any]: # Create the change request cr = ChangeRequest( order_id=request.order_id, - deal_id=order.get("deal_id", ""), + deal_id=deal_id, change_type=change_type, severity=severity, requested_by=request.requested_by, diff --git a/tests/unit/test_change_request.py b/tests/unit/test_change_request.py index ce0a147d..5a4a7145 100644 --- a/tests/unit/test_change_request.py +++ b/tests/unit/test_change_request.py @@ -234,6 +234,29 @@ async def test_order_not_found(self, client, mock_storage): ) assert resp.status_code == 404 + async def test_existing_order_with_null_deal_id_returns_structured_error( + self, client, mock_storage + ): + _seed_order(mock_storage) + mock_storage._store["order:ORD-TEST001"]["deal_id"] = None + + with patch("ad_seller.storage.factory.get_storage", return_value=mock_storage): + resp = await client.post( + "/api/v1/change-requests", + json={ + "order_id": "ORD-TEST001", + "change_type": "impressions", + "reason": "Increase campaign reach", + }, + ) + + assert resp.status_code == 400 + assert resp.json()["detail"] == { + "error": "deal_id_required", + "message": "Order 'ORD-TEST001' has no deal_id and cannot be changed.", + } + assert not any(key.startswith("change_request:") for key in mock_storage._store) + async def test_invalid_change_type(self, client, mock_storage): _seed_order(mock_storage) with patch("ad_seller.storage.factory.get_storage", return_value=mock_storage): diff --git a/tests/unit/test_order_endpoints.py b/tests/unit/test_order_endpoints.py index a9cd90e1..456c83da 100644 --- a/tests/unit/test_order_endpoints.py +++ b/tests/unit/test_order_endpoints.py @@ -112,6 +112,7 @@ async def test_order_persisted_to_storage(self, client, mock_storage): stored = mock_storage._store[f"order:{order_id}"] assert stored["order_id"] == order_id assert stored["status"] == "draft" + assert stored["deal_id"] == "" # =============================================================================