From 30b2855dec27e244c7986e015fa37fbc0a3f65ed Mon Sep 17 00:00:00 2001
From: Nameru Thapa
+
{{ message }}
{{ completion_message }}
{% endif %} {% if transition_message %} -+ {{ transition_message }} +
+ {% endif %} + + {% if scan_message %} ++ {{ scan_message }} +
{% endif %} {% if step and current_unit %} diff --git a/tests/test_parallel_station_flow.py b/tests/test_parallel_station_flow.py new file mode 100644 index 0000000..bbf5f81 --- /dev/null +++ b/tests/test_parallel_station_flow.py @@ -0,0 +1,379 @@ +import pytest + +from app import create_app, db +from app.models import ( + Job, + JobStep, + Part, + ProductUnit, + StationInventory, + StepPart, + UnitStepProgress, +) +from app.services import ( + complete_current_step, + get_current_unit_and_step, + scan_job_barcode, +) + + +@pytest.fixture +def app(): + test_app = create_app( + { + "TESTING": True, + "SQLALCHEMY_DATABASE_URI": "sqlite:///:memory:", + } + ) + + yield test_app + + +def create_parallel_station_job( + upstream_station_id, + downstream_station_id, +): + upstream_part = Part( + name="Parallel Upstream Part", + unit="pcs", + ) + + downstream_part = Part( + name="Parallel Downstream Part", + unit="pcs", + ) + + job = Job( + name="Parallel Station Test", + quantity=2, + threshold_percent=20.0, + status="Active", + barcode="MES-PARALLEL-001", + ) + + db.session.add_all( + [ + upstream_part, + downstream_part, + job, + ] + ) + db.session.flush() + + unit_1 = ProductUnit( + job_id=job.id, + unit_number=1, + status="Pending", + ) + + unit_2 = ProductUnit( + job_id=job.id, + unit_number=2, + status="Pending", + ) + + upstream_step = JobStep( + job_id=job.id, + step_number=1, + station_id=upstream_station_id, + instruction="Complete upstream work", + ) + + downstream_step = JobStep( + job_id=job.id, + step_number=2, + station_id=downstream_station_id, + instruction="Complete downstream work", + ) + + db.session.add_all( + [ + unit_1, + unit_2, + upstream_step, + downstream_step, + ] + ) + db.session.flush() + + db.session.add_all( + [ + StepPart( + step_id=upstream_step.id, + part_id=upstream_part.id, + quantity=1, + ), + StepPart( + step_id=downstream_step.id, + part_id=downstream_part.id, + quantity=1, + ), + StationInventory( + station_id=upstream_station_id, + part_id=upstream_part.id, + quantity=2, + ), + StationInventory( + station_id=downstream_station_id, + part_id=downstream_part.id, + quantity=2, + ), + ] + ) + + db.session.commit() + + return { + "job_id": job.id, + "unit_1_id": unit_1.id, + "unit_2_id": unit_2.id, + "upstream_step_id": upstream_step.id, + "downstream_step_id": downstream_step.id, + } + + +@pytest.mark.parametrize( + ( + "upstream_station_id", + "downstream_station_id", + ), + [ + ("ST-01", "ST-02"), + ("ST-02", "ST-03"), + ("ST-03", "ST-04"), + ("ST-04", "ST-05"), + ("ST-05", "ST-01"), + ], +) +def test_tc16_upstream_station_can_start_next_unit( + app, + upstream_station_id, + downstream_station_id, +): + with app.app_context(): + ids = create_parallel_station_job( + upstream_station_id, + downstream_station_id, + ) + + job = db.session.get(Job, ids["job_id"]) + + first_result, first_error = complete_current_step( + job, + upstream_station_id, + ) + + assert first_error is None + assert ( + first_result["completed_unit"].id + == ids["unit_1_id"] + ) + assert ( + first_result["completed_step"].id + == ids["upstream_step_id"] + ) + + second_result, second_error = complete_current_step( + job, + upstream_station_id, + ) + + assert second_error is None + assert ( + second_result["completed_unit"].id + == ids["unit_2_id"] + ) + assert ( + second_result["completed_step"].id + == ids["upstream_step_id"] + ) + + upstream_progress_count = ( + UnitStepProgress.query.filter_by( + job_step_id=ids["upstream_step_id"], + status="Completed", + ).count() + ) + + downstream_progress_count = ( + UnitStepProgress.query.filter_by( + job_step_id=ids["downstream_step_id"], + status="Completed", + ).count() + ) + + assert upstream_progress_count == 2 + assert downstream_progress_count == 0 + + ready_unit, ready_step = get_current_unit_and_step( + job, + downstream_station_id, + ) + + assert ready_unit.id == ids["unit_1_id"] + assert ready_step.id == ids["downstream_step_id"] + + scanned_step, scan_error = scan_job_barcode( + "MES-PARALLEL-001", + downstream_station_id, + ) + + assert scan_error is None + assert scanned_step.id == ids["downstream_step_id"] + + downstream_result, downstream_error = ( + complete_current_step( + job, + downstream_station_id, + ) + ) + + assert downstream_error is None + assert ( + downstream_result["completed_unit"].id + == ids["unit_1_id"] + ) + assert downstream_result["unit_completed"] is True + + next_downstream_unit, next_downstream_step = ( + get_current_unit_and_step( + job, + downstream_station_id, + ) + ) + + assert next_downstream_unit.id == ids["unit_2_id"] + assert ( + next_downstream_step.id + == ids["downstream_step_id"] + ) + + unavailable_step, unavailable_error = scan_job_barcode( + "MES-PARALLEL-001", + upstream_station_id, + ) + + assert unavailable_step is None + assert unavailable_error == ( + "This job is not ready at this station." + ) +def test_tc17_kiosk_requires_new_scan_after_completion(app): + with app.app_context(): + ids = create_parallel_station_job( + "ST-03", + "ST-05", + ) + + client = app.test_client() + + completion_response = client.post( + "/kiosk", + data={ + "station_id": "ST-03", + "barcode": "MES-PARALLEL-001", + "action": "complete", + }, + ) + + assert completion_response.status_code == 200 + assert b"Unit 1, Step 1 completed." in ( + completion_response.data + ) + assert b"Pass unit to next station." in ( + completion_response.data + ) + assert b"Scan the Barcode for next unit." in ( + completion_response.data + ) + + assert b"Complete upstream work" not in ( + completion_response.data + ) + + with app.app_context(): + job = db.session.get(Job, ids["job_id"]) + + ready_unit, ready_step = get_current_unit_and_step( + job, + "ST-03", + ) + + assert ready_unit.id == ids["unit_2_id"] + assert ready_step.id == ids["upstream_step_id"] + + scan_response = client.post( + "/kiosk", + data={ + "station_id": "ST-03", + "barcode": "MES-PARALLEL-001", + "action": "scan", + }, + ) + + assert scan_response.status_code == 200 + assert b"Complete upstream work" in scan_response.data + + normalized_page = " ".join( + scan_response.get_data(as_text=True).split() + ) + + assert "Product Unit: 2 of 2" in normalized_page +def test_tc18_finished_unit_returns_kiosk_to_waiting(app): + with app.app_context(): + ids = create_parallel_station_job( + "ST-03", + "ST-05", + ) + + job = db.session.get(Job, ids["job_id"]) + + for _ in range(2): + result, error = complete_current_step( + job, + "ST-03", + ) + + assert error is None + assert result is not None + + client = app.test_client() + + first_finished_response = client.post( + "/kiosk", + data={ + "station_id": "ST-05", + "barcode": "MES-PARALLEL-001", + "action": "complete", + }, + ) + + assert first_finished_response.status_code == 200 + assert b"Pass unit to Finished Goods Section." in ( + first_finished_response.data + ) + assert b"Scan the Barcode for next unit." in ( + first_finished_response.data + ) + assert b"Complete downstream work" not in ( + first_finished_response.data + ) + + final_finished_response = client.post( + "/kiosk", + data={ + "station_id": "ST-05", + "barcode": "MES-PARALLEL-001", + "action": "complete", + }, + ) + + assert final_finished_response.status_code == 200 + assert b"Pass unit to Finished Goods Section." in ( + final_finished_response.data + ) + assert b"Production Complete:" in ( + final_finished_response.data + ) + assert b"Scan the Barcode for next unit." not in ( + final_finished_response.data + ) \ No newline at end of file -- GitLab