class_name ServiceRequest extends RefCounted ## Immutable-at-enqueue quotation for one facility visit. ## ## FacilityService owns the lifecycle. Price and policy values are copied when ## this object is configured so later facility policy changes cannot alter an ## already queued request. var request_id: StringName = &"" var guest_ids: Array[StringName] = [] var facility_id: StringName = &"" var service_type: StringName = &"default" var created_at := 0 var quoted_price := 0 var policy_snapshot: Dictionary = {} var policy_revision := 0 var reserved_inventory_ids: Array[StringName] = [] var preference_match := 0 var expected_quality := 0 var expected_wait := 0 var priority := 0 var enqueued_at := -1 var service_minutes := 1 func configure( p_request_id: StringName, p_facility_id: StringName, p_guest_ids: Array[StringName], p_service_type: StringName, p_created_at: int, options: Dictionary = {} ) -> ServiceRequest: request_id = p_request_id facility_id = p_facility_id guest_ids.assign(p_guest_ids) service_type = p_service_type created_at = maxi(p_created_at, 0) quoted_price = maxi(int(_value(options, &"quoted_price", 0)), 0) policy_snapshot = _dictionary_copy(_value(options, &"policy_snapshot", {})) policy_revision = maxi(int(_value(options, &"policy_revision", 0)), 0) reserved_inventory_ids = _string_name_array( _value(options, &"reserved_inventory_ids", []) ) preference_match = int(_value(options, &"preference_match", 0)) expected_quality = int(_value(options, &"expected_quality", 0)) expected_wait = maxi(int(_value(options, &"expected_wait", 0)), 0) priority = int(_value(options, &"priority", 0)) enqueued_at = int(_value(options, &"enqueued_at", -1)) service_minutes = maxi(int(_value(options, &"service_minutes", 1)), 1) return self func is_valid() -> bool: if request_id.is_empty() or facility_id.is_empty() or service_type.is_empty(): return false if guest_ids.is_empty() or service_minutes <= 0 or quoted_price < 0: return false var seen: Dictionary = {} for guest_id: StringName in guest_ids: if guest_id.is_empty() or seen.has(guest_id): return false seen[guest_id] = true return true func create_snapshot() -> Dictionary: return { &"request_id": String(request_id), &"guest_ids": _names_to_strings(guest_ids), &"facility_id": String(facility_id), &"service_type": String(service_type), &"created_at": created_at, &"quoted_price": quoted_price, &"policy_snapshot": policy_snapshot.duplicate(true), &"policy_revision": policy_revision, &"reserved_inventory_ids": _names_to_strings(reserved_inventory_ids), &"preference_match": preference_match, &"expected_quality": expected_quality, &"expected_wait": expected_wait, &"priority": priority, &"enqueued_at": enqueued_at, &"service_minutes": service_minutes, } static func from_snapshot(snapshot: Dictionary) -> ServiceRequest: if not snapshot.get(&"guest_ids", null) is Array: return null if not snapshot.get(&"policy_snapshot", null) is Dictionary: return null if not snapshot.get(&"reserved_inventory_ids", null) is Array: return null var request := ServiceRequest.new().configure( StringName(snapshot.get(&"request_id", "")), StringName(snapshot.get(&"facility_id", "")), _string_name_array(snapshot.get(&"guest_ids", [])), StringName(snapshot.get(&"service_type", "default")), int(snapshot.get(&"created_at", 0)), { &"quoted_price": snapshot.get(&"quoted_price", 0), &"policy_snapshot": snapshot.get(&"policy_snapshot", {}), &"policy_revision": snapshot.get(&"policy_revision", 0), &"reserved_inventory_ids": snapshot.get(&"reserved_inventory_ids", []), &"preference_match": snapshot.get(&"preference_match", 0), &"expected_quality": snapshot.get(&"expected_quality", 0), &"expected_wait": snapshot.get(&"expected_wait", 0), &"priority": snapshot.get(&"priority", 0), &"enqueued_at": snapshot.get(&"enqueued_at", -1), &"service_minutes": snapshot.get(&"service_minutes", 1), } ) return request if request.is_valid() else null static func _value(source: Dictionary, key: StringName, fallback: Variant) -> Variant: return source.get(key, source.get(String(key), fallback)) static func _dictionary_copy(source: Variant) -> Dictionary: return source.duplicate(true) if source is Dictionary else {} static func _string_name_array(source: Variant) -> Array[StringName]: var values: Array[StringName] = [] if not source is Array: return values for value: Variant in source: values.append(StringName(value)) return values static func _names_to_strings(source: Array[StringName]) -> Array[String]: var values: Array[String] = [] for value: StringName in source: values.append(String(value)) return values