feat: operational resource procurement facility
Implement RESOURCE-WP-0005: entity register, V0.1 terms parameters, entity association on inventory and planning records, transfer-price and credit-state arithmetic, monthly settlement, and entity views on the portfolio report. Live close emits nothing until delivered cost is known. Handoffs are FIN-WP-0006 and RAILIANCE-WP-0017.
This commit is contained in:
parent
325a505980
commit
f8d1c542d5
37 changed files with 1316 additions and 28 deletions
|
|
@ -13,6 +13,7 @@ import sys
|
|||
from datetime import date
|
||||
from pathlib import Path
|
||||
|
||||
from entities import REQUIRED_ENTITY_IDS, load_register
|
||||
from optimization import evaluate, validate_case
|
||||
from portfolio import validate_record
|
||||
|
||||
|
|
@ -260,6 +261,47 @@ def optimization_section(cases: list[dict]) -> dict:
|
|||
}
|
||||
|
||||
|
||||
def entities_section(resources: list[dict], register: dict[str, dict]) -> dict:
|
||||
by_id = {entity_id: {
|
||||
"financial_entity_id": entity_id,
|
||||
"display_name": register[entity_id]["display_name"],
|
||||
"role": register[entity_id]["role"],
|
||||
"dedicated_resources": [],
|
||||
"shared_shares": [],
|
||||
"priced_resources": 0,
|
||||
"consumption_mode": None,
|
||||
"consumption_mode_note": "no settlement close yet; mode is unknown, not open",
|
||||
} for entity_id in REQUIRED_ENTITY_IDS}
|
||||
unattributed = []
|
||||
for resource in resources:
|
||||
entity_id = resource.get("financial_entity_id")
|
||||
entry = {
|
||||
"resource_id": resource["id"],
|
||||
"price_evidence": bool(resource["cost"]["price_evidence"]),
|
||||
}
|
||||
if entity_id:
|
||||
by_id[entity_id]["dedicated_resources"].append(resource["id"])
|
||||
if resource["cost"]["price_evidence"]:
|
||||
by_id[entity_id]["priced_resources"] += 1
|
||||
else:
|
||||
unattributed.append({
|
||||
"resource_id": resource["id"],
|
||||
"entity_gap": resource.get("entity_gap"),
|
||||
"allocation_mode": resource["ownership"]["allocation"]["mode"],
|
||||
})
|
||||
for share in resource["ownership"]["allocation"].get("entity_shares") or []:
|
||||
share_id = share["financial_entity_id"]
|
||||
by_id[share_id]["shared_shares"].append({
|
||||
"resource_id": resource["id"],
|
||||
"note": share["note"],
|
||||
})
|
||||
return {
|
||||
"entities": [by_id[entity_id] for entity_id in REQUIRED_ENTITY_IDS],
|
||||
"unattributed_resources": unattributed,
|
||||
"known_monthly_spend_eur": None,
|
||||
}
|
||||
|
||||
|
||||
def next_actions(report: dict) -> list[str]:
|
||||
"""The smallest set of evidence that would unblock the most decisions."""
|
||||
actions = []
|
||||
|
|
@ -281,6 +323,7 @@ def next_actions(report: dict) -> list[str]:
|
|||
def build(root: Path, today: date | None = None) -> dict:
|
||||
today = today or date.today()
|
||||
data = load_portfolio(root)
|
||||
_, register = load_register(root)
|
||||
resources = data["resources"]
|
||||
utilization = utilization_section(resources)
|
||||
cost = cost_section(resources)
|
||||
|
|
@ -292,6 +335,7 @@ def build(root: Path, today: date | None = None) -> dict:
|
|||
"lifecycle": lifecycle_section(resources),
|
||||
"utilization": utilization,
|
||||
"cost": cost,
|
||||
"entities": entities_section(resources, register),
|
||||
"renewals": renewals_section(resources, today),
|
||||
"optimization": optimization_section(data["cases"]),
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue