Files
calminer/tests/test_scenario_pricing.py
zwitschi 795a9f99f4 feat: Enhance currency handling and validation across scenarios
- Updated form template to prefill currency input with default value and added help text for clarity.
- Modified integration tests to assert more descriptive error messages for invalid currency codes.
- Introduced new tests for currency normalization and validation in various scenarios, including imports and exports.
- Added comprehensive tests for pricing calculations, ensuring defaults are respected and overrides function correctly.
- Implemented unit tests for pricing settings repository, ensuring CRUD operations and default settings are handled properly.
- Enhanced scenario pricing evaluation tests to validate currency handling and metadata defaults.
- Added simulation tests to ensure Monte Carlo runs are accurate and handle various distribution scenarios.
2025-11-11 18:29:59 +01:00

121 lines
3.5 KiB
Python

from __future__ import annotations
import pytest
from models import MiningOperationType, Project, Scenario, ScenarioStatus
from services.pricing import PricingInput, PricingMetadata
from services.scenario_evaluation import ScenarioPricingConfig, ScenarioPricingEvaluator
def build_scenario() -> Scenario:
project = Project(name="Test Project",
operation_type=MiningOperationType.OPEN_PIT)
scenario = Scenario(
project=project,
project_id=1,
name="Scenario A",
status=ScenarioStatus.ACTIVE,
currency="USD",
)
scenario.id = 1 # simulate persisted entity
return scenario
def test_scenario_pricing_evaluator_uses_metadata_defaults() -> None:
scenario = build_scenario()
evaluator = ScenarioPricingEvaluator(
ScenarioPricingConfig(
metadata=PricingMetadata(
default_currency="USD", default_payable_pct=95)
)
)
inputs = [
PricingInput(
metal="copper",
ore_tonnage=50_000,
head_grade_pct=1.0,
recovery_pct=90,
payable_pct=None,
reference_price=9_000,
treatment_charge=50_000,
smelting_charge=10_000,
moisture_pct=9,
moisture_threshold_pct=None,
moisture_penalty_per_pct=None,
impurity_ppm={"As": 120},
premiums=10_000,
fx_rate=1.0,
currency_code=None,
)
]
snapshot = evaluator.evaluate(scenario, inputs=inputs)
assert snapshot.scenario_id == scenario.id
assert len(snapshot.results) == 1
result = snapshot.results[0]
assert result.currency == "USD"
assert result.net_revenue > 0
def test_scenario_pricing_evaluator_override_metadata() -> None:
scenario = build_scenario()
evaluator = ScenarioPricingEvaluator(ScenarioPricingConfig())
metadata_override = PricingMetadata(
default_currency="CAD",
default_payable_pct=90,
moisture_threshold_pct=5,
moisture_penalty_per_pct=500,
)
inputs = [
PricingInput(
metal="copper",
ore_tonnage=20_000,
head_grade_pct=1.2,
recovery_pct=88,
payable_pct=None,
reference_price=8_200,
treatment_charge=15_000,
smelting_charge=6_000,
moisture_pct=6,
moisture_threshold_pct=None,
moisture_penalty_per_pct=None,
premiums=5_000,
fx_rate=1.0,
currency_code="cad",
),
PricingInput(
metal="gold",
ore_tonnage=5_000,
head_grade_pct=2.0,
recovery_pct=90,
payable_pct=None,
reference_price=60_000,
treatment_charge=10_000,
smelting_charge=5_000,
moisture_pct=4,
moisture_threshold_pct=None,
moisture_penalty_per_pct=None,
premiums=15_000,
fx_rate=1.0,
currency_code="cad",
),
]
snapshot = evaluator.evaluate(
scenario,
inputs=inputs,
metadata_override=metadata_override,
)
assert len(snapshot.results) == 2
assert all(result.currency ==
scenario.currency for result in snapshot.results)
copper_result = snapshot.results[0]
expected_payable = 20_000 * 0.012 * 0.88 * 0.90
assert copper_result.payable_metal_tonnes == pytest.approx(
expected_payable)
assert sum(result.net_revenue for result in snapshot.results) > 0