| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- """合同完善导出:按段次×产品展开,缺口类型跟本行段。"""
- from datetime import datetime
- from app.api.pl.plan import (
- CONTRACT_GAP_EXPORT_COLUMNS,
- build_contract_gap_export_rows,
- )
- from app.schemas.pl.plan import (
- PlanContractGapRead,
- PlanContractLink,
- PlanDeliveryRead,
- PlanLoadRead,
- PlanStopProductRead,
- )
- from app.services.pl_internal_customer import INTERNAL_CUSTOMER_NAMES
- NOW = datetime(2026, 10, 11, 0, 0, 0)
- INTERNAL = next(iter(INTERNAL_CUSTOMER_NAMES))
- def _stop_product(name: str, *, product_id: str) -> PlanStopProductRead:
- return PlanStopProductRead(
- id=f"sp-{product_id}",
- planId="p1",
- tenantNo="t1",
- productId=product_id,
- productNo=f"NO-{product_id}",
- productName=name,
- createTime=NOW,
- updateTime=NOW,
- )
- def _load(*, customer_name: str, contracts: list, products: list) -> PlanLoadRead:
- return PlanLoadRead(
- id="load1",
- planId="p1",
- tenantNo="t1",
- customerName=customer_name,
- products=products,
- contracts=contracts,
- createTime=NOW,
- updateTime=NOW,
- )
- def _delivery(
- *,
- stop_id: str,
- seq: int,
- customer_name: str,
- delivery_time: str,
- contracts: list,
- products: list,
- ) -> PlanDeliveryRead:
- return PlanDeliveryRead(
- id=stop_id,
- planId="p1",
- tenantNo="t1",
- seq=seq,
- customerName=customer_name,
- deliveryTime=delivery_time,
- products=products,
- contracts=contracts,
- createTime=NOW,
- updateTime=NOW,
- )
- def _gap_item() -> PlanContractGapRead:
- return PlanContractGapRead(
- id="p1",
- planNo="PL001",
- planDate="2026-10-11",
- planType="direct",
- followStatus="arranged",
- supplierName="供方甲",
- customerName="需方乙",
- supplierContractExempt=False,
- demanderContractExempt=False,
- )
- def test_contract_gap_export_columns_match_segment_rows():
- assert [column.field for column in CONTRACT_GAP_EXPORT_COLUMNS] == [
- "planNo",
- "stopSegment",
- "planDate",
- "deliveryTimes",
- "planType",
- "followStatus",
- "loadCustomer",
- "deliveryCustomer",
- "productName",
- "supplierName",
- "customerName",
- "gapType",
- ]
- assert [column.title for column in CONTRACT_GAP_EXPORT_COLUMNS] == [
- "计划编号",
- "段次",
- "计划日期",
- "送货时间",
- "单据类型",
- "跟进状态",
- "装货客户",
- "送货客户",
- "产品名称",
- "供方",
- "需方",
- "缺口类型",
- ]
- def test_build_contract_gap_export_rows_expands_multi_segment_products():
- """装货缺合同 + 两送货段(一段有合同、一段两产品缺合同)展开为 4 行。"""
- load = _load(
- customer_name="外部装货客户",
- contracts=[],
- products=[_stop_product("甲醇", product_id="prod-load")],
- )
- delivery_ok = _delivery(
- stop_id="d1",
- seq=1,
- customer_name="外部送货客户A",
- delivery_time="2026-10-12",
- contracts=[PlanContractLink(contractId="c1", contractNo="HT001")],
- products=[_stop_product("甲醇", product_id="prod-d1")],
- )
- delivery_gap = _delivery(
- stop_id="d2",
- seq=2,
- customer_name="外部送货客户B",
- delivery_time="2026-10-13",
- contracts=[],
- products=[
- _stop_product("乙醇", product_id="prod-d2a"),
- _stop_product("丙酮", product_id="prod-d2b"),
- ],
- )
- rows = build_contract_gap_export_rows(
- [_gap_item()],
- {"p1": (load, [delivery_ok, delivery_gap])},
- )
- assert len(rows) == 4
- assert [row["stopSegment"] for row in rows] == ["装货", "送货 #1", "送货 #2", "送货 #2"]
- assert [row["productName"] for row in rows] == ["甲醇", "甲醇", "乙醇", "丙酮"]
- assert [row["gapType"] for row in rows] == ["缺供方合同", "", "缺需方合同", "缺需方合同"]
- load_row = rows[0]
- assert load_row["loadCustomer"] == "外部装货客户"
- assert load_row["deliveryCustomer"] == ""
- assert load_row["deliveryTimes"] == ""
- ok_row = rows[1]
- assert ok_row["loadCustomer"] == ""
- assert ok_row["deliveryCustomer"] == "外部送货客户A"
- assert ok_row["deliveryTimes"] == "2026-10-12"
- gap_row = rows[3]
- assert gap_row["deliveryCustomer"] == "外部送货客户B"
- assert gap_row["deliveryTimes"] == "2026-10-13"
- assert gap_row["loadCustomer"] == ""
- for row in rows:
- assert row["planNo"] == "PL001"
- assert row["planDate"] == "2026-10-11"
- assert row["planType"] == "直销单"
- assert row["followStatus"] == "已安排"
- assert row["supplierName"] == "供方甲"
- assert row["customerName"] == "需方乙"
- def test_build_contract_gap_export_rows_internal_side_has_empty_gap_type():
- """内置客户免合同:装货行缺口为空,外送段仍标缺需方合同。"""
- load = _load(
- customer_name=INTERNAL,
- contracts=[],
- products=[_stop_product("甲醇", product_id="prod-load")],
- )
- delivery = _delivery(
- stop_id="d1",
- seq=1,
- customer_name="外部送货客户",
- delivery_time="2026-10-12T08:30:00",
- contracts=[],
- products=[_stop_product("甲醇", product_id="prod-d1")],
- )
- rows = build_contract_gap_export_rows(
- [_gap_item()],
- {"p1": (load, [delivery])},
- )
- assert [row["stopSegment"] for row in rows] == ["装货", "送货 #1"]
- assert [row["gapType"] for row in rows] == ["", "缺需方合同"]
- assert rows[1]["deliveryTimes"] == "2026-10-12"
|