"""运输计划多段:内部客户地磅默认值与数量平衡校验""" from decimal import Decimal from app.services.pl_internal_customer import INTERNAL_CUSTOMER_NAMES from app.services.pl_plan_stop_rules import ( load_delivery_product_gap, normalize_stop_dibang_fields, resolve_stop_dibang_defaults, warn_qty_imbalance, ) def test_internal_shanxia_load_outbound(): name = "安庆市山峡化工有限公司" assert name in INTERNAL_CUSTOMER_NAMES assert resolve_stop_dibang_defaults(name, "load") == (True, "outbound") def test_internal_shanxia_delivery_inbound(): name = "安庆市山峡化工有限公司" assert resolve_stop_dibang_defaults(name, "delivery") == (True, "inbound") def test_internal_yundong_load_outbound(): name = "安徽云栋化工有限公司" assert resolve_stop_dibang_defaults(name, "load") == (True, "outbound") def test_internal_yundong_delivery_inbound(): name = "安徽云栋化工有限公司" assert resolve_stop_dibang_defaults(name, "delivery") == (True, "inbound") def test_external_customer_no_dibang(): assert resolve_stop_dibang_defaults("外部客户有限公司", "load") == (False, "none") assert resolve_stop_dibang_defaults("外部客户有限公司", "delivery") == (False, "none") def test_delivery_defaults_use_delivery_customer(): """送货段地磅默认以本段客户是否为内部客户为准。""" internal = "安庆市山峡化工有限公司" assert resolve_stop_dibang_defaults(internal, "delivery") == (True, "inbound") assert resolve_stop_dibang_defaults("外部客户有限公司", "delivery") == (False, "none") def test_normalize_stop_dibang_fields_repairs_none_direction(): gen, direction = normalize_stop_dibang_fields( "安庆市山峡化工有限公司", "delivery", 1, "none", ) assert gen == 1 assert direction == "inbound" def test_normalize_respects_explicit_uncheck_for_internal_customer(): """内部客户显式传 0(如可选车皖H21522 取消勾选)时须保留,不得用默认值强制回 1。""" gen, direction = normalize_stop_dibang_fields( "安庆市山峡化工有限公司", "load", 0, "none", ) assert gen == 0 assert direction == "none" def test_normalize_respects_explicit_uncheck_for_internal_delivery(): gen, direction = normalize_stop_dibang_fields( "安徽云栋化工有限公司", "delivery", 0, "inbound", ) assert gen == 0 assert direction == "none" def test_normalize_forces_off_for_external_even_when_checked(): gen, direction = normalize_stop_dibang_fields( "外部客户有限公司", "load", 1, "outbound", ) assert gen == 0 assert direction == "none" def test_normalize_keeps_explicit_check_for_internal(): gen, direction = normalize_stop_dibang_fields( "安庆市山峡化工有限公司", "load", 1, "outbound", ) assert gen == 1 assert direction == "outbound" def test_external_empty_name_no_dibang(): assert resolve_stop_dibang_defaults(None, "load") == (False, "none") assert resolve_stop_dibang_defaults(" ", "delivery") == (False, "none") def test_warn_qty_balanced_returns_empty(): plan = [{"quantity": Decimal("30")}] load = [{"plan_qty": Decimal("30")}] delivery = [{"plan_qty": Decimal("30")}] assert warn_qty_imbalance(plan, load, delivery) == [] def test_warn_qty_uses_plan_qty_on_plan_products(): plan = [{"plan_qty": Decimal("28")}] load = [{"plan_qty": Decimal("28")}] delivery = [{"plan_qty": Decimal("28")}] assert warn_qty_imbalance(plan, load, delivery) == [] def test_warn_qty_load_vs_delivery_imbalance(): plan = [{"quantity": Decimal("28")}] load = [{"plan_qty": Decimal("30")}] delivery = [{"plan_qty": Decimal("28")}] warnings = warn_qty_imbalance(plan, load, delivery) assert warnings == [ "装货合计(30)与送货合计(28)不一致,请核对", ] def test_warn_qty_delivery_vs_load_imbalance(): plan = [{"quantity": Decimal("30")}] load = [{"plan_qty": Decimal("30")}] delivery = [{"plan_qty": Decimal("25")}] warnings = warn_qty_imbalance(plan, load, delivery) assert warnings == [ "装货合计(30)与送货合计(25)不一致,请核对", ] def test_warn_qty_load_delivery_decimal_imbalance(): plan = [{"quantity": Decimal("30")}] load = [{"plan_qty": Decimal("30")}] delivery = [{"plan_qty": Decimal("30.31")}] warnings = warn_qty_imbalance(plan, load, delivery) assert warnings == [ "装货合计(30)与送货合计(30.31)不一致,请核对", ] def test_warn_qty_multi_stop_30_equals_10_15_5_balanced(): """验收场景:计划 30 = 送货 10+15+5,装货 30。""" plan = [{"quantity": Decimal("30")}] load = [{"plan_qty": Decimal("30")}] delivery = [ {"plan_qty": Decimal("10")}, {"plan_qty": Decimal("15")}, {"plan_qty": Decimal("5")}, ] assert warn_qty_imbalance(plan, load, delivery) == [] def test_warn_qty_sums_multiple_rows_balanced_across_stops(): plan = [{"quantity": Decimal("10")}, {"quantity": Decimal("20")}] load = [{"plan_qty": Decimal("10")}, {"plan_qty": Decimal("15")}] delivery = [{"plan_qty": Decimal("25")}] assert warn_qty_imbalance(plan, load, delivery) == [] def test_warn_qty_sums_multiple_rows_imbalanced_across_stops(): plan = [{"quantity": Decimal("10")}, {"quantity": Decimal("20")}] load = [{"plan_qty": Decimal("10")}, {"plan_qty": Decimal("15")}] delivery = [{"plan_qty": Decimal("24")}] warnings = warn_qty_imbalance(plan, load, delivery) assert warnings == [ "装货合计(25)与送货合计(24)不一致,请核对", ] def test_same_product_quantities_sum_across_packages_and_delivery_stops(): load = [ {"product_id": "a", "product_name": "尿素", "plan_qty": Decimal("8")}, {"product_id": "a", "product_name": "尿素", "plan_qty": Decimal("2")}, ] delivery = [ {"product_id": "a", "product_name": "尿素", "plan_qty": Decimal("6")}, {"product_id": "a", "product_name": "尿素", "plan_qty": Decimal("4")}, ] assert warn_qty_imbalance([], load, delivery) == [] def test_warn_qty_names_each_product_when_sums_differ(): load = [ {"product_id": "a", "product_name": "尿素", "plan_qty": Decimal("10")}, {"product_id": "b", "product_name": "甲醇", "plan_qty": Decimal("5")}, ] delivery = [ {"product_id": "a", "product_name": "尿素", "plan_qty": Decimal("6")}, {"product_id": "b", "product_name": "甲醇", "plan_qty": Decimal("9")}, ] assert warn_qty_imbalance([], load, delivery) == [ "产品尿素:装货合计(10)与送货合计(6)不一致,请核对", "产品甲醇:装货合计(5)与送货合计(9)不一致,请核对", ] def test_product_set_mismatch_names_both_sides(): load = { "products": [ {"product_id": "a", "product_name": "A"}, {"product_id": "d", "product_name": "D"}, ] } deliveries = [ {"products": [{"product_id": "a", "product_name": "A"}]}, { "products": [ {"product_id": "b", "product_name": "B"}, {"product_id": "c", "product_name": "C"}, ] }, ] assert load_delivery_product_gap(load, deliveries) == ( "装货段有产品 D,送货段没有;送货段有产品 B、C,装货段没有。两边产品必须一致,不能保存" ) def test_same_product_with_different_packages_is_one_product(): load = { "products": [ {"product_id": "a", "product_name": "尿素", "package_spec": "桶"}, {"product_id": "a", "product_name": "尿素", "package_spec": "散装"}, ] } deliveries = [{"products": [{"product_id": "a", "product_name": "尿素", "package_spec": "袋"}]}] assert load_delivery_product_gap(load, deliveries) == "" def test_empty_product_rows_match(): assert load_delivery_product_gap({"products": []}, [{"products": []}]) == ""