"""PM eligibility is shared with processing, before source-field completion.""" import json from pathlib import Path import tempfile import unittest from arr_processing.policy import load_processor_policy from arr_web.arr_data_review import DataFieldReviews from arr_web.contracts import PortalError from tests.test_arr_data_review import source_document, raw, gap, CONTEXT, DAY, REQUEST, ACTOR, SOURCE_MANIFEST class PMReviewTests(unittest.TestCase): def setUp(self): temporary = tempfile.TemporaryDirectory(prefix="arr-pm-review-") self.addCleanup(temporary.cleanup) self.root = Path(temporary.name) / "reviews" self.policy = load_processor_policy(Path(__file__).resolve().parents[1]) self.service = DataFieldReviews(root=self.root, policy=self.policy, context=CONTEXT) self.document = source_document(2) def prepare(self): return self.service.prepare(REQUEST, raw(self.document), SOURCE_MANIFEST, DAY) def test_explicit_pm_needs_no_fields_and_does_not_hide_other_rows(self): self.document["records"][0]["fields"]["ROOM_CATEGORY_LABEL"] = {"state": "available", "value": " pm "} for field in ("DISP_ROOM_NO", "RATE_CODE", "BLOCK_CODE", "ADULTS"): gap(self.document, field) gap(self.document, "DISP_ROOM_NO", sequence=2) review = self.prepare() self.assertEqual([item["item_id"] for item in review["items"]], ["2:DISP_ROOM_NO"]) self.assertEqual(review["excluded_pm_count"], 1) self.assertEqual(review["excluded_cancelled_count"], 0) with self.assertRaisesRegex(PortalError, "PM"): self.service.update(REQUEST, "1:BLOCK_CODE", review["revision"], "IGNORED", ACTOR) def test_zero_price_or_nine_thousand_room_number_does_not_identify_pm(self): for row in self.document["records"]: row["fields"]["EFFECTIVE_RATE_AMOUNT"] = {"state": "available", "value": "0"} row["fields"]["DISP_ROOM_NO"] = {"state": "available", "value": "9002"} row["fields"]["ROOM_CATEGORY_LABEL"] = {"state": "available", "value": "PMX"} gap(self.document, "ADULTS") review = self.prepare() self.assertEqual(review["excluded_pm_count"], 0) self.assertIn("1:ADULTS", [item["item_id"] for item in review["items"]]) def test_cancelled_pm_is_counted_once_as_cancelled(self): row = self.document["records"][0] row["reservation_status"] = "Cancelled" row["fields"]["ROOM_CATEGORY_LABEL"] = {"state": "available", "value": "PM"} gap(self.document, "BLOCK_CODE", sequence=2) review = self.prepare() self.assertEqual((review["excluded_cancelled_count"], review["excluded_pm_count"]), (1, 0)) def test_prior_decisions_remain_audited_when_completed_room_type_is_pm(self): gap(self.document, "BLOCK_CODE") gap(self.document, "ROOM_CATEGORY_LABEL") review = self.prepare() original = self.service.original(REQUEST) review = self.service.update(REQUEST, "1:BLOCK_CODE", review["revision"], "VERIFIED", ACTOR) review = self.service.update(REQUEST, "1:ROOM_CATEGORY_LABEL", review["revision"], "PM", ACTOR) self.assertEqual([item["item_id"] for item in review["items"]], ["1:ROOM_CATEGORY_LABEL"]) self.assertTrue(review["items"][0]["confirmed"]) self.assertEqual(review["excluded_pm_count"], 1) self.assertTrue(review["can_finalize"]) with self.assertRaisesRegex(PortalError, "PM"): self.service.update(REQUEST, "1:BLOCK_CODE", review["revision"], "CHANGED", ACTOR) self.service.finalize(REQUEST, review["revision"], ACTOR) derived = json.loads(self.service.payload(REQUEST)[0]) self.assertEqual(self.service.original(REQUEST), original) changes = derived["manual_data_review"]["manifest"]["changes"] self.assertEqual({item["field"]: item["value"] for item in changes}, {"BLOCK_CODE": "VERIFIED", "ROOM_CATEGORY_LABEL": "PM"}) def test_existing_room_type_normalization_is_shared_by_exclusion_count_and_edit_guard(self): self.document["records"][0]["fields"]["ROOM_CATEGORY_LABEL"] = {"state": "available", "value": "PM😀"} gap(self.document, "BLOCK_CODE") gap(self.document, "DISP_ROOM_NO", sequence=2) review = self.prepare() self.assertEqual(review["excluded_pm_count"], 1) self.assertEqual([item["item_id"] for item in review["items"]], ["2:DISP_ROOM_NO"]) with self.assertRaisesRegex(PortalError, "PM"): self.service.update(REQUEST, "1:BLOCK_CODE", review["revision"], "IGNORED", ACTOR) def test_manually_completed_room_type_can_be_corrected_before_finalization(self): gap(self.document, "ROOM_CATEGORY_LABEL") gap(self.document, "BLOCK_CODE") review = self.prepare() review = self.service.update(REQUEST, "1:ROOM_CATEGORY_LABEL", review["revision"], "PM", ACTOR) self.assertEqual(review["pending_count"], 0) review = self.service.update(REQUEST, "1:ROOM_CATEGORY_LABEL", review["revision"], "SU6", ACTOR) self.assertEqual(review["excluded_pm_count"], 0) self.assertEqual(review["pending_count"], 1) self.assertIn("1:BLOCK_CODE", [item["item_id"] for item in review["items"]]) if __name__ == "__main__": unittest.main()