161 lines
5.0 KiB
Python
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)
|