feat: account for defects and five-unit batches in delivery forecasts
This commit is contained in:
@@ -404,6 +404,66 @@ class TriggerGateTests(unittest.TestCase):
|
||||
self.assertNotIn(key, bridge._candidate_continuations)
|
||||
|
||||
|
||||
class ProductionQuantityTests(unittest.TestCase):
|
||||
def test_defect_allowance_precedes_batch_rounding_at_exact_boundaries(self) -> None:
|
||||
for demand, expected in ((1, 5), (4, 5), (5, 10), (10, 15), (19, 20), (20, 25), (25, 30), (95, 100), (190, 200)):
|
||||
with self.subTest(demand=demand):
|
||||
self.assertEqual(bridge.production_quantity_for_demand(demand), expected)
|
||||
# Integer arithmetic must also cover quantities beyond float precision.
|
||||
demand = 10**18 + 19
|
||||
planned = bridge.production_quantity_for_demand(demand)
|
||||
self.assertEqual(planned % 5, 0)
|
||||
self.assertGreaterEqual(planned * 95, demand * 100)
|
||||
self.assertLess((planned - 5) * 95, demand * 100)
|
||||
|
||||
def test_invalid_demand_stops_before_api_or_recording(self) -> None:
|
||||
for value in (0, -1, True, 5.0, "5"):
|
||||
with (
|
||||
self.subTest(value=value),
|
||||
mock.patch.object(bridge, "run_controlled_query") as query,
|
||||
mock.patch.object(bridge, "write_record") as record,
|
||||
):
|
||||
with self.assertRaises(bridge.InputError):
|
||||
bridge.build_report(bridge.RequestInput("eRob70H50I-FS-18CN[V5]", value))
|
||||
query.assert_not_called()
|
||||
record.assert_not_called()
|
||||
|
||||
def test_initial_and_follow_up_send_adjusted_quantity_once_to_controlled_script(self) -> None:
|
||||
request = bridge.RequestInput(model="eRob70H50I-FS-18CN[V5]", quantity=5)
|
||||
completed = SimpleNamespace(stdout=bridge.json.dumps(successful_payload()), stderr="", returncode=0)
|
||||
for offset, expected_calls in ((0, 5), (bridge.CANDIDATE_BATCH_SIZE, 4)):
|
||||
with (
|
||||
self.subTest(offset=offset),
|
||||
mock.patch.object(bridge.subprocess, "run", return_value=completed) as run,
|
||||
mock.patch.object(bridge, "write_record") as record,
|
||||
):
|
||||
report = bridge.build_report(request, candidate_offset=offset)
|
||||
self.assertEqual(run.call_count, expected_calls)
|
||||
for call in run.call_args_list:
|
||||
command = call.args[0]
|
||||
self.assertEqual(command[command.index("--quantity") + 1], "10")
|
||||
self.assertIn(f"输入需求:{request.model},5台", report)
|
||||
self.assertEqual(report.count("- 需求数量:5台"), expected_calls)
|
||||
self.assertEqual(report.count("- 排产测算数量:10台"), expected_calls)
|
||||
self.assertEqual(record.call_args.args[0].quantity, 5)
|
||||
recorded = bridge.render_record(*record.call_args.args)
|
||||
self.assertIn("**输入数量**:5台", recorded)
|
||||
self.assertIn("**排产测算数量(API查询数量)**:10台", recorded)
|
||||
|
||||
def test_stock_coverage_uses_same_quantity_as_api_forecast(self) -> None:
|
||||
payload = successful_payload()
|
||||
payload["data"]["库存信息"]["可用库存(扣除了待产数量)"] = 7
|
||||
with (
|
||||
mock.patch.object(bridge, "run_controlled_query", return_value=payload),
|
||||
mock.patch.object(bridge, "write_record"),
|
||||
):
|
||||
report = bridge.build_report(bridge.RequestInput("eRob70H50I-BHM-18CTC[V5]", 5))
|
||||
self.assertIn("库存覆盖口径:按排产测算数量判断", report)
|
||||
self.assertIn("部分覆盖,仍需补齐3台", report)
|
||||
self.assertIn("是否完全覆盖数量:否", report)
|
||||
self.assertIn("现货候选:无", report)
|
||||
|
||||
|
||||
class CandidateBatchTests(unittest.TestCase):
|
||||
def setUp(self) -> None:
|
||||
self.request = bridge.RequestInput(model="eRob70H50I-FS-18CN[V5]", quantity=10)
|
||||
|
||||
Reference in New Issue
Block a user