"""Linear scenario tests for the earnings transfer calculation engine. Stubs OWS and Snowflake by constructing TransferRecord objects directly from the fixture data below. Exercises evaluate() and stops before the writer produces any XLSX output. """ from __future__ import annotations import pytest from src.calculator import evaluate from src.enums import RateType, TransferType from src.types import ContractRef, TransferRecord earnings_transfers = [ # Valid percent transfer. Should transfer $500 { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'percent', 'transfer_amount': 0.5, 'input': 'closing_balance', 'negative': False, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': 1000.0, }, # Invalid percent transfer. Nothing transferred due to 0 balance { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'percent', 'transfer_amount': 0.5, 'input': 'closing_balance', 'negative': False, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': 0, }, # Invalid percent transfer. Nothing transferred due to negative balance { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'percent', 'transfer_amount': 0.5, 'input': 'closing_balance', 'negative': False, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': -100.0, }, # Valid flat rate transfer, no negative. Should transfer $500 { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'flat_rate', 'transfer_amount': 500, 'input': 'closing_balance', 'negative': False, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': 1000.0, }, # Valid flat rate transfer, no negative, zero balance. Should transfer $500 (balance >= 0, only already-negative is blocked). { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'flat_rate', 'transfer_amount': 500, 'input': 'closing_balance', 'negative': False, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': 0.0, }, # Invalid flat rate transfer, no negative, already-negative balance. Should transfer $0. { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'flat_rate', 'transfer_amount': 500, 'input': 'closing_balance', 'negative': False, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': -100.0, }, # Valid flat rate transfer, yes negative, 0 balance. Should transfer 500 { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'flat_rate', 'transfer_amount': 500, 'input': 'closing_balance', 'negative': True, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': 0.0, }, # Valid flat rate transfer, yes negative, negative balance. Should transfer 500 { 'earnings_transfer_id': 1, 'from_contract_id': 100, 'to_contract_id': 300, 'transfer_type': 'transfer', 'rate_type': 'flat_rate', 'transfer_amount': 500, 'input': 'closing_balance', 'negative': True, # use this value as the return value for the stub that fetches contract data from Snowflake 'closing_balance': -10.0, }, ] # Expected calculated_amount for each scenario above (index-aligned). _expected = [500.0, 0.0, 0.0, 500.0, 500.0, 0.0, 500.0, 500.0] _ids = [ 'percent_positive_balance', 'percent_zero_balance', 'percent_negative_balance_blocked', 'flat_rate_balance_covers_amount', 'flat_rate_zero_balance_allowed', 'flat_rate_already_negative_blocked', 'flat_rate_negative_allowed_zero_balance', 'flat_rate_negative_allowed_negative_balance', ] def _build_record(scenario: dict) -> TransferRecord: """Construct a TransferRecord from a raw fixture dict. Simulates what OWS + Snowflake would supply at runtime. """ return TransferRecord( earnings_transfer_id=scenario['earnings_transfer_id'], transfer_type=TransferType(scenario['transfer_type'].capitalize()), rate_type=RateType(scenario['rate_type']), transfer_amount=float(scenario['transfer_amount']), input=scenario['input'], negative=scenario['negative'], from_contract=ContractRef(contract_id=scenario['from_contract_id']), to_contract=ContractRef(contract_id=scenario['to_contract_id']), closing_balance=float(scenario['closing_balance']) if scenario.get('closing_balance') is not None else None, ) @pytest.mark.parametrize( 'scenario,expected', [(earnings_transfers[i], _expected[i]) for i in range(len(earnings_transfers))], ids=_ids, ) def test_linear_scenario(scenario: dict, expected: float) -> None: """Verify calculate_amount matches expected output for each linear scenario.""" record = _build_record(scenario) results = evaluate([record]) assert len(results) == 1 assert results[0].calculated_amount == expected