"""Test for /account-payee/tax-form-info/details/bulk when secure_document_item is missing.""" from datetime import date from http import HTTPStatus from unittest.mock import patch from abacus_common_logic.models.base import db from payee.constants.constants import TAX_FORM_TYPES from payee.models.tax_form import TaxFormInfo from tests.conftest import mock_abacus_headers @patch('payee.utils.validations._get_vendor_ids', return_value=[1, 2, 3]) @patch('payee.utils.permissions.authorization_backend.is_authorized', return_value=True) def test_tax_form_details_bulk_with_missing_secure_document( mock_is_authorized, mock_vendor_ids, fresh_db, account_fixtures, payoneer_program_fixtures, account_payee_fixtures, fixture_client, ): """Test that /account-payee/tax-form-info/details/bulk handles missing secure documents gracefully.""" # Create TaxFormInfo records in MySQL without corresponding secure documents in DynamoDB tax_form_info_1 = TaxFormInfo.build( account_payee_id=1, tax_form_type=TAX_FORM_TYPES.W9, signed_date=date(2024, 1, 1), expiration_date=None, ) db.session.add(tax_form_info_1) tax_form_info_2 = TaxFormInfo.build( account_payee_id=2, tax_form_type=TAX_FORM_TYPES.W8BEN, signed_date=date(2024, 2, 1), expiration_date=date(2027, 12, 31), ) db.session.add(tax_form_info_2) tax_form_info_3 = TaxFormInfo.build( account_payee_id=3, tax_form_type=TAX_FORM_TYPES.W8BENE, signed_date=date(2024, 3, 1), expiration_date=date(2027, 12, 31), ) db.session.add(tax_form_info_3) db.session.commit() # Call the endpoint - should not crash even though secure documents are missing result = fixture_client.post( '/account-payee/tax-form-info/details/bulk', headers=mock_abacus_headers(), ) # Verify the response assert result.status_code == HTTPStatus.OK assert 'items' in result.json assert 'total_count' in result.json assert result.json['total_count'] == 3 assert len(result.json['items']) == 3 # Verify each item has the expected structure expected_account_payee_ids = {1, 2, 3} returned_account_payee_ids = set() for item in result.json['items']: # Verify base fields are present assert 'account_payee_tax_form_info_id' in item assert 'tax_form_type' in item assert 'account_payee_id' in item assert 'signed_date' in item returned_account_payee_ids.add(item['account_payee_id']) # Verify that tax form type-specific fields are present but may be None # when secure document is missing (details=None causes __getattr__ to return None) if item['tax_form_type'] == TAX_FORM_TYPES.W9: assert 'tax_classification' in item assert item['tax_classification'] is None elif item['tax_form_type'] in (TAX_FORM_TYPES.W8BEN, TAX_FORM_TYPES.W8BENE): assert 'tax_treaty_claim' in item assert item['tax_treaty_claim'] is None # Verify all expected account_payee_ids are present assert returned_account_payee_ids == expected_account_payee_ids @patch('payee.utils.validations._get_vendor_ids', return_value=[1]) @patch('payee.utils.permissions.authorization_backend.is_authorized', return_value=True) def test_tax_form_details_bulk_filter_with_missing_document( mock_is_authorized, mock_vendor_ids, fresh_db, account_fixtures, payoneer_program_fixtures, account_payee_fixtures, fixture_client, ): """Test filtered endpoint call with missing secure document.""" # Create TaxFormInfo without secure document tax_form_info = TaxFormInfo.build( account_payee_id=1, tax_form_type=TAX_FORM_TYPES.W9, signed_date=date(2024, 1, 1), expiration_date=None, ) db.session.add(tax_form_info) db.session.commit() # Call with filter for this specific account_payee_id result = fixture_client.post( '/account-payee/tax-form-info/details/bulk', headers=mock_abacus_headers(), json={'account_payee_ids': [1]}, ) # Should not crash assert result.status_code == HTTPStatus.OK assert result.json['total_count'] == 1 assert len(result.json['items']) == 1 # Verify the returned item item = result.json['items'][0] assert item['account_payee_id'] == 1 assert item['tax_form_type'] == TAX_FORM_TYPES.W9 assert item['signed_date'] == '2024-01-01' # W9 specific field should be None when secure document is missing assert 'tax_classification' in item assert item['tax_classification'] is None @patch('payee.utils.validations._get_vendor_ids', return_value=[]) @patch('payee.utils.permissions.authorization_backend.is_authorized', return_value=True) def test_tax_form_details_bulk_with_empty_results( mock_is_authorized, mock_vendor_ids, fresh_db, account_fixtures, payoneer_program_fixtures, account_payee_fixtures, fixture_client, ): """Test endpoint returns empty results when no tax forms exist.""" # Don't create any TaxFormInfo records result = fixture_client.post( '/account-payee/tax-form-info/details/bulk', headers=mock_abacus_headers(), ) # Should return empty results assert result.status_code == HTTPStatus.OK assert result.json['total_count'] == 0 assert len(result.json['items']) == 0 @patch('payee.utils.validations._get_vendor_ids', return_value=[1, 2]) @patch('payee.utils.permissions.authorization_backend.is_authorized', return_value=True) def test_tax_form_details_bulk_with_pagination_and_missing_document( mock_is_authorized, mock_vendor_ids, fresh_db, account_fixtures, payoneer_program_fixtures, account_payee_fixtures, fixture_client, ): """Test pagination works correctly when secure documents are missing.""" # Create multiple TaxFormInfo records without secure documents for i in range(1, 6): tax_form_info = TaxFormInfo.build( account_payee_id=i, tax_form_type=TAX_FORM_TYPES.W9, signed_date=date(2024, 1, i), expiration_date=None, ) db.session.add(tax_form_info) db.session.commit() # First page result = fixture_client.post( '/account-payee/tax-form-info/details/bulk?limit=2&offset=0', headers=mock_abacus_headers(), ) assert result.status_code == HTTPStatus.OK assert result.json['total_count'] == 5 assert len(result.json['items']) == 2 # Second page result = fixture_client.post( '/account-payee/tax-form-info/details/bulk?limit=2&offset=2', headers=mock_abacus_headers(), ) assert result.status_code == HTTPStatus.OK assert result.json['total_count'] == 5 assert len(result.json['items']) == 2 # Third page result = fixture_client.post( '/account-payee/tax-form-info/details/bulk?limit=2&offset=4', headers=mock_abacus_headers(), ) assert result.status_code == HTTPStatus.OK assert result.json['total_count'] == 5 assert len(result.json['items']) == 1 @patch('payee.utils.validations._get_vendor_ids', return_value=[1, 2, 3]) @patch('payee.utils.permissions.authorization_backend.is_authorized', return_value=True) def test_tax_form_details_bulk_with_multiple_tax_form_types_missing_documents( mock_is_authorized, mock_vendor_ids, fresh_db, account_fixtures, payoneer_program_fixtures, account_payee_fixtures, fixture_client, ): """Test endpoint handles different tax form types when secure documents are missing.""" # Create TaxFormInfo records with different types tax_forms = [ (1, TAX_FORM_TYPES.W9, None), (2, TAX_FORM_TYPES.W8BEN, date(2027, 12, 31)), (3, TAX_FORM_TYPES.W8BENE, date(2027, 12, 31)), (4, TAX_FORM_TYPES.W8IMY, date(2027, 12, 31)), (5, TAX_FORM_TYPES.W8ECI, date(2027, 12, 31)), ] for account_payee_id, tax_form_type, expiration_date in tax_forms: tax_form_info = TaxFormInfo.build( account_payee_id=account_payee_id, tax_form_type=tax_form_type, signed_date=date(2024, 1, 1), expiration_date=expiration_date, ) db.session.add(tax_form_info) db.session.commit() result = fixture_client.post( '/account-payee/tax-form-info/details/bulk', headers=mock_abacus_headers(), ) # Verify response assert result.status_code == HTTPStatus.OK assert result.json['total_count'] == 5 assert len(result.json['items']) == 5 # Verify all tax form types are present returned_types = {item['tax_form_type'] for item in result.json['items']} expected_types = {tf[1] for tf in tax_forms} assert returned_types == expected_types