Files
calminer/tests/integration/test_capex_calculations.py
zwitschi d9fd82b2e3 feat: Implement initial capex calculation feature
- Added CapexComponentInput, CapexParameters, CapexCalculationRequest, CapexCalculationResult, and related schemas for capex calculations.
- Introduced calculate_initial_capex function to aggregate capex components and compute totals and timelines.
- Created ProjectCapexRepository and ScenarioCapexRepository for managing capex snapshots in the database.
- Developed capex.html template for capturing and displaying initial capex data.
- Registered common Jinja2 filters for formatting currency and percentages.
- Implemented unit and integration tests for capex calculation functionality.
- Updated unit of work to include new repositories for capex management.
2025-11-12 23:51:52 +01:00

123 lines
4.2 KiB
Python

from __future__ import annotations
import pytest
from fastapi.testclient import TestClient
def _create_project(client: TestClient, name: str) -> int:
response = client.post(
"/projects",
json={
"name": name,
"location": "Nevada",
"operation_type": "open_pit",
"description": "Project for capex testing",
},
)
assert response.status_code == 201
return response.json()["id"]
def _create_scenario(client: TestClient, project_id: int, name: str) -> int:
response = client.post(
f"/projects/{project_id}/scenarios",
json={
"name": name,
"description": "Capex scenario",
"status": "draft",
"currency": "usd",
"primary_resource": "diesel",
},
)
assert response.status_code == 201
return response.json()["id"]
def test_capex_calculation_html_flow(client: TestClient) -> None:
project_id = _create_project(client, "Capex HTML Project")
scenario_id = _create_scenario(client, project_id, "Capex HTML Scenario")
form_page = client.get(
f"/calculations/capex?project_id={project_id}&scenario_id={scenario_id}"
)
assert form_page.status_code == 200
assert "Initial Capex Planner" in form_page.text
response = client.post(
f"/calculations/capex?project_id={project_id}&scenario_id={scenario_id}",
data={
"components[0][name]": "Crusher",
"components[0][category]": "equipment",
"components[0][amount]": "1200000",
"components[0][currency]": "USD",
"components[0][spend_year]": "0",
"components[1][name]": "Conveyor",
"components[1][category]": "equipment",
"components[1][amount]": "800000",
"components[1][currency]": "USD",
"components[1][spend_year]": "1",
"parameters[currency_code]": "USD",
"parameters[contingency_pct]": "5",
"parameters[discount_rate_pct]": "8",
"parameters[evaluation_horizon_years]": "5",
"options[persist]": "1",
},
)
assert response.status_code == 200
assert "Initial capex calculation completed successfully." in response.text
assert "Capex Summary" in response.text
assert "$1,200,000.00" in response.text or "1,200,000" in response.text
assert "USD" in response.text
def test_capex_calculation_json_flow(client: TestClient) -> None:
project_id = _create_project(client, "Capex JSON Project")
scenario_id = _create_scenario(client, project_id, "Capex JSON Scenario")
payload = {
"components": [
{
"name": "Camp",
"category": "infrastructure",
"amount": 600000,
"currency": "USD",
"spend_year": 0,
},
{
"name": "Power",
"category": "infrastructure",
"amount": 400000,
"currency": "USD",
"spend_year": 1,
},
],
"parameters": {
"currency_code": "USD",
"contingency_pct": 12.5,
"discount_rate_pct": 6.5,
"evaluation_horizon_years": 4,
},
"options": {"persist": True},
}
response = client.post(
f"/calculations/capex?project_id={project_id}&scenario_id={scenario_id}",
json=payload,
)
assert response.status_code == 200
data = response.json()
assert data["currency"] == "USD"
assert data["totals"]["overall"] == 1_000_000
assert data["totals"]["contingency_pct"] == pytest.approx(12.5)
assert data["totals"]["contingency_amount"] == pytest.approx(125000)
assert data["totals"]["with_contingency"] == pytest.approx(1_125_000)
by_category = {row["category"]: row for row in data["totals"]["by_category"]}
assert by_category["infrastructure"]["amount"] == pytest.approx(1_000_000)
assert by_category["infrastructure"]["share"] == pytest.approx(100)
assert len(data["timeline"]) == 2
assert data["timeline"][0]["year"] == 0
assert data["timeline"][0]["spend"] == pytest.approx(600_000)
assert data["timeline"][1]["cumulative"] == pytest.approx(1_000_000)