Files
shanxia2.0/backend/tests/test_pl_brand_archive.py
T
2026-10-22 16:24:46 +08:00

204 lines
6.5 KiB
Python

from decimal import Decimal
import pytest
from app.services.pl_brand_archive import (
expand_export_rows_by_brand_qty,
expand_export_rows_for_plan_brand,
format_plan_product_constraint_brand,
is_archived_for_export_brand,
resolve_export_brand_qty_rows,
validate_brand_qty_rows,
)
from types import SimpleNamespace
def test_resolve_export_brand_qty_rows_prefers_stop_level():
by_stop = {
"sp1": [{"brandId": "b1", "brandName": "君正", "qty": Decimal("32")}],
}
by_plan = {
"pp1": [{"brandId": "b2", "brandName": "红四方", "qty": Decimal("10")}],
}
rows = resolve_export_brand_qty_rows(
stop_product_id="sp1",
plan_product_id="pp1",
by_stop_id=by_stop,
by_plan_product_id=by_plan,
)
assert len(rows) == 1
assert rows[0]["brandName"] == "君正"
def test_resolve_export_brand_qty_rows_falls_back_to_plan_level():
rows = resolve_export_brand_qty_rows(
stop_product_id="missing",
plan_product_id="pp1",
by_stop_id={},
by_plan_product_id={
"pp1": [{"brandId": "b1", "brandName": "君正", "qty": Decimal("32")}],
},
)
assert len(rows) == 1
assert rows[0]["brandName"] == "君正"
def test_resolve_export_brand_qty_rows_empty():
assert (
resolve_export_brand_qty_rows(
stop_product_id=None,
plan_product_id=None,
by_stop_id={},
by_plan_product_id={},
)
== []
)
def test_expand_export_rows_by_brand_qty_splits_and_blanks():
base = {"productName": "片碱", "planQty": 34, "actualQty": 32, "brandName": "旧"}
blank = expand_export_rows_by_brand_qty(base, [])
assert len(blank) == 1
assert blank[0]["brandName"] == ""
assert blank[0]["actualQty"] == 32
split = expand_export_rows_by_brand_qty(
base,
[
{"brandId": "b1", "brandName": "君正", "qty": Decimal("20")},
{"brandId": "b2", "brandName": "红四方", "qty": Decimal("12")},
],
)
assert [r["brandName"] for r in split] == ["君正", "红四方"]
assert [r["actualQty"] for r in split] == [Decimal("20"), Decimal("12")]
assert all(r["planQty"] == 34 for r in split)
def test_archive_status_gate_for_export_brand():
assert is_archived_for_export_brand("archived") is True
assert is_archived_for_export_brand("unarchived") is False
assert is_archived_for_export_brand("draft") is False
product = SimpleNamespace(brand_mode="required", brand_name="君正")
assert format_plan_product_constraint_brand(product) == "君正"
assert (
format_plan_product_constraint_brand(
SimpleNamespace(brand_mode="any", brand_name="君正")
)
== ""
)
def test_expand_export_rows_for_plan_brand_draft_uses_product_not_qty():
base = {"productName": "片碱", "planQty": 34, "actualQty": 32, "brandName": ""}
product = SimpleNamespace(id="pp1", brand_mode="required", brand_name="君正")
rows = expand_export_rows_for_plan_brand(
base,
archive_status="draft",
plan_product=product,
stop_product_id="lp1",
by_stop_id={
"lp1": [
{"brandId": "b1", "brandName": "红四方", "qty": Decimal("20")},
{"brandId": "b2", "brandName": "君正", "qty": Decimal("12")},
]
},
)
assert len(rows) == 1
assert rows[0]["brandName"] == "君正"
assert rows[0]["actualQty"] == 32
def test_expand_export_rows_for_plan_brand_archived_splits_qty():
base = {"productName": "片碱", "planQty": 34, "actualQty": 32, "brandName": ""}
product = SimpleNamespace(id="pp1", brand_mode="any", brand_name=None)
rows = expand_export_rows_for_plan_brand(
base,
archive_status="archived",
plan_product=product,
stop_product_id="lp1",
by_stop_id={
"lp1": [
{"brandId": "b1", "brandName": "君正", "qty": Decimal("20")},
{"brandId": "b2", "brandName": "红四方", "qty": Decimal("12")},
]
},
)
assert [r["brandName"] for r in rows] == ["君正", "红四方"]
assert [r["actualQty"] for r in rows] == [Decimal("20"), Decimal("12")]
def test_required_allows_other_brand_when_sum_matches():
validate_brand_qty_rows(
brand_mode="required",
required_brand_id="b1",
actual_qty=Decimal("10"),
rows=[{"brandId": "b2", "brandName": "红四方", "qty": Decimal("10")}],
)
def test_required_allows_multi_brand_when_sum_matches():
validate_brand_qty_rows(
brand_mode="required",
required_brand_id="b1",
actual_qty=Decimal("10"),
rows=[
{"brandId": "b1", "brandName": "君正", "qty": Decimal("6")},
{"brandId": "b2", "brandName": "红四方", "qty": Decimal("4")},
],
)
def test_required_sum_must_match():
with pytest.raises(ValueError, match="合计"):
validate_brand_qty_rows(
brand_mode="required",
required_brand_id="b1",
actual_qty=Decimal("10"),
rows=[
{"brandId": "b1", "brandName": "君正", "qty": Decimal("6")},
{"brandId": "b2", "brandName": "红四方", "qty": Decimal("3")},
],
)
def test_any_sum_must_match():
with pytest.raises(ValueError, match="合计"):
validate_brand_qty_rows(
brand_mode="any",
required_brand_id=None,
actual_qty=Decimal("10"),
rows=[
{"brandId": "b1", "brandName": "君正", "qty": Decimal("6")},
{"brandId": "b2", "brandName": "红四方", "qty": Decimal("3")},
],
)
def test_any_ok():
validate_brand_qty_rows(
brand_mode="any",
required_brand_id=None,
actual_qty=Decimal("10"),
rows=[
{"brandId": "b1", "brandName": "君正", "qty": Decimal("6")},
{"brandId": "b2", "brandName": "红四方", "qty": Decimal("4")},
],
)
def test_no_brand_ignores_rows():
validate_brand_qty_rows(
brand_mode=None,
required_brand_id=None,
actual_qty=Decimal("5"),
rows=[],
)
def test_delta_for_plan_type():
from app.services.pl_inventory_service import qty_delta_for_plan
assert qty_delta_for_plan("inbound", Decimal("3")) == Decimal("3")
assert qty_delta_for_plan("outbound", Decimal("3")) == Decimal("-3")
assert qty_delta_for_plan("direct", Decimal("3")) == Decimal("0")