169 lines
5.4 KiB
Python
169 lines
5.4 KiB
Python
from datetime import date
|
|
from decimal import Decimal
|
|
|
|
from errors import DiligenceError, NodeError
|
|
from job import outcome_from_run, run_batch
|
|
from persist import KIND_DILIGENCE, KIND_FAIL, KIND_OK, ContractOutcome, build_save
|
|
from repo import MemoryContractRepo, PurchaseContractRow
|
|
|
|
|
|
def _row(**overrides) -> PurchaseContractRow:
|
|
data = dict(
|
|
fid=1,
|
|
oms_id=2026100501,
|
|
supplier_id="SUP001",
|
|
supplier_name="示例供应商",
|
|
contract_sign_date=date(2026, 10, 1),
|
|
contract_start_date=date(2026, 10, 2),
|
|
contract_end_date=date(2027, 9, 30),
|
|
payment_term=90,
|
|
goods_id="G0001",
|
|
goods_name="阿莫西林胶囊",
|
|
reg_no="国药准字H20201234",
|
|
spec="0.25g*24粒",
|
|
unit="盒",
|
|
qty=Decimal("10.0000"),
|
|
unit_price=Decimal("100.0000"),
|
|
purchaser_id="P001",
|
|
purchaser_name="张三",
|
|
planner_id="PL001",
|
|
planner_name="李四",
|
|
contract_entry_status=None,
|
|
contract_no=None,
|
|
process_status=0,
|
|
org_code="901",
|
|
goods_mdm_code="QX0100167583",
|
|
supplier_mdm_code="DW0100046361",
|
|
)
|
|
data.update(overrides)
|
|
return PurchaseContractRow(**data)
|
|
|
|
|
|
def test_claim_pending_sets_processing_and_skips_protocol_rerun():
|
|
repo = MemoryContractRepo(
|
|
[
|
|
_row(),
|
|
_row(fid=2, oms_id=2026100502, process_status=1),
|
|
_row(fid=3, oms_id=2026100503, contract_entry_status=0, contract_no="HT-OLD"),
|
|
]
|
|
)
|
|
claimed = repo.claim_pending()
|
|
assert [row.fid for row in claimed] == [1]
|
|
assert repo.table3[1].process_status == 3
|
|
assert repo.table3[3].process_status == 0
|
|
|
|
|
|
def test_save_group_inserts_one_table4_row_per_oms_id():
|
|
repo = MemoryContractRepo(
|
|
[
|
|
_row(),
|
|
_row(fid=2, oms_id=2026100501, goods_id="G0002"),
|
|
_row(fid=3, oms_id=2026100502, goods_id="G0003"),
|
|
]
|
|
)
|
|
repo.claim_pending()
|
|
outcome = ContractOutcome(KIND_OK, "HT20261005001", None)
|
|
payload = build_save(list(repo.table3.values()), outcome)
|
|
repo.save_group(payload)
|
|
assert [row["oms_id"] for row in repo.table4] == [2026100501, 2026100502]
|
|
assert {row["contract_no"] for row in repo.table4} == {"HT20261005001"}
|
|
assert {row["action_code"] for row in repo.table4} == {1}
|
|
assert {row["contract_status"] for row in repo.table4} == {1}
|
|
assert {row["push_status"] for row in repo.table4} == {0}
|
|
assert repo.table3[1].process_status == 1
|
|
assert repo.table3[3].process_status == 1
|
|
|
|
|
|
def test_job_merges_same_supplier_and_writes_table4():
|
|
repo = MemoryContractRepo(
|
|
[
|
|
_row(),
|
|
_row(fid=2, oms_id=2026100502, goods_id="G0002"),
|
|
_row(fid=3, oms_id=2026100503, contract_entry_status=0, contract_no="HT-OLD"),
|
|
]
|
|
)
|
|
calls: list = []
|
|
|
|
def runner(draft):
|
|
calls.append(draft)
|
|
return ContractOutcome(KIND_OK, "HT20261005001", None)
|
|
|
|
run_batch(repo, runner=runner)
|
|
assert len(calls) == 1
|
|
assert [line.goods_code for line in calls[0].goods_lines] == [
|
|
"QX0100167583",
|
|
"QX0100167583",
|
|
]
|
|
assert [line.mdm_code for line in calls[0].goods_lines] == [
|
|
"QX0100167583",
|
|
"QX0100167583",
|
|
]
|
|
assert calls[0].customer_code == "DW0100046361"
|
|
assert [row["oms_id"] for row in repo.table4] == [2026100501, 2026100502]
|
|
assert {row["contract_no"] for row in repo.table4} == {"HT20261005001"}
|
|
assert {row["action_code"] for row in repo.table4} == {1}
|
|
assert {row["contract_status"] for row in repo.table4} == {1}
|
|
assert {row["push_status"] for row in repo.table4} == {0}
|
|
assert repo.table3[1].process_status == 1
|
|
assert repo.table3[2].process_status == 1
|
|
assert repo.table3[3].process_status == 0
|
|
|
|
|
|
def test_job_marks_diligence_fail():
|
|
repo = MemoryContractRepo([_row()])
|
|
|
|
def runner(draft):
|
|
return ContractOutcome(KIND_DILIGENCE, None, "客户未尽调")
|
|
|
|
run_batch(repo, runner=runner)
|
|
assert repo.table3[1].process_status == 2
|
|
assert "客户未尽调" in repo.table3[1].process_result
|
|
assert repo.table4[0]["contract_status"] == 3
|
|
assert repo.table4[0]["contract_no"] is None
|
|
assert repo.table4[0]["contract_fail_reason"] == "客户未尽调"
|
|
|
|
|
|
def test_job_skips_runner_when_mdm_missing():
|
|
repo = MemoryContractRepo([_row(supplier_mdm_code="")])
|
|
called = {"n": 0}
|
|
|
|
def runner(draft):
|
|
called["n"] += 1
|
|
return ContractOutcome(KIND_OK, "HT-X", None)
|
|
|
|
run_batch(repo, runner=runner)
|
|
assert called["n"] == 0
|
|
assert repo.table3[1].process_status == 2
|
|
assert "缺少供应商MDM码" in repo.table3[1].process_result
|
|
|
|
|
|
def test_outcome_from_run_maps_diligence():
|
|
def run():
|
|
raise DiligenceError("客户未尽调")
|
|
|
|
out = outcome_from_run(run)
|
|
assert out.kind == KIND_DILIGENCE
|
|
assert out.reason == "客户未尽调"
|
|
assert out.contract_no is None
|
|
|
|
|
|
def test_outcome_from_run_maps_empty_number_to_fail():
|
|
out = outcome_from_run(lambda: "")
|
|
assert out.kind == KIND_FAIL
|
|
assert "未读取到真实合同编号" in (out.reason or "")
|
|
|
|
|
|
def test_outcome_from_run_ok():
|
|
out = outcome_from_run(lambda: "HT9")
|
|
assert out == ContractOutcome(KIND_OK, "HT9", None)
|
|
|
|
|
|
def test_outcome_from_run_maps_node_error():
|
|
def run():
|
|
raise NodeError("客商加载失败")
|
|
|
|
out = outcome_from_run(run)
|
|
assert out.kind == KIND_FAIL
|
|
assert "客商加载失败" in (out.reason or "")
|
|
|