"""Tests payment Details serialization.""" from typing import Any from unittest.mock import patch from marshmallow import ValidationError import pytest from payee.constants.constants import ( KNR_VAT_PREFIXES_OMIT_VALIDATION, PAYMENT_ENTITIES, REQUIRED_FIELD_MESSAGE, UNKNOWN_FIELD_MESSAGE, ) from payee.schemas.address import AddressSchema, NonUSAddressSchema from payee.schemas.tax_details import ( DETaxDetailsSchema, ESTaxDetailsSchema, get_tax_details_schema_for_corp_entity, HmrcApiException, KnrDetailsSchema, KnrTaxDetailsSchema, NOTaxDetailsSchema, UkTaxDetailsSchema, ViesApiException, ) from tests.utils.factories import AddressFactory def test_vat_registered_schema(mock_payee_vat_registered_tax_details, faker): """Test tax details schema for VAT-registered users.""" test_address = faker.pystr(min_chars=255, max_chars=255) mock_tax_details = { **mock_payee_vat_registered_tax_details, 'address': { **mock_payee_vat_registered_tax_details['address'], 'address_1': test_address, 'address_2': test_address, }, } result = UkTaxDetailsSchema().dump(mock_tax_details) assert result == mock_tax_details def test_norway_schema(mock_payee_vat_registered_tax_details): """Test tax details schema for Norway.""" result = NOTaxDetailsSchema().dump(mock_payee_vat_registered_tax_details) assert result == mock_payee_vat_registered_tax_details @patch('payee.schemas.tax_details.Vies') def test_eu_vat_registered_schema_success( mock_vies, mock_payee_eu_vat_registered_tax_details ): """Test tax details schema for KNR EU VAT-registered users.""" mock_vies.return_value.request.return_value = True result = KnrTaxDetailsSchema().load(mock_payee_eu_vat_registered_tax_details) assert result == mock_payee_eu_vat_registered_tax_details @patch('payee.schemas.tax_details.Vies') def test_eu_vat_registered_schema_failure( mock_vies, mock_payee_eu_vat_registered_tax_details ): """Test tax details schema for KNR EU VAT-registered users.""" mock_vies.return_value.request.side_effect = ViesApiException with pytest.raises(ValidationError) as exc_info: KnrTaxDetailsSchema().load(mock_payee_eu_vat_registered_tax_details) assert 'vat_number' in exc_info.value.messages @patch('payee.schemas.tax_details.uk_gov.validate_vat_number', return_value=True) def test_gb_vat_registered_schema_success( mock_uk_gov, mock_payee_gb_vat_registered_tax_details ): """Test tax details schema for KNR EU VAT-registered users.""" result = KnrTaxDetailsSchema().load(mock_payee_gb_vat_registered_tax_details) assert result == mock_payee_gb_vat_registered_tax_details @patch( 'payee.schemas.tax_details.uk_gov.validate_vat_number', side_effect=HmrcApiException ) def test_gb_vat_registered_schema_failure( mock_uk_gov, mock_payee_gb_vat_registered_tax_details ): """Test tax details schema for KNR EU VAT-registered users.""" with pytest.raises(ValidationError) as exc_info: KnrTaxDetailsSchema().load(mock_payee_gb_vat_registered_tax_details) assert 'vat_number' in exc_info.value.messages @pytest.mark.parametrize('country', KNR_VAT_PREFIXES_OMIT_VALIDATION) def test_omitted_vat_registered_schema(mock_payee_vat_registered_tax_details, country): """Test tax details schema for KNR EU VAT-registered users.""" data = { **mock_payee_vat_registered_tax_details, 'vat_number': f'{country}821018768', } result = KnrTaxDetailsSchema().load(data) assert result == data def test_knr_details_schema(mock_payee_knr_details): """Test tax details schema for VAT-registered users.""" result = KnrDetailsSchema().dump(mock_payee_knr_details) assert result == mock_payee_knr_details def test_non_vat_registered_schema(mock_payee_non_vat_registered_tax_details): """Test tax details schema for NON-VAT-registered users.""" result = UkTaxDetailsSchema().dump(mock_payee_non_vat_registered_tax_details) assert result == mock_payee_non_vat_registered_tax_details def test_get_tax_details_schema_for_corp_entity(): """Test that we get back the correct schema based on the parameters.""" schema = get_tax_details_schema_for_corp_entity(PAYMENT_ENTITIES.AWAL_UK) assert isinstance(schema(), UkTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(PAYMENT_ENTITIES.ORCHARD_UK) assert isinstance(schema(), UkTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(PAYMENT_ENTITIES.ORCHARD_NO) assert isinstance(schema(), NOTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(PAYMENT_ENTITIES.KNR_NL) assert isinstance(schema(), KnrTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(PAYMENT_ENTITIES.KNR_UK) assert isinstance(schema(), KnrTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(PAYMENT_ENTITIES.ORCHARD_ES) assert isinstance(schema(), ESTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity('US') assert schema is None def test_get_tax_details_schema_for_corp_entity_id( fresh_db, reference_payment_entity_fixtures ): """Test that we get back the correct schema based on the parameters.""" schema = get_tax_details_schema_for_corp_entity(1) assert isinstance(schema(), UkTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(7) assert isinstance(schema(), UkTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(9) assert isinstance(schema(), NOTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(4) assert isinstance(schema(), KnrTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(3) assert isinstance(schema(), KnrTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(6) assert isinstance(schema(), ESTaxDetailsSchema) schema = get_tax_details_schema_for_corp_entity(99999) assert schema is None @pytest.mark.parametrize( 'params_country,expected_country', ((None, 'ESP'), ('ESP', 'ESP'), ('CAN', 'CAN')), ) def test_es_vat_registered_schema_success( mock_payee_es_vat_registered_tax_details: dict[str, Any], params_country: str, expected_country: str, ): """Test tax details schema for Orchard ES VAT-registered users.""" params = dict(mock_payee_es_vat_registered_tax_details) params['country_of_tax_residency_code'] = params_country result = ESTaxDetailsSchema().load(params) local_tax_id = f'ES{params["local_tax_id"]}' assert result == { **params, 'vat_number': local_tax_id, 'country_of_tax_residency_code': expected_country, } def test_es_vat_registered_schema_success_empty_fields(): """Test tax details schema for Orchard ES VAT-registered users and empty address fields.""" data = { 'local_tax_id': '12345678', 'is_vat_registered': True, 'address': {'country_code': 'UKR'}, } result = ESTaxDetailsSchema().load(data) local_tax_id = f'ES{data["local_tax_id"]}' assert result == { **data, 'vat_number': local_tax_id, 'country_of_tax_residency_code': 'ESP', } def test_es_non_vat_registered_schema_success( mock_payee_es_non_vat_registered_tax_details: dict[str, Any], ): """Test tax details schema for Orchard ES non VAT-registered users.""" result = ESTaxDetailsSchema().load(mock_payee_es_non_vat_registered_tax_details) assert result == { **mock_payee_es_non_vat_registered_tax_details, 'vat_number': None, 'country_of_tax_residency_code': 'ESP', } def test_es_vat_registered_schema_failure_address( mock_payee_es_vat_registered_tax_details: dict[str, Any], ): """Test tax details schema for Orchard ES VAT-registered users.""" del mock_payee_es_vat_registered_tax_details['address'] with pytest.raises(ValidationError) as exc_info: ESTaxDetailsSchema().load(mock_payee_es_vat_registered_tax_details) assert exc_info.value.messages == {'address': REQUIRED_FIELD_MESSAGE} def test_es_non_vat_registered_schema_failure_address( mock_payee_es_vat_registered_tax_details: dict[str, Any], ): """Test tax details schema for Orchard ES non VAT-registered users.""" mock_payee_es_vat_registered_tax_details['is_vat_registered'] = False with pytest.raises(ValidationError) as exc_info: ESTaxDetailsSchema().load(mock_payee_es_vat_registered_tax_details) assert exc_info.value.messages == {'address': UNKNOWN_FIELD_MESSAGE} def test_de_tax_details_schema_success(mock_payee_de_tax_details: dict[str, Any]): """Test tax details schema for Orchard DE.""" result = DETaxDetailsSchema().load(mock_payee_de_tax_details) assert result == mock_payee_de_tax_details def test_no_tax_details_schema_success(mock_payee_no_tax_details: dict[str, Any]): """Test tax details schema for Orchard NO.""" result = NOTaxDetailsSchema().load(mock_payee_no_tax_details) assert result == mock_payee_no_tax_details def test_no_tax_details_schema_failure(mock_payee_no_tax_details: dict[str, Any]): """Test tax details schema for Orchard NO.""" del mock_payee_no_tax_details['vat_number'] with pytest.raises(ValidationError) as exc_info: NOTaxDetailsSchema().load(mock_payee_no_tax_details) def test_no_tax_details_schema_success_incomplete_address( mock_payee_no_tax_details: dict[str, Any], ): """Test tax details schema for Orchard NO with incomplete address.""" data = { **mock_payee_no_tax_details, 'address': {'country_code': 'ESP'}, } result = NOTaxDetailsSchema().load(data) assert result == data def test_address_schema_ag_zip_not_required(): """Test that AddressSchema does not require zip for ATG (Antigua and Barbuda).""" address = AddressFactory.build() address['country_code'] = 'ATG' del address['zip'] # Remove zip field result = AddressSchema().load(address) assert result['country_code'] == 'ATG' assert 'zip' not in result @pytest.mark.parametrize('country_code', ['USA', 'GBR']) def test_address_schema_zip_required_for_us_gb(country_code): """Test that AddressSchema requires zip for USA and GBR.""" address = AddressFactory.build() address['country_code'] = country_code del address['zip'] # Remove zip field with pytest.raises(ValidationError) as exc_info: AddressSchema().load(address) # Should fail because zip is required for non-AG countries assert 'zip' in exc_info.value.messages assert exc_info.value.messages['zip'] == ['This field is required.'] @pytest.mark.parametrize('country_code', ['ATG', 'NOR']) # NOR = Norway def test_non_us_address_schema_zip_not_required_ag_norway(country_code): """Test that NonUSAddressSchema does not require zip for ATG and NOR.""" address = AddressFactory.build() address['country_code'] = country_code del address['zip'] # Remove zip field result = NonUSAddressSchema().load(address) assert result['country_code'] == country_code assert 'zip' not in result