from __future__ import annotations import json import pytest from shunyunbaoerp import ERPProtocolError, normalize_freight_result def raw_result() -> dict: return { "count": 1, "query": { "orderNumber": "PRIVATE-QUERY", "matchField": "allcode", }, "records": [ { "stock": { "id": 12, "code": "SOURCE-12", "orderCode": "PLATFORM-12", "shopName": "来源店铺", "created": "2026-07-28 10:00:00", "orderStatus": 2, "purchaseStatus": 0, "isCancel": 0, "receiver": "不得返回", "receiverTel": "不得返回", "receiverAddr": "不得返回", }, "detail": { "id": 12, "shopName": "来源店铺", "created": "2026-07-28 10:00:00", "details": [ { "id": 102, "productTitle": "第二件商品", "productSpec": "蓝色,L", "sku": "", "variationSku": "BLUE-L", "productQty": 2, "productThumb": 190000002, "purchaseStatus": 0, "cost": "不得返回", }, { "id": 101, "productTitle": "第一件商品", "productSpec": "灰色,2XL", "sku": "GRAY-2XL", "variationSku": "IGNORED", "productQty": 1, "productThumb": 190000001, "purchaseStatus": 0, }, ], "receiver": "不得返回", }, } ], } def test_normalizes_all_items_and_excludes_private_fields() -> None: normalized = normalize_freight_result(raw_result()) assert normalized["schema_version"] == 1 assert normalized["query"] == {"mode": "ORDER_NUMBER"} assert len(normalized["orders"]) == 1 order = normalized["orders"][0] assert order["external_stock_id"] == "12" assert [item["external_item_id"] for item in order["items"]] == [ "101", "102", ] assert order["items"][1]["sku"] == "BLUE-L" assert order["items"][1]["quantity"] == 2 assert order["items"][0]["product_thumb_ref"] == "190000001" encoded = json.dumps(normalized, ensure_ascii=False) for forbidden in ( "PRIVATE-QUERY", "receiver", "receiverTel", "receiverAddr", "cost", "不得返回", ): assert forbidden not in encoded def test_invalid_procurement_fields_remain_reviewable() -> None: source = raw_result() item = source["records"][0]["detail"]["details"][0] item["productTitle"] = None item["detailProductName"] = None item["sku"] = "" item["variationSku"] = "" item["productQty"] = 0 item["productThumb"] = None normalized = normalize_freight_result(source) result = normalized["orders"][0]["items"][1] assert result["title"] == "" assert result["sku"] == "" assert result["quantity"] is None assert result["product_thumb_ref"] is None def test_conflicting_duplicate_item_is_rejected() -> None: source = raw_result() duplicate = dict(source["records"][0]["detail"]["details"][0]) duplicate["productTitle"] = "冲突内容" source["records"][0]["detail"]["details"].append(duplicate) with pytest.raises(ERPProtocolError, match="重复身份"): normalize_freight_result(source) @pytest.mark.parametrize( "mutation", [ lambda source: source["records"][0].update(detail=None), lambda source: source["records"][0]["detail"].update(id=99), lambda source: source["records"][0]["detail"].update(details=None), lambda source: source["records"][0]["detail"]["details"][0].update( id=None ), ], ) def test_identity_or_detail_shape_failure_rejects_whole_batch( mutation, ) -> None: source = raw_result() mutation(source) with pytest.raises(ERPProtocolError): normalize_freight_result(source)