import asyncio from importlib import import_module from unittest.mock import MagicMock import pytest from app.modules.sag.backend import commands from app.core.config import settings router = import_module('app.timetracking.backend.router') @pytest.mark.parametrize('choice', ['invoice', 'card_7', 'fpa_9']) def test_automatic_capture_ignores_manual_billing_and_saves_draft(monkeypatch, choice): monkeypatch.setattr(router, '_resolve_case_customer_id', lambda *args: 77) captured = {} def choose(case, value): assert value == 'draft' return {'method': 'draft', 'status': 'kladde', 'card_id': None, 'agreement_id': None} monkeypatch.setattr(router, '_case_billing_choice', choose) def insert(sql, params): captured['params'] = params return [{'id': 3}] monkeypatch.setattr(router, 'execute_query', insert) asyncio.run(router.create_manual_time_v1({'sag_id': 186, 'faktisk_tid_min': 15, 'billing_mode': 'automatic', 'settlement_choice': choice, 'billing_method': 'invoice'}, {'id': 12, 'username': 'test'})) assert captured['params'][9] == 'draft' assert captured['params'][16] == 'kladde' assert captured['params'][-4:-2] == (None, None) def test_explicit_time_tab_choice_retains_existing_validation(monkeypatch): choose = MagicMock(return_value={'method': 'invoice'}) monkeypatch.setattr(router, '_case_billing_choice', choose) assert router._case_registration_billing(186, {'billing_mode': 'manual', 'settlement_choice': 'invoice'}) == {'method': 'invoice'} choose.assert_called_once_with(186, 'invoice') def test_automatic_live_timer_is_draft_even_when_invoice_is_submitted(monkeypatch): monkeypatch.setattr(router, '_resolve_case_customer_id', lambda *args: 77) monkeypatch.setattr(router, '_resolve_target_user_id', lambda *args: 12) monkeypatch.setattr(router, 'execute_query_single', lambda *args: None) monkeypatch.setattr(router, '_case_billing_choice', lambda case, choice: { 'method': choice, 'status': 'kladde', 'card_id': None, 'agreement_id': None}) def insert(sql, params): assert params[-4:-1] == ('draft', None, None) return [{'id': 3}] monkeypatch.setattr(router, 'execute_query', insert) asyncio.run(router.start_live_timer_v1({'sag_id': 186, 'billing_mode': 'automatic', 'settlement_choice': 'invoice'}, {'id': 12, 'username': 'test'})) def test_v5_command_cannot_select_card_in_automatic_mode(monkeypatch): choose = MagicMock(return_value={'method': 'draft', 'status': 'kladde', 'card_id': None, 'agreement_id': None}) monkeypatch.setattr(router, '_case_billing_choice', choose) result = commands.normalize(MagicMock(), {'id': 186}, {'billing_mode': 'automatic', 'commands': [{'type': 'time', 'minutes': 15, 'description': 'Test', 'settlement_choice': 'card_7'}]}, {'id': 12}) choose.assert_called_once_with(186, 'draft') assert result[0]['settlement_choice'] == 'draft' def test_display_uses_workflow_choice_without_mutating_stored_draft(monkeypatch): monkeypatch.setattr(settings, 'WORKFLOWS_ENABLED', True) from app.workflows import integration monkeypatch.setattr(integration, 'active_for_customer', lambda _: True) monkeypatch.setattr(router, 'execute_query_single', lambda sql, params=None: {'customer_id': 24} if 'sag_sager' in sql else {'name': 'bmc_billing_decisions'}) monkeypatch.setattr(router, 'execute_query', lambda *args: [{'time_id': 3, 'revision': 2, 'status': 'decided', 'method': 'subscription'}]) result = router._case_time_billing_display([{'id': 3, 'workflow_revision': 2, 'billing_method': 'draft'}], 186, {'permissions': ['workflows.override', 'workflows.decisions.view']})[0] assert result['billing_method'] == 'draft' assert result['selected_billing_method'] == 'subscription' assert result['workflow_can_override'] is True def test_stale_workflow_choice_displays_draft_until_recalculated(monkeypatch): monkeypatch.setattr(settings, 'WORKFLOWS_ENABLED', True) from app.workflows import integration monkeypatch.setattr(integration, 'active_for_customer', lambda _: True) monkeypatch.setattr(router, 'execute_query_single', lambda sql, params=None: {'customer_id': 24} if 'sag_sager' in sql else {'name': 'bmc_billing_decisions'}) monkeypatch.setattr(router, 'execute_query', lambda *args: [{'time_id': 3, 'revision': 1, 'status': 'decided', 'method': 'prepaid'}]) result = router._case_time_billing_display([{'id': 3, 'workflow_revision': 2, 'billing_method': 'draft'}], 186, {})[0] assert result['selected_billing_method'] == 'draft' and result['workflow_stale'] is True