Files
cmroubao/erp-connector/tests/test_normalizer.py
T

161 lines
5.0 KiB
Python

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_normalizes_created_range_without_exposing_raw_query() -> None:
source = raw_result()
source["query"] = {
"mode": "CREATED_RANGE",
"createdFrom": "2026-07-22",
"createdTo": "2026-07-28",
"private": "must-not-leak",
}
normalized = normalize_freight_result(source)
assert normalized["query"] == {
"mode": "CREATED_RANGE",
"created_from": "2026-07-22",
"created_to": "2026-07-28",
}
assert "must-not-leak" not in json.dumps(normalized)
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)