extends SceneTree const FixtureCleanup := preload("res://tests/helpers/ui_audio_fixture_cleanup.gd") var _finishing := false ## Uses the real Main business controls and Runtime paid-service boundary. ## No amount, deficit threshold or production attribute assignment is introduced. var _checks := 0 var _failures := 0 var _runtime: Variant var _clock: Variant var _main: Control var _panel: BusinessManagementPanel var _room_id: StringName = &"" var _workplace_id: StringName = &"" var _reception_id: StringName = &"" var _warehouse_id: StringName = &"" var _cleaning_id: StringName = &"" func _initialize() -> void: call_deferred("_run") func _run() -> void: _runtime = root.get_node("SimulationRuntime") _clock = root.get_node("GameClock") var state: Variant = root.get_node("GameState") _clock.reset(1, 6, 0) state.reset() _runtime.initialize(_clock, state, 42602) _clock.set_paused(true) root.size = Vector2i(1280, 720) _main = load("res://scenes/main/main.tscn").instantiate() as Control _main.set("manual_save_path", "user://tests/pending_service_pricing_%d/manual" % OS.get_process_id()) root.add_child(_main) _runtime.configure_save_policy({&"enabled": false, &"daily_checkpoint_enabled": false}) await process_frame await process_frame _panel = _main.find_child("BusinessManagementPanel", true, false) as BusinessManagementPanel _expect(_panel != null, "normal Main includes business controls") if _panel == null: _finish() return # Existing Anri fixture plus one paid cleaning room for non-customer UI. for row: Array in [ [&"reception", Vector3i(-6, 0, 0)], [&"warehouse", Vector3i(-6, 0, 1)], [&"premium_room", Vector3i(-6, 2, 0)], [&"warehouse", Vector3i(-6, 2, 1)], [&"service_stairs", Vector3i(-7, 1, 1)], [&"service_stairs", Vector3i(-7, 2, 1)], [&"cleaning_room", Vector3i(2, 0, 1)], ]: var built: CommandResult = _runtime.submit_command(&"build_facility", {&"definition_id": row[0], &"origin": row[1]}) _expect(built.is_success(), "normal paid fixture build %s: %s" % [row[0], built.message]) if not built.is_success(): _finish() return _clock.advance_minutes(_runtime.definition_registry.get_facility(row[0]).build_minutes) for facility: FacilityInstance in _runtime.facility_service.get_instances(): if facility.definition_id == &"premium_room": _room_id = facility.instance_id elif facility.definition_id == &"reception": _reception_id = facility.instance_id elif facility.definition_id == &"cleaning_room": _cleaning_id = facility.instance_id elif facility.definition_id == &"warehouse": if facility.origin.y == 2: _workplace_id = facility.instance_id else: _warehouse_id = facility.instance_id _expect(not _room_id.is_empty() and not _workplace_id.is_empty() and not _reception_id.is_empty() and not _warehouse_id.is_empty() and not _cleaning_id.is_empty(), "real customer and non-customer facilities complete before the report") if _room_id.is_empty() or _workplace_id.is_empty() or _reception_id.is_empty() or _warehouse_id.is_empty() or _cleaning_id.is_empty(): _finish() return _expect(_runtime.submit_command(&"hire_staff_candidate", {&"candidate_id": &"heroine_anri"}).is_success(), "canonical free Anri remains recruitable") var assignment: CommandResult = _runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": &"heroine_anri", &"facility_id": _workplace_id, &"template_id": &"DAY"}) _expect(assignment.is_success(), "normal accessible workplace accepts Anri placement") _expect(_runtime.get_facility_business_price(_room()) == 264, "approved room fee includes existing Anri20 percent") _test_owned_pending_report() await _test_normal_ui() _test_frozen_service_price() _finish() func _test_owned_pending_report() -> void: var before: Dictionary = _runtime.create_snapshot() var before_bytes := var_to_bytes(before) var before_digest := SimulationDigest.compute(before) var readmodel: Dictionary = _runtime.get_facility_service_pricing_readmodel(_room()) _expect(readmodel[&"normal_price"] == _runtime.get_facility_business_price(_room()), "readmodel uses actual existing normal charge") _expect(readmodel[&"service_attribute"] == null and readmodel.has(&"deficient_attributes") and readmodel[&"deficient_attributes"] == null, "unassigned service attribute and unassessed deficits remain null") _expect(_is_pending(readmodel), "unknown deficiency is neither nonmatch nor zero-G surcharge") var report: Dictionary = _runtime.get_business_management_report() var row := _row(report, _room_id) _expect(not row.is_empty() and row[&"price"] == 264 and row[&"service_pricing"][&"normal_price"] == row[&"price"], "normal business report preserves its price and includes separate pending rule") var row_before := row.duplicate(true) var second: Dictionary = _runtime.get_facility_service_pricing_readmodel(_room()) readmodel[&"normal_price"] = -900 readmodel[&"surcharge"] = 0 readmodel[&"resolved"] = true _expect(_is_pending(second) and second[&"normal_price"] == 264, "independent readmodel does not share mutable caller data") _expect(var_to_bytes(row) == var_to_bytes(row_before), "direct readmodel does not alias report readmodel") (row[&"service_pricing"] as Dictionary).clear() (report[&"facilities"] as Array).clear() var fresh_row := _row(_runtime.get_business_management_report(), _room_id) _expect(_is_pending(fresh_row[&"service_pricing"]) and fresh_row[&"price"] == 264, "mutating nested report output cannot alter subsequent reports") var reception: FacilityInstance = _runtime.facility_service.get_instance(_reception_id) var free_readmodel: Dictionary = _runtime.get_facility_service_pricing_readmodel(reception) _expect(free_readmodel[&"normal_price"] == 0 and _is_pending(free_readmodel), "existing free normal fee does not settle extra rule to zero") # These are schema/display examples only, never assigned to production data. for attribute: StringName in [&"appetite", &"relaxation", &"sexual", &"gambling"]: var named: Dictionary = FacilityPricing.pending_service_readmodel(264, attribute) _expect(named[&"service_attribute"] == attribute and named[&"service_attribute"] is StringName and _is_pending(named), "known service label alone cannot resolve a customer match: %s" % attribute) var after: Dictionary = _runtime.create_snapshot() _expect(var_to_bytes(after) == before_bytes, "report/getter and caller mutations preserve full typed snapshot order and bytes") _expect(SimulationDigest.compute(after) == before_digest, "observation preserves values including RNG, IDs and all saved domain events") func _test_normal_ui() -> void: _main.call("_activate_management_mode", &"business") _panel.select_facility(_room_id) await process_frame await process_frame _expect(_panel.visible and _panel.price_option.item_count == 5 and not _panel.price_option.disabled, "normal business UI retains five existing price policies") var text := _panel.quote_label.text _expect(text.contains("通常料金") and text.count("設定後 264G") == 1 and text.count("現在 264G") == 1 and text.count("標準 220G") == 1, "current, draft and base normal fees are each shown once") _expect(text.contains("サービス属性:未設定") and text.contains("欲求一致加算:未設定"), "UI identifies both unset extra-rule parts separately from normal charge") _expect(not text.contains("加算0G") and not text.contains("利用不可") and not text.contains("resolved"), "pending UI neither invents zero nor blocks use nor exposes implementation terms") _expect(_panel.quote_label.autowrap_mode == TextServer.AUTOWRAP_WORD_SMART, "additional status wraps in normal narrow business panel") var before := var_to_bytes(_runtime.create_snapshot()) var owned := _panel.get_report() var row := _row(owned, _room_id) (row[&"service_pricing"] as Dictionary).clear() _panel.refresh() _expect(_is_pending(_row(_panel.get_report(), _room_id)[&"service_pricing"]), "panel client-owned report is defensive at nested pricing data") for layer in [0, 1]: _main.call("_set_layer", layer) _panel.refresh() _expect(_panel.quote_label.text == text, "palette/layer refresh keeps current normal fee and pending rule unchanged") _main.call("_set_layer", 0) _panel.select_facility(_reception_id) var reception_row := _row(_panel.get_report(), _reception_id) _expect(reception_row[&"category"] == &"guest_service" and reception_row[&"price"] == 0 and not bool(reception_row[&"can_price"]), "actual reception is a zero-normal-price guest service") _expect(_panel.price_option.disabled and _panel.quote_label.text.count("通常の利用料金はありません(現在 0G)。") == 1 and _panel.quote_label.text.contains("サービス属性:未設定") and _panel.quote_label.text.contains("欲求一致加算:未設定"), "normal reception UI separates free normal fee from unset addition") _expect(not _panel.quote_label.text.contains("この施設に利用料金はありません。") and not _panel.quote_label.text.contains("加算0G") and not _panel.business_open_button.disabled, "reception neither claims complete no-fee nor blocks ordinary admission") _expect(_is_pending(reception_row[&"service_pricing"]) and reception_row[&"service_pricing"][&"service_attribute"] == null, "reception keeps unknown assessment/attribute/amount owned and unresolved") _panel.select_facility(_warehouse_id) _expect(_panel.price_option.disabled and _panel.quote_label.text == "この施設に利用料金はありません。" and not _panel.quote_label.text.contains("欲求一致加算"), "non-customer warehouse is not presented as a pending customer charge") _expect(_panel.business_open_button.text == "営業する" and _panel.effect_label.text == "営業・休業を設定できます。" and _panel.explanation_label.text.contains("補給"), "warehouse keeps actual supply controls and explanation") _panel.select_facility(_cleaning_id) _expect(_panel.price_option.disabled and _panel.quote_label.text == "この施設に利用料金はありません。" and not _panel.quote_label.text.contains("欲求一致加算"), "paid cleaning base is not presented as a pending customer charge") _expect(_panel.business_open_button.text == "清掃業務を有効にする" and _panel.facility_status_label.text.contains("顧客利用なし") and _panel.effect_label.text == "清掃業務の有効・無効を設定できます。", "cleaning retains staff-work meaning instead of customer admission") _panel.select_facility(_room_id) _expect(var_to_bytes(_runtime.create_snapshot()) == before, "customer and non-customer business selection/refresh changes no simulation snapshot") func _test_frozen_service_price() -> void: _expect(_runtime.submit_command(&"register_guest_wallet", {&"guest_id": &"pending_rule_payer", &"gold": 1000}).is_success(), "fund controlled normal service payer") var queued: CommandResult = _runtime.submit_command(&"create_service_request", {&"request_id": &"pending_rule_stay", &"facility_id": _room_id, &"guest_ids": [&"pending_rule_payer"], &"service_type": &"lodging"}) _expect(queued.is_success(), "unset extra rule does not stop ordinary service acceptance") if not queued.is_success(): return var request: ServiceRequest = _runtime.facility_service.get_request(&"pending_rule_stay") _expect(request.quoted_price == 264, "accepted request freezes existing current normal fee") var queue_save: Dictionary = _runtime.create_snapshot() var changed: CommandResult = _runtime.submit_command(&"set_facility_policy", {&"facility_id": _room_id, &"patch": {&"price_mode": &"expensive"}}) _expect(changed.is_success() and _runtime.get_facility_business_price(_room()) == 396, "new normal estimate follows existing policy then Anri rounding") _expect(_runtime.get_facility_service_pricing_readmodel(_room())[&"normal_price"] == 396 and request.quoted_price == 264, "new readmodel never rewrites an already queued quotation") _expect(_runtime.restore_snapshot(queue_save), "queued quote and placement restore through actual Runtime validation") request = _runtime.facility_service.get_request(&"pending_rule_stay") _expect(request != null and request.quoted_price == 264 and _is_pending(_runtime.get_facility_service_pricing_readmodel(_room())), "loading retains queued normal price without resolving unknown surcharge") _clock.advance_one_minute() var active: Array = _runtime.facility_service.get_active_services(_room_id) _expect(active.size() == 1 and active[0].price_snapshot == 264, "normal service starts with frozen accepted price") if active.is_empty(): return var service_id: StringName = active[0].service_id var started: Dictionary = _runtime.create_snapshot() _expect(_runtime.restore_snapshot(started), "started service restores while extra rule remains pending") _expect(_runtime.submit_command(&"set_staff_work_assignment", {&"staff_id": &"heroine_anri", &"facility_id": &"", &"template_id": &"DAY"}).is_success(), "unassign Anri after accepted service has started") _expect(_runtime.get_facility_service_pricing_readmodel(_room())[&"normal_price"] == 220 and _runtime.facility_service.get_service(service_id).price_snapshot == 264, "new normal fee reverts but loaded service price stays frozen") _clock.advance_minutes(721) _expect(_runtime.facility_service.get_service(service_id).state == ServiceInstance.State.COMPLETED, "ordinary paid service completes with unknown extra rule") _expect(_runtime.economy_service.get_balance(&"GUEST_WALLET:pending_rule_payer") == 736, "customer pays frozen264 exactly once") var revenue := 0 for entry: LedgerEntry in _runtime.economy_service.get_entries(): if entry.source_entity_id == _room_id and entry.category == &"SERVICE_SALE": revenue += entry.amount _expect(revenue == 264 and bool(_runtime.economy_service.validate_ledger()[&"ok"]), "facility receives exactly customer's264 with balanced ledger") func _is_pending(value: Dictionary) -> bool: return value.has(&"resolved") and value[&"resolved"] is bool and value[&"resolved"] == false and value.has(&"deficient_attributes") and value[&"deficient_attributes"] == null and value.has(&"matches") and value[&"matches"] == null and value.has(&"surcharge") and value[&"surcharge"] == null and value.has(&"total") and value[&"total"] == null func _room() -> FacilityInstance: return _runtime.facility_service.get_instance(_room_id) func _row(report: Dictionary, id: StringName) -> Dictionary: for row: Dictionary in report.get(&"facilities", []): if StringName(row.get(&"facility_id", &"")) == id: return row return {} func _expect(ok: bool, label: String) -> void: _checks += 1 if not ok: _failures += 1 push_error(label) func _finish() -> void: if _finishing: return _finishing = true if is_instance_valid(_main): var final_cleanup: Dictionary = await FixtureCleanup.free_owner_and_wait(self, _main) if not bool(final_cleanup.get(&"passed", false)): _failures += 1 push_error("ordinary Main pricing fixture audio cleanup failed") print("Pending service pricing report: %d checks, %d failures" % [_checks, _failures]) quit(1 if _failures > 0 else 0)