""" Unit tests for bot response formatters. Updated to match the actual formatter implementations in app/bot/formatters.py which use plain text (no emojis) and different data structures. """ import pytest from app.bot.formatters import ( format_dashboard_response, format_invoices_response, format_treasury_casa_response, format_treasury_banca_response ) # Alias for backward compatibility with tests def format_treasury_response(data, company_name=None): """Combined treasury formatter for test compatibility.""" return format_treasury_casa_response(data, company_name) class TestDashboardFormatter: """Tests for dashboard response formatter.""" def test_format_dashboard_basic(self): """Test basic dashboard formatting with new data structure.""" data = { 'treasury_totals_by_currency': {'RON': 150000.50}, 'clienti_sold_total': 100000.00, 'clienti_sold_in_termen': 80000.00, 'clienti_sold_restant': 20000.00, 'furnizori_sold_total': 50000.00, 'furnizori_sold_in_termen': 40000.00, 'furnizori_sold_restant': 10000.00, 'furnizori_avansuri': 0 } company_name = "ACME SRL" result = format_dashboard_response(data, company_name) # Check treasury balance (rounded to integer - round() uses banker's rounding) assert "**Sold Trezorerie:**" in result assert "150,000 RON" in result or "150,001 RON" in result # Rounding depends on implementation # Check clients balance assert "**Sold Clienți:**" in result assert "100,000 RON" in result # Check suppliers balance assert "**Sold Furnizori:**" in result def test_format_dashboard_zero_values(self): """Test dashboard with zero values.""" data = { 'treasury_totals_by_currency': {'RON': 0}, 'clienti_sold_total': 0, 'clienti_sold_in_termen': 0, 'clienti_sold_restant': 0, 'furnizori_sold_total': 0, 'furnizori_sold_in_termen': 0, 'furnizori_sold_restant': 0, 'furnizori_avansuri': 0 } company_name = "TEST SRL" result = format_dashboard_response(data, company_name) # Should show 0 values assert "0 RON" in result assert "**Sold Trezorerie:**" in result def test_format_dashboard_large_numbers(self): """Test dashboard with large numbers (millions).""" data = { 'treasury_totals_by_currency': {'RON': 1234567.89}, 'clienti_sold_total': 9876543.21, 'clienti_sold_in_termen': 5000000.00, 'clienti_sold_restant': 4876543.21, 'furnizori_sold_total': 5432100.00, 'furnizori_sold_in_termen': 3000000.00, 'furnizori_sold_restant': 2432100.00, 'furnizori_avansuri': 0 } company_name = "BIG CORP SA" result = format_dashboard_response(data, company_name) # Check proper number formatting with thousands separator (rounded integers) assert "1,234,568 RON" in result # Rounded from 1234567.89 assert "9,876,543 RON" in result def test_format_dashboard_missing_fields(self): """Test dashboard with missing fields (defaults to 0).""" data = {} # Empty data company_name = "EMPTY SRL" result = format_dashboard_response(data, company_name) # Should use defaults (0) assert "0 RON" in result assert "**Sold Trezorerie:**" in result def test_format_dashboard_with_tva(self): """Test dashboard with TVA values shown.""" data = { 'treasury_totals_by_currency': {'RON': 50000}, 'clienti_sold_total': 10000, 'clienti_sold_in_termen': 8000, 'clienti_sold_restant': 2000, 'furnizori_sold_total': 5000, 'furnizori_sold_in_termen': 4000, 'furnizori_sold_restant': 1000, 'furnizori_avansuri': 0, 'tva_plata_precedent': 1500, 'tva_recuperat_precedent': 0, 'tva_plata_curent': 2500, 'tva_recuperat_curent': 0 } company_name = "TVA SRL" result = format_dashboard_response(data, company_name) # Should show TVA section assert "**Solduri TVA:**" in result assert "TVA de plată precedent:" in result or "TVA de plată curent:" in result class TestInvoicesFormatter: """Tests for invoices response formatter.""" def test_format_invoices_basic(self): """Test basic invoice list formatting.""" invoices = [ { 'seria': 'FAC', 'numar': '001', 'client': 'Client ABC', 'suma_totala': 5000.00, 'status': 'platit' }, { 'seria': 'FAC', 'numar': '002', 'client': 'Client XYZ', 'suma_totala': 3500.50, 'status': 'neplatit' } ] company_name = "TEST SRL" result = format_invoices_response(invoices, company_name) # Check header with count (plain text, no emoji) assert "**Facturi**" in result assert "(2 total)" in result # Check invoice appears (table format) assert "FAC001" in result assert "Client ABC" in result # Check status markers (plain text) assert "PLATIT" in result or "NEPLATIT" in result def test_format_invoices_empty_list(self): """Test with empty invoice list.""" invoices = [] company_name = "EMPTY SRL" result = format_invoices_response(invoices, company_name) # Message for no invoices found assert "Nu s-au gasit facturi" in result def test_format_invoices_limit(self): """Test invoice list with limit.""" # Create 15 invoices invoices = [ { 'seria': 'FAC', 'numar': f'{i:03d}', 'client': f'Client {i}', 'suma_totala': 1000 * i, 'status': 'platit' } for i in range(1, 16) ] company_name = "MANY SRL" result = format_invoices_response(invoices, company_name, limit=10) # Should show only 10 invoices assert "FAC001" in result assert "FAC010" in result # 11th should not appear in the main list # (it may show count like "+5 facturi") # Should show message about remaining assert "+5 facturi" in result def test_format_invoices_status_text(self): """Test status text markers.""" invoices_platit = [ {'seria': 'A', 'numar': '1', 'client': 'X', 'suma_totala': 100, 'status': 'platit'} ] invoices_neplatit = [ {'seria': 'B', 'numar': '2', 'client': 'Y', 'suma_totala': 200, 'status': 'neplatit'} ] result_platit = format_invoices_response(invoices_platit, "TEST") result_neplatit = format_invoices_response(invoices_neplatit, "TEST") # Should use plain text status markers assert "PLATIT" in result_platit assert "NEPLATIT" in result_neplatit def test_format_invoices_missing_fields(self): """Test invoices with missing fields.""" invoices = [ { 'seria': '', 'numar': '', # 'client' missing # 'suma_totala' missing # 'status' missing } ] company_name = "TEST SRL" result = format_invoices_response(invoices, company_name) # Should handle missing fields gracefully assert "N/A" in result class TestTreasuryFormatter: """Tests for treasury response formatter.""" def test_format_treasury_casa_basic(self): """Test basic treasury CASA formatting.""" data = { 'total': 50000.00, 'accounts': [ {'name': 'Casa principala', 'balance': 30000.00}, {'name': 'Casa secundara', 'balance': 20000.00} ] } company_name = "TREASURY SRL" result = format_treasury_casa_response(data, company_name) # Check total (plain text, no emoji) assert "**Sold Total Cash:**" in result assert "50,000 RON" in result # Check accounts assert "**Conturi de Casa:**" in result assert "Casa principala" in result assert "30,000 RON" in result def test_format_treasury_banca_basic(self): """Test basic treasury BANCA formatting.""" data = { 'total': 175000.50, 'accounts': [ {'name': 'BCR', 'balance': 100000.00}, {'name': 'BRD', 'balance': 75000.50} ] } company_name = "BANK SRL" result = format_treasury_banca_response(data, company_name) # Check total (plain text, no emoji, rounded to integer) assert "**Sold Total Banca:**" in result assert "175,000 RON" in result or "175,001 RON" in result # Rounding depends on implementation # Check accounts assert "**Conturi Bancare:**" in result assert "BCR" in result assert "BRD" in result def test_format_treasury_no_accounts(self): """Test treasury without accounts.""" data = { 'total': 0, 'accounts': [] } company_name = "CASH ONLY SRL" result = format_treasury_casa_response(data, company_name) # Should show message about no accounts assert "Nu exista conturi de casa configurate" in result def test_format_treasury_many_accounts(self): """Test treasury with many accounts.""" data = { 'total': 55000, 'accounts': [ {'name': f'Cont {i}', 'balance': i * 1000} for i in range(1, 11) # 10 accounts ] } company_name = "MANY ACCOUNTS SRL" result = format_treasury_banca_response(data, company_name) # Should show all accounts (no limit in current implementation) assert "Cont 1:" in result assert "Cont 10:" in result def test_format_treasury_zero_values(self): """Test treasury with zero values.""" data = { 'total': 0, 'accounts': [ {'name': 'Cont gol', 'balance': 0} ] } company_name = "ZERO SRL" result = format_treasury_casa_response(data, company_name) assert "0 RON" in result def test_format_treasury_large_numbers(self): """Test treasury with large numbers.""" data = { 'total': 9876543.21, 'accounts': [ {'name': 'BIG BANK', 'balance': 9876543.21} ] } company_name = "BIG MONEY SA" result = format_treasury_banca_response(data, company_name) # Check proper number formatting (rounded integers) assert "9,876,543 RON" in result class TestFormatterIntegration: """Integration tests for formatters.""" def test_all_formatters_return_string(self): """Ensure all formatters return valid strings.""" company = "INTEGRATION TEST SRL" # Dashboard dash_result = format_dashboard_response({}, company) assert isinstance(dash_result, str) assert len(dash_result) > 0 # Invoices (non-empty) inv_result = format_invoices_response([ {'seria': 'A', 'numar': '1', 'client': 'X', 'suma_totala': 100, 'status': 'platit'} ], company) assert isinstance(inv_result, str) assert len(inv_result) > 0 # Treasury Casa casa_result = format_treasury_casa_response({'total': 0, 'accounts': []}, company) assert isinstance(casa_result, str) assert len(casa_result) > 0 # Treasury Banca banca_result = format_treasury_banca_response({'total': 0, 'accounts': []}, company) assert isinstance(banca_result, str) assert len(banca_result) > 0 def test_number_formatting_consistency(self): """Test that all formatters use consistent number formatting (integers with thousands separator).""" test_amount = 1234567 # Dashboard dash_data = {'treasury_totals_by_currency': {'RON': test_amount}} dash_result = format_dashboard_response(dash_data, "TEST") assert "1,234,567" in dash_result # Treasury Casa casa_data = {'total': test_amount, 'accounts': []} casa_result = format_treasury_casa_response(casa_data, "TEST") assert "1,234,567" in casa_result # Treasury Banca banca_data = {'total': test_amount, 'accounts': []} banca_result = format_treasury_banca_response(banca_data, "TEST") assert "1,234,567" in banca_result