import json from datetime import date from decimal import Decimal from pathlib import Path from group import ( draft_from_group, drafts_from_oms_payload, group_by_supplier, is_claimable, is_oms_envelope, missing_mdm_reason, money4, row_from_oms_item, ) from repo import PurchaseContractRow _OMS_EXAMPLE = ( Path(__file__).resolve().parent.parent / "examples" / "oms_purchase_contract.json" ) 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_protocol_rerun_is_not_claimable(): row = _row(contract_entry_status=0, contract_no="HT-OLD") assert is_claimable(row) is False def test_blank_contract_no_is_still_claimable(): assert is_claimable(_row(contract_entry_status=0, contract_no=" ")) is True assert is_claimable(_row(contract_entry_status=0, contract_no="")) is True assert is_claimable(_row(contract_entry_status=0, contract_no=None)) is True def test_processing_or_done_is_not_claimable(): assert is_claimable(_row(process_status=3)) is False assert is_claimable(_row(process_status=1)) is False def test_group_by_supplier_keeps_fid_order_and_first_header(): rows = [ _row(fid=2, supplier_id="B", payment_term=30, supplier_mdm_code="MDM-B"), _row(fid=1, supplier_id="A", payment_term=90, supplier_mdm_code="MDM-A"), _row(fid=3, supplier_id="A", payment_term=60, oms_id=2026100502, goods_id="G0002"), ] groups = group_by_supplier(rows) assert [g[0].supplier_id for g in groups] == ["A", "B"] assert [r.fid for r in groups[0]] == [1, 3] draft = draft_from_group(groups[0]) assert draft.customer_code == "MDM-A" assert draft.payment_days == "90" assert draft.order_date == "2026-10-01" assert draft.contract_sign_date == "2026-10-01" assert draft.contract_start_date == "2026-10-02" assert draft.contract_end_date == "2027-09-30" assert draft.amount == "2000.0000" assert draft.source_type == "" assert draft.contract_category == "" assert draft.settlement_type == "" assert draft.is_prepayment == "" assert draft.payment_method == "" assert len(draft.goods_lines) == 2 assert draft.goods_lines[0].goods_code == "QX0100167583" assert draft.goods_lines[0].operation_code == "QX0100167583" assert draft.goods_lines[0].mdm_code == "QX0100167583" assert draft.goods_lines[0].unit_price == "100.0000" assert draft.belong_year == "2026" # 同供应商但货主或三个日期任一不同,不得收成同一张草稿。 def test_same_supplier_splits_when_org_or_dates_differ(): rows = [ _row(fid=1, supplier_id="A"), _row(fid=2, supplier_id="A", org_code="902", oms_id=2), _row(fid=3, supplier_id="A", contract_sign_date=date(2026, 11, 1), oms_id=3), _row(fid=4, supplier_id="A", contract_start_date=date(2026, 11, 2), oms_id=4), _row(fid=5, supplier_id="A", contract_end_date=date(2028, 1, 1), oms_id=5), _row(fid=6, supplier_id="A", oms_id=6, goods_id="G0009"), ] groups = group_by_supplier(rows) drafts = { tuple(row.fid for row in group): draft_from_group(group) for group in groups } assert len(groups) == 5 assert (1, 6) in drafts assert drafts[(1, 6)].amount == "2000.0000" assert len(drafts[(1, 6)].goods_lines) == 2 for fid in (2, 3, 4, 5): assert (fid,) in drafts assert len(drafts[(fid,)].goods_lines) == 1 def test_missing_mdm_reason(): rows = [_row(supplier_mdm_code="")] assert missing_mdm_reason(rows) == "缺少供应商MDM码" assert missing_mdm_reason([_row(goods_mdm_code="")]) == "缺少货品MDM码" assert missing_mdm_reason([_row()]) is None def test_money4(): assert money4(Decimal("10.5")) == "10.5000" def test_oms_envelope_skips_protocol_and_merges_same_supplier(): payload = json.loads(_OMS_EXAMPLE.read_text(encoding="utf-8")) assert is_oms_envelope(payload) is True drafts = drafts_from_oms_payload(payload) assert len(drafts) == 1 draft = drafts[0] assert draft.customer_code == "DW0100046361" assert draft.customer_name == "重庆亿昊药业有限公司" assert draft.order_date == "2026-10-25" assert draft.contract_sign_date == "2026-10-25" assert draft.contract_start_date == "2026-10-25" assert draft.contract_end_date == "2027-10-24" assert draft.amount == "300.0000" assert draft.payment_days == "30" assert draft.belong_year == "2026" assert draft.submit_mode == "submit" assert [line.mdm_code for line in draft.goods_lines] == [ "FQX0100020661", "FQX0100031787", "FQX0100044037", ] assert [line.quantity for line in draft.goods_lines] == [10.0, 10.0, 10.0] def test_oms_item_maps_mdm_and_dates(): row = row_from_oms_item( { "fid": 9, "omsId": 2026102509, "supplierId": "SUP001", "supplierName": "重庆亿昊药业有限公司", "contractSignDate": "2026-10-25", "contractStartDate": "2026-10-26", "contractEndDate": "2027-10-24", "paymentTerm": 90, "goodsId": "G1", "goodsName": "阿莫西林胶囊", "regNo": "H1", "spec": "0.25g", "unit": "盒", "qty": "2.0000", "unitPrice": "12.5000", "purchaserId": "P1", "purchaserName": "张三", "plannerId": "PL1", "plannerName": "李四", "orgCode": "901", "goodsMdmCode": "FQX0100020661", "supplierMdmCode": "DW0100046361", } ) assert row.fid == 9 assert row.oms_id == 2026102509 assert row.goods_mdm_code == "FQX0100020661" assert row.supplier_mdm_code == "DW0100046361" assert row.contract_start_date == date(2026, 10, 26) assert row.qty == Decimal("2.0000") assert is_claimable(row) is True def test_page_draft_json_is_not_oms_envelope(): assert is_oms_envelope({"jobId": "x", "goodsLines": []}) is False assert is_oms_envelope({"data": []}) is True