"""WorksheetPaymentCustom functional tests.""" from datetime import datetime, timedelta import pytest from tests.utils.factories import WorksheetPaymentCustomFactory def test_worksheet_payment_custom_create_success( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create endpoint success.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'withholding_tax_amount': '-10.00', 'vat_amount': '20.00', 'withholding_tax_rate': '5.00', 'vat_rate': '10.00', 'amount_after_withholding_and_vat': '110.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test custom payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['worksheet_payment_custom_id'] == 1 assert res.json['account_id'] == 1 assert res.json['contract_id'] == 1 assert res.json['currency_code'] == 'USD' assert res.json['amount'] == '100.00' assert res.json['withholding_tax_amount'] == '-10.00' assert res.json['vat_amount'] == '20.00' assert res.json['withholding_tax_rate'] == '5.00' assert res.json['vat_rate'] == '10.00' assert res.json['amount_after_withholding_and_vat'] == '110.00' assert res.json['activity_statement_period_id'] == 1 assert res.json['statement_period_id'] == 1 assert res.json['payment_name'] == 'test custom payment' def test_worksheet_payment_custom_create_without_optional_fields( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create without optional fields.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'amount_after_withholding_and_vat': '100.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test custom payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['amount'] == '100.00' assert res.json['amount_after_withholding_and_vat'] == '100.00' def test_worksheet_payment_custom_create_with_positive_wht( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create with positive WHT (correction case).""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'withholding_tax_amount': '10.00', # Positive for corrections 'vat_amount': '20.00', 'withholding_tax_rate': '10.00', 'vat_rate': '20.00', 'amount_after_withholding_and_vat': '130.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test correction payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['withholding_tax_amount'] == '10.00' assert res.json['amount_after_withholding_and_vat'] == '130.00' def test_worksheet_payment_custom_create_with_negative_vat( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create with negative VAT (correction case).""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'withholding_tax_amount': '-10.00', 'vat_amount': '-20.00', # Negative for corrections 'withholding_tax_rate': '10.00', 'vat_rate': '20.00', 'amount_after_withholding_and_vat': '70.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test correction payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['vat_amount'] == '-20.00' assert res.json['amount_after_withholding_and_vat'] == '70.00' def test_worksheet_payment_custom_create_failure_negative_amount( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create failure with negative amount.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '-100.00', # Must be positive 'withholding_tax_amount': '-10.00', 'vat_amount': '20.00', 'withholding_tax_rate': '10.00', 'vat_rate': '20.00', 'amount_after_withholding_and_vat': '110.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test custom payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 400 assert 'message' in res.json assert 'json' in res.json['message'] assert 'amount' in res.json['message']['json'] def test_worksheet_payment_custom_create_failure_zero_post_tax_amount( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create failure with zero post-tax amount.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'withholding_tax_amount': '-10.00', 'vat_amount': '20.00', 'withholding_tax_rate': '10.00', 'vat_rate': '20.00', 'amount_after_withholding_and_vat': '0.00', # Must be > 0 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test custom payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 400 assert 'message' in res.json assert 'json' in res.json['message'] assert 'amount_after_withholding_and_vat' in res.json['message']['json'] def test_worksheet_payment_custom_create_failure_negative_post_tax_amount( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create failure with negative post-tax amount.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'withholding_tax_amount': '-10.00', 'vat_amount': '20.00', 'withholding_tax_rate': '10.00', 'vat_rate': '20.00', 'amount_after_withholding_and_vat': '-110.00', # Must be > 0 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test custom payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 400 assert 'message' in res.json assert 'json' in res.json['message'] assert 'amount_after_withholding_and_vat' in res.json['message']['json'] @pytest.mark.parametrize('value', [None, '0']) def test_worksheet_payment_custom_create_failure_missed_rates( fixture_client, mock_accounts, mock_contracts, mock_statement_periods, value ): """Test WorksheetPaymentCustom create failure with negative post-tax amount.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'withholding_tax_amount': '-10.00', 'vat_amount': '20.00', 'withholding_tax_rate': value, 'vat_rate': value, 'amount_after_withholding_and_vat': '110.00', # Must be > 0 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test custom payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 400 assert 'message' in res.json assert 'json' in res.json['message'] assert 'withholding_tax_rate' in res.json['message']['json'] assert 'vat_rate' in res.json['message']['json'] def test_worksheet_payment_custom_create_failure_missing_required_fields( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create failure with missing required fields.""" test_data = { 'account_id': 1, # Missing other required fields including amount_after_withholding_and_vat } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 400 def test_worksheet_payment_custom_create_failure_empty_strings( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create failure with empty string fields.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': '', # Empty string not allowed 'amount': '100.00', 'amount_after_withholding_and_vat': '100.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': '', # Empty string not allowed } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 400 def test_worksheet_payment_custom_create_failure_negative_ids( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test WorksheetPaymentCustom create failure with negative IDs.""" test_data = { 'account_id': -1, # Must be non-negative 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'amount_after_withholding_and_vat': '100.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test custom payment', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 400 def test_worksheet_payment_custom_create_multiple_records( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test creating multiple WorksheetPaymentCustom records.""" test_data_1 = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'withholding_tax_amount': '-10.00', 'vat_amount': '20.00', 'withholding_tax_rate': '10.00', 'vat_rate': '20.00', 'amount_after_withholding_and_vat': '110.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test payment 1', } test_data_2 = { 'account_id': 2, 'contract_id': 2, 'currency_code': 'GBP', 'amount': '200.00', 'withholding_tax_amount': '-20.00', 'vat_amount': '40.00', 'withholding_tax_rate': '20.00', 'vat_rate': '40.00', 'amount_after_withholding_and_vat': '220.00', 'activity_statement_period_id': 2, 'statement_period_id': 2, 'payment_name': 'test payment 2', } res1 = fixture_client.post('/payment/custom', json=test_data_1) assert res1.status_code == 201 assert res1.json['worksheet_payment_custom_id'] == 1 res2 = fixture_client.post('/payment/custom', json=test_data_2) assert res2.status_code == 201 assert res2.json['worksheet_payment_custom_id'] == 2 assert res2.json['currency_code'] == 'GBP' assert res2.json['amount'] == '200.00' def test_worksheet_payment_custom_create_with_different_currencies( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test creating WorksheetPaymentCustom with various currencies.""" currencies = ['USD', 'GBP', 'EUR', 'JPY', 'CAD'] for idx, currency in enumerate(currencies, start=1): test_data = { 'account_id': idx, 'contract_id': idx, 'currency_code': currency, 'amount': f'{idx * 100}.00', 'withholding_tax_amount': f'-{idx * 10}.00', 'vat_amount': f'{idx * 20}.00', 'withholding_tax_rate': f'{idx * 10}.00', 'vat_rate': f'{idx * 20}.00', 'amount_after_withholding_and_vat': f'{idx * 110}.00', 'activity_statement_period_id': idx, 'statement_period_id': idx, 'payment_name': f'test payment {currency}', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['currency_code'] == currency assert res.json['worksheet_payment_custom_id'] == idx def test_worksheet_payment_custom_create_with_large_amounts( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test creating WorksheetPaymentCustom with large decimal amounts.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '999999999999999999.99', 'withholding_tax_amount': '-99999999999999999.99', 'vat_amount': '99999999999999999.99', 'withholding_tax_rate': '10.99', 'vat_rate': '20.99', 'amount_after_withholding_and_vat': '999999999999999999.99', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test large amounts', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['amount'] == '999999999999999999.99' def test_worksheet_payment_custom_create_with_small_amounts( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test creating WorksheetPaymentCustom with small decimal amounts.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '0.01', 'withholding_tax_amount': '-0.01', 'vat_amount': '0.01', 'withholding_tax_rate': '0.01', 'vat_rate': '0.01', 'amount_after_withholding_and_vat': '0.01', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test small amounts', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['amount'] == '0.01' assert res.json['amount_after_withholding_and_vat'] == '0.01' def test_worksheet_payment_custom_create_with_zero_amount( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test creating WorksheetPaymentCustom with zero amount (edge case).""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '0.00', # Edge case: zero is allowed 'withholding_tax_amount': '0.00', 'vat_amount': '0.01', 'withholding_tax_rate': '0.00', 'vat_rate': '0.01', 'amount_after_withholding_and_vat': '0.01', # Must be > 0 and equal to 0.00 + 0.00 + 0.01 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'test zero amount', } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert res.json['amount'] == '0.00' def test_worksheet_payment_custom_create_with_long_payment_name( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test creating WorksheetPaymentCustom with maximum length payment name.""" test_data = { 'account_id': 1, 'contract_id': 1, 'currency_code': 'USD', 'amount': '100.00', 'amount_after_withholding_and_vat': '100.00', 'activity_statement_period_id': 1, 'statement_period_id': 1, 'payment_name': 'a' * 180, # Max length is 180 } res = fixture_client.post('/payment/custom', json=test_data) assert res.status_code == 201 assert len(res.json['payment_name']) == 180 def test_worksheet_payment_custom_bulk_get_all_success( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test getting all WorksheetPaymentCustom records via bulk endpoint.""" # Create test records WorksheetPaymentCustomFactory.create( created_at=datetime.now() - timedelta(days=2), payment_name='payment 1', ) WorksheetPaymentCustomFactory.create( created_at=datetime.now() - timedelta(days=1), payment_name='payment 2', ) WorksheetPaymentCustomFactory.create( created_at=datetime.now(), payment_name='payment 3', ) res = fixture_client.post('/payments/custom/bulk', json={}) assert res.status_code == 200 assert res.json['total_count'] == 3 assert len(res.json['items']) == 3 # Results should be ordered by created_at desc (newest first) assert res.json['items'][0]['payment_name'] == 'payment 3' assert res.json['items'][1]['payment_name'] == 'payment 2' assert res.json['items'][2]['payment_name'] == 'payment 1' def test_worksheet_payment_custom_bulk_get_with_pagination( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint with pagination parameters.""" # Create 5 test records for i in range(5): WorksheetPaymentCustomFactory.create( created_at=datetime.now() - timedelta(days=i), payment_name=f'payment {i}', ) # Test first page res = fixture_client.post('/payments/custom/bulk?limit=2&offset=0', json={}) assert res.status_code == 200 assert res.json['total_count'] == 5 assert len(res.json['items']) == 2 assert res.json['items'][0]['payment_name'] == 'payment 0' assert res.json['items'][1]['payment_name'] == 'payment 1' # Test second page res = fixture_client.post('/payments/custom/bulk?limit=2&offset=2', json={}) assert res.status_code == 200 assert res.json['total_count'] == 5 assert len(res.json['items']) == 2 assert res.json['items'][0]['payment_name'] == 'payment 2' assert res.json['items'][1]['payment_name'] == 'payment 3' # Test last page res = fixture_client.post('/payments/custom/bulk?limit=2&offset=4', json={}) assert res.status_code == 200 assert res.json['total_count'] == 5 assert len(res.json['items']) == 1 assert res.json['items'][0]['payment_name'] == 'payment 4' def test_worksheet_payment_custom_bulk_filter_by_ids( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint filtering by worksheet_payment_custom_ids.""" # Create test records record1 = WorksheetPaymentCustomFactory.create(payment_name='payment 1') record2 = WorksheetPaymentCustomFactory.create(payment_name='payment 2') record3 = WorksheetPaymentCustomFactory.create(payment_name='payment 3') # Filter by specific IDs test_data = { 'filters': { 'worksheet_payment_custom_ids': [ record1.worksheet_payment_custom_id, record3.worksheet_payment_custom_id, ] } } res = fixture_client.post('/payments/custom/bulk', json=test_data) assert res.status_code == 200 assert res.json['total_count'] == 2 assert len(res.json['items']) == 2 payment_names = [item['payment_name'] for item in res.json['items']] assert 'payment 1' in payment_names assert 'payment 3' in payment_names assert 'payment 2' not in payment_names def test_worksheet_payment_custom_bulk_filter_by_single_id( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint filtering by a single ID.""" record1 = WorksheetPaymentCustomFactory.create(payment_name='payment 1') WorksheetPaymentCustomFactory.create(payment_name='payment 2') test_data = { 'filters': { 'worksheet_payment_custom_ids': [record1.worksheet_payment_custom_id] } } res = fixture_client.post('/payments/custom/bulk', json=test_data) assert res.status_code == 200 assert res.json['total_count'] == 1 assert len(res.json['items']) == 1 assert res.json['items'][0]['payment_name'] == 'payment 1' assert ( res.json['items'][0]['worksheet_payment_custom_id'] == record1.worksheet_payment_custom_id ) def test_worksheet_payment_custom_bulk_filter_no_match( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint filtering with non-existent IDs.""" WorksheetPaymentCustomFactory.create(payment_name='payment 1') WorksheetPaymentCustomFactory.create(payment_name='payment 2') # Filter by non-existent IDs test_data = {'filters': {'worksheet_payment_custom_ids': [999, 1000]}} res = fixture_client.post('/payments/custom/bulk', json=test_data) assert res.status_code == 200 assert res.json['total_count'] == 0 assert len(res.json['items']) == 0 def test_worksheet_payment_custom_bulk_empty_filters( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint with empty filters object.""" WorksheetPaymentCustomFactory.create(payment_name='payment 1') WorksheetPaymentCustomFactory.create(payment_name='payment 2') test_data = {'filters': {}} res = fixture_client.post('/payments/custom/bulk', json=test_data) assert res.status_code == 200 assert res.json['total_count'] == 2 assert len(res.json['items']) == 2 def test_worksheet_payment_custom_bulk_excludes_deleted( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint excludes soft-deleted records.""" WorksheetPaymentCustomFactory.create(payment_name='active payment') WorksheetPaymentCustomFactory.create( payment_name='deleted payment', deleted_at=datetime.now() ) res = fixture_client.post('/payments/custom/bulk', json={}) assert res.status_code == 200 assert res.json['total_count'] == 1 assert len(res.json['items']) == 1 assert res.json['items'][0]['payment_name'] == 'active payment' def test_worksheet_payment_custom_bulk_with_different_currencies( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint returns records with different currencies.""" WorksheetPaymentCustomFactory.create( payment_name='usd payment', currency_code='USD' ) WorksheetPaymentCustomFactory.create( payment_name='gbp payment', currency_code='GBP' ) WorksheetPaymentCustomFactory.create( payment_name='eur payment', currency_code='EUR' ) res = fixture_client.post('/payments/custom/bulk', json={}) assert res.status_code == 200 assert res.json['total_count'] == 3 currencies = [item['currency_code'] for item in res.json['items']] assert 'USD' in currencies assert 'GBP' in currencies assert 'EUR' in currencies def test_worksheet_payment_custom_bulk_response_structure( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint returns correctly structured response.""" WorksheetPaymentCustomFactory.create( account_id=1, contract_id=1, currency_code='USD', amount='100.00', withholding_tax_amount='-10.00', vat_amount='20.00', withholding_tax_rate='10.00', vat_rate='20.00', amount_after_withholding_and_vat='110.00', activity_statement_period_id=1, statement_period_id=1, payment_name='test payment', ) res = fixture_client.post('/payments/custom/bulk', json={}) assert res.status_code == 200 assert 'items' in res.json assert 'total_count' in res.json assert isinstance(res.json['items'], list) assert isinstance(res.json['total_count'], int) # Check first item structure item = res.json['items'][0] assert 'worksheet_payment_custom_id' in item assert 'account_id' in item assert 'contract_id' in item assert 'currency_code' in item assert 'amount' in item assert 'withholding_tax_amount' in item assert 'vat_amount' in item assert 'withholding_tax_rate' in item assert 'vat_rate' in item assert 'amount_after_withholding_and_vat' in item assert 'activity_statement_period_id' in item assert 'statement_period_id' in item assert 'payment_name' in item def test_worksheet_payment_custom_bulk_empty_database( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint when no records exist.""" res = fixture_client.post('/payments/custom/bulk', json={}) assert res.status_code == 200 assert res.json['total_count'] == 0 assert res.json['items'] == [] def test_worksheet_payment_custom_bulk_ordering_by_created_at( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint orders results by created_at descending.""" oldest = WorksheetPaymentCustomFactory.create( created_at=datetime.now() - timedelta(days=10), payment_name='oldest', ) middle = WorksheetPaymentCustomFactory.create( created_at=datetime.now() - timedelta(days=5), payment_name='middle', ) newest = WorksheetPaymentCustomFactory.create( created_at=datetime.now(), payment_name='newest', ) res = fixture_client.post('/payments/custom/bulk', json={}) assert res.status_code == 200 assert res.json['total_count'] == 3 # Should be ordered newest first assert res.json['items'][0]['payment_name'] == 'newest' assert res.json['items'][1]['payment_name'] == 'middle' assert res.json['items'][2]['payment_name'] == 'oldest' def test_worksheet_payment_custom_bulk_large_id_list( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint with large list of IDs.""" # Create 10 records records = [] for i in range(10): records.append( WorksheetPaymentCustomFactory.create(payment_name=f'payment {i}') ) # Request all IDs all_ids = [r.worksheet_payment_custom_id for r in records] test_data = {'filters': {'worksheet_payment_custom_ids': all_ids}} res = fixture_client.post('/payments/custom/bulk', json=test_data) assert res.status_code == 200 assert res.json['total_count'] == 10 assert len(res.json['items']) == 10 def test_worksheet_payment_custom_bulk_mixed_existing_nonexisting_ids( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint with mix of existing and non-existing IDs.""" record1 = WorksheetPaymentCustomFactory.create(payment_name='payment 1') record2 = WorksheetPaymentCustomFactory.create(payment_name='payment 2') # Mix existing and non-existing IDs test_data = { 'filters': { 'worksheet_payment_custom_ids': [ record1.worksheet_payment_custom_id, 999, # doesn't exist record2.worksheet_payment_custom_id, 1000, # doesn't exist ] } } res = fixture_client.post('/payments/custom/bulk', json=test_data) assert res.status_code == 200 assert res.json['total_count'] == 2 assert len(res.json['items']) == 2 payment_names = [item['payment_name'] for item in res.json['items']] assert 'payment 1' in payment_names assert 'payment 2' in payment_names def test_worksheet_payment_custom_bulk_empty_id_list( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint with empty ID list.""" WorksheetPaymentCustomFactory.create(payment_name='payment 1') WorksheetPaymentCustomFactory.create(payment_name='payment 2') test_data = {'filters': {'worksheet_payment_custom_ids': []}} res = fixture_client.post('/payments/custom/bulk', json=test_data) assert res.status_code == 200 # Empty list should return all records assert res.json['total_count'] == 2 assert len(res.json['items']) == 2 def test_worksheet_payment_custom_bulk_pagination_beyond_results( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint pagination when offset exceeds total count.""" WorksheetPaymentCustomFactory.create(payment_name='payment 1') WorksheetPaymentCustomFactory.create(payment_name='payment 2') res = fixture_client.post('/payments/custom/bulk?limit=10&offset=100', json={}) assert res.status_code == 200 assert res.json['total_count'] == 2 assert len(res.json['items']) == 0 def test_worksheet_payment_custom_bulk_with_various_amounts( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test bulk endpoint returns records with various amount values.""" WorksheetPaymentCustomFactory.create( payment_name='small', amount='0.01', withholding_tax_amount='0.00', vat_amount='0.00', amount_after_withholding_and_vat='0.01', ) WorksheetPaymentCustomFactory.create( payment_name='large', amount='999999.99', withholding_tax_amount='-99999.99', vat_amount='99999.99', amount_after_withholding_and_vat='999999.99', ) res = fixture_client.post('/payments/custom/bulk', json={}) assert res.status_code == 200 assert res.json['total_count'] == 2 # Verify amounts are returned as strings with proper precision for item in res.json['items']: assert isinstance(item['amount'], str) assert isinstance(item['amount_after_withholding_and_vat'], str) def test_worksheet_payment_custom_get_by_id_success( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test GET single WorksheetPaymentCustom by ID success.""" # Create a worksheet payment custom record worksheet = WorksheetPaymentCustomFactory.create( account_id=1, contract_id=1, currency_code='USD', amount='100.00', withholding_tax_amount='-10.00', vat_amount='20.00', withholding_tax_rate='10.00', vat_rate='20.00', amount_after_withholding_and_vat='110.00', activity_statement_period_id=1, statement_period_id=1, payment_name='test custom payment', ) res = fixture_client.get(f'/payment/custom/{worksheet.worksheet_payment_custom_id}') assert res.status_code == 200 assert ( res.json['worksheet_payment_custom_id'] == worksheet.worksheet_payment_custom_id ) assert res.json['account_id'] == 1 assert res.json['contract_id'] == 1 assert res.json['currency_code'] == 'USD' assert res.json['amount'] == '100.00' assert res.json['withholding_tax_amount'] == '-10.00' assert res.json['vat_amount'] == '20.00' assert res.json['withholding_tax_rate'] == '10.00' assert res.json['vat_rate'] == '20.00' assert res.json['amount_after_withholding_and_vat'] == '110.00' assert res.json['activity_statement_period_id'] == 1 assert res.json['statement_period_id'] == 1 assert res.json['payment_name'] == 'test custom payment' def test_worksheet_payment_custom_get_by_id_different_currencies( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test GET single WorksheetPaymentCustom with different currencies.""" currencies = ['USD', 'EUR', 'GBP', 'CAD'] for currency in currencies: worksheet = WorksheetPaymentCustomFactory.create( account_id=1, contract_id=1, currency_code=currency, amount='500.00', amount_after_withholding_and_vat='500.00', activity_statement_period_id=1, statement_period_id=1, payment_name=f'{currency} payment', ) res = fixture_client.get( f'/payment/custom/{worksheet.worksheet_payment_custom_id}' ) assert res.status_code == 200 assert res.json['currency_code'] == currency assert res.json['payment_name'] == f'{currency} payment' def test_worksheet_payment_custom_get_by_id_large_amounts( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test GET single WorksheetPaymentCustom with large amounts.""" worksheet = WorksheetPaymentCustomFactory.create( account_id=1, contract_id=1, currency_code='USD', amount='999999999999999999.99', amount_after_withholding_and_vat='999999999999999999.99', activity_statement_period_id=1, statement_period_id=1, payment_name='large amount payment', ) res = fixture_client.get(f'/payment/custom/{worksheet.worksheet_payment_custom_id}') assert res.status_code == 200 assert res.json['amount'] == '999999999999999999.99' assert res.json['amount_after_withholding_and_vat'] == '999999999999999999.99' def test_worksheet_payment_custom_get_by_id_response_structure( fixture_client, mock_accounts, mock_contracts, mock_statement_periods ): """Test GET single WorksheetPaymentCustom returns correct response structure.""" worksheet = WorksheetPaymentCustomFactory.create( account_id=1, contract_id=1, currency_code='USD', amount='100.00', withholding_tax_amount='-10.00', vat_amount='20.00', withholding_tax_rate='10.00', vat_rate='20.00', amount_after_withholding_and_vat='110.00', activity_statement_period_id=1, statement_period_id=1, payment_name='test payment', ) res = fixture_client.get(f'/payment/custom/{worksheet.worksheet_payment_custom_id}') assert res.status_code == 200 # Verify all expected fields are present expected_fields = [ 'worksheet_payment_custom_id', 'account_id', 'contract_id', 'currency_code', 'amount', 'withholding_tax_amount', 'vat_amount', 'withholding_tax_rate', 'vat_rate', 'amount_after_withholding_and_vat', 'activity_statement_period_id', 'statement_period_id', 'payment_name', ] for field in expected_fields: assert field in res.json # Verify amounts are returned as strings assert isinstance(res.json['amount'], str) assert isinstance(res.json['amount_after_withholding_and_vat'], str)