class_name ABGReadinessPageController extends RefCounted ## UI-independent Readiness Review view-data assembly. ## ## FormationRiskService remains responsible for loading, saving and accepting ## the readiness snapshot. This controller only validates the supplied saved ## formation boundary and copies the facts the existing PTY-002 View renders. const VALID_STATUSES: Array[String] = ["ordered", "ready"] func snapshot( company: Dictionary, formation: Dictionary, warnings: Array = [], reviewed_recruit_id := "", locale := "zh_CN" ) -> Dictionary: if company.is_empty(): return {"ok": false, "code": "COMPANY_REQUIRED"} var raw_recruits = company.get("owned_recruits", []) if not raw_recruits is Array: return {"ok": false, "code": "COMPANY_INVALID"} var raw_contract = company.get("active_contract", {}) if not raw_contract is Dictionary or Dictionary(raw_contract).is_empty(): return {"ok": false, "code": "FORMATION_CONTRACT_REQUIRED"} if formation.is_empty(): return {"ok": false, "code": "FORMATION_REQUIRED"} var contract: Dictionary = Dictionary(raw_contract).duplicate(true) var members := _members_by_id(raw_recruits) var capacity := int(formation.get("line_capacity", contract.get("line_capacity", 0))) if capacity <= 0: return {"ok": false, "code": "READINESS_CAPACITY_INVALID"} var saved_order = formation.get("saved_front_to_rear_ids", []) if not saved_order is Array or saved_order.is_empty(): return {"ok": false, "code": "READINESS_ORDER_REQUIRED"} var order_validation := _validate_saved_order(saved_order, members, capacity) if not order_validation.ok: return order_validation var status := String(formation.get("status", "")) if status not in VALID_STATUSES: return {"ok": false, "code": "READINESS_STATUS_INVALID"} var raw_receipts = formation.get("readiness_receipts", []) if not raw_receipts is Array: return {"ok": false, "code": "READINESS_RECEIPTS_INVALID"} if status == "ready" and raw_receipts.is_empty(): return {"ok": false, "code": "READINESS_RECEIPT_REQUIRED"} if not warnings is Array: return {"ok": false, "code": "READINESS_WARNINGS_INVALID"} var normalized_order: Array = order_validation.ids var copied_relations: Array = _copy_array(formation.get("relations", [])) var relation_by_id := _relations_by_id(copied_relations) var ordered_recruits: Array[Dictionary] = [] for position in range(normalized_order.size()): var recruit_id := String(normalized_order[position]) var recruit: Dictionary = Dictionary(members[recruit_id]).duplicate(true) ordered_recruits.append({ "position": position, "recruit_id": recruit_id, "recruit": recruit, "relation": Dictionary(relation_by_id.get(recruit_id, {})).duplicate(true), }) var selected := String(reviewed_recruit_id) if String(reviewed_recruit_id) in normalized_order else "" var copied_coverage: Dictionary = Dictionary(formation.get("coverage", {})).duplicate(true) var copied_first_threat: Dictionary = Dictionary(formation.get("first_threat", {})).duplicate(true) var copied_receipts: Array = _copy_array(raw_receipts) var copied_snapshot: Dictionary = Dictionary(formation.get("accepted_party_snapshot", {})).duplicate(true) var front_recruit: Dictionary = Dictionary(members[String(normalized_order[0])]).duplicate(true) var state := "ready" if status == "ready" else "ordered" var order_hash := _hash(normalized_order) var contract_data := { "contract_id": String(contract.get("contract_id", "")), "run_id": String(contract.get("run_id", "")), "difficulty": String(contract.get("difficulty", "standard")), "coin": int(contract.get("coin", 0)), "line_capacity": int(contract.get("line_capacity", capacity)), } var company_data := { "company_id": String(company.get("company_id", "")), "owned_count": members.size(), "line_capacity": capacity, "recruits": _copy_array(raw_recruits), } return { "ok": true, "page_id": "readiness_review", "locale": String(locale), "company": company_data, "contract": contract_data, "formation": { "status": status, "state": state, "orientation": String(formation.get("orientation", "rear_left_front_right")), "front_position": int(formation.get("front_position", 0)), "line_capacity": capacity, "order_revision": int(formation.get("order_revision", 0)), "first_threat": copied_first_threat, "relations": copied_relations, "coverage": copied_coverage, "risk_option_ids": _risk_option_ids(formation.get("risk_options", []), copied_snapshot), }, "order": { "front_to_rear_ids": normalized_order.duplicate(true), "order_hash": order_hash, "ordered_recruits": ordered_recruits, "front_recruit": front_recruit, "reviewed_recruit_id": selected, "review_reason": "selected" if not selected.is_empty() else "no_selection", }, "warnings": { "rows": _copy_array(warnings), "count": warnings.size(), }, "receipt": { "present": not copied_receipts.is_empty(), "latest": Dictionary(copied_receipts.back()).duplicate(true) if not copied_receipts.is_empty() and copied_receipts.back() is Dictionary else {}, "all": copied_receipts, }, "accepted_party_snapshot": copied_snapshot, "commands": { "settings_enabled": true, "member_review_enabled": true, "warning_review_enabled": true, "revise_enabled": true, "back_enabled": true, "accept_enabled": state == "ordered", "risk_enabled": state == "ready", }, } func _validate_saved_order(values: Array, members: Dictionary, capacity: int) -> Dictionary: if values.size() != capacity: return {"ok": false, "code": "READINESS_COUNT_INVALID"} var ids: Array = [] for value in values: var recruit_id := String(value) if not members.has(recruit_id): return {"ok": false, "code": "READINESS_RECRUIT_UNKNOWN"} if recruit_id in ids: return {"ok": false, "code": "READINESS_RECRUIT_DUPLICATE"} ids.append(recruit_id) return {"ok": true, "code": "READINESS_ORDER_VALID", "ids": ids} func _members_by_id(values) -> Dictionary: var result := {} for value in values: if value is Dictionary: var copied: Dictionary = Dictionary(value).duplicate(true) var recruit_id := String(copied.get("recruit_id", "")) if recruit_id.is_empty(): continue result[recruit_id] = copied return result func _relations_by_id(values: Array) -> Dictionary: var result := {} for value in values: if value is Dictionary: result[String(value.get("recruit_id", ""))] = Dictionary(value).duplicate(true) return result func _risk_option_ids(options, accepted_snapshot: Dictionary) -> Array: var result: Array = [] if options is Array: for option in options: if option is Dictionary: result.append(String(option.get("risk_option_id", ""))) if result.is_empty() and accepted_snapshot.has("risk_option_ids"): result = _copy_array(accepted_snapshot.get("risk_option_ids", [])) return result func _copy_array(values) -> Array: var result: Array = [] if not values is Array: return result for value in values: result.append(value.duplicate(true) if value is Dictionary or value is Array else value) return result func _hash(value) -> String: return JSON.stringify(_canonical(value)).sha256_text() func _canonical(value): if value is float and is_equal_approx(value, round(value)): return int(round(value)) if value is Dictionary: var result := {} var keys: Array = value.keys() keys.sort_custom(func(left, right): return String(left) < String(right)) for key in keys: result[key] = _canonical(value[key]) return result if value is Array: var result: Array = [] for item in value: result.append(_canonical(item)) return result return value