"""AccountTaxInfo logic.""" from datetime import date import typing from marshmallow import ValidationError from owsresponse import response from abacus_account import models from abacus_account.connectors.kafka import emit_account_tax_id_event from abacus_account.constants import error from abacus_account.constants.constants import ( ACCOUNT_KAFKA_EVENT_NAMES, ALLOW_NONE_COTR_COUNTRIES_OF_TAX_REPORTING ) from abacus_account.schemas.account_tax_info import AccountTaxInfoDetailSchema from abacus_account.utils.validations import validate_country_code account_tax_info_detail_schema = AccountTaxInfoDetailSchema() def create_account_tax_info(**params): """Create an account_tax_info.""" account_id = params['account_id'] country_code = params['country_of_tax_residence'] is_sba_signed = params.get('is_sba_signed') is_vat_exempt = params.get('is_vat_exempt', True) is_tax_treaty_claimed = params.get('is_tax_treaty_claimed', False) tax_employment_type = params.get('tax_employment_type') certificate_of_residence_expiration_date = params.get( 'certificate_of_residence_expiration_date' ) is_wht_applicable = params.get('is_wht_applicable', True) is_resident_of_spanish_islands = params.get('is_resident_of_spanish_islands') wht_rate_override = params.get('wht_rate_override') try: if country_code: country_code = country_code.upper() validate_country_code(country_code) _validate_account_id_unique(account_id) new_account_tax_info = models.AccountTaxInfo.create( account_id=account_id, country_of_tax_residence=country_code, is_sba_signed=is_sba_signed, is_vat_exempt=is_vat_exempt, is_tax_treaty_claimed=is_tax_treaty_claimed, tax_employment_type=tax_employment_type, certificate_of_residence_expiration_date=certificate_of_residence_expiration_date, # noqa is_wht_applicable=is_wht_applicable, is_resident_of_spanish_islands=is_resident_of_spanish_islands, wht_rate_override=wht_rate_override ) except Exception as e: return response.create_error_response('error', str(e), status=400) return response.Response( message=account_tax_info_detail_schema.dump(new_account_tax_info), status=201 ) def update_account_tax_info(account_tax_info_object: models.AccountTaxInfo, **params): """Wrap updating account_tax_info logic. Params could be: country_of_tax_residence: Optional[str] is_sba_signed: Optional[bool] """ try: _validate_update_params(account_tax_info_object, params) account_tax_info_object = account_tax_info_object.update_attributes(**params) models.AccountTaxInfo.commit_changes() except Exception as e: return response.create_error_response('error', str(e), status=400) emit_account_tax_id_event( account_tax_info_id=account_tax_info_object.account_tax_info_id, action_name=ACCOUNT_KAFKA_EVENT_NAMES.TAX_INFO_UPDATED) return response.Response( message=account_tax_info_detail_schema.dump(account_tax_info_object), status=201 ) def _validate_update_params(account_tax_info_object: models.AccountTaxInfo, params): # the country_of_tax_residence is optional param for update # so we should deal with it only if it is really present if 'country_of_tax_residence' in params: country_of_tax_residence = params['country_of_tax_residence'] payment_entity = models.ReferencePaymentEntity.get_by_id( account_tax_info_object.account.account_payment_term.payment_entity_id ) if ( not country_of_tax_residence and payment_entity.country_of_tax_reporting not in ALLOW_NONE_COTR_COUNTRIES_OF_TAX_REPORTING ): raise ValidationError(error.COUNTRY_OF_TAX_RESIDENCE_IS_REQUIRED) elif country_of_tax_residence: country_of_tax_residence = country_of_tax_residence.upper() validate_country_code(country_of_tax_residence) params['country_of_tax_residence'] = country_of_tax_residence def get_account_tax_info_by_account_id(account_id: int): """Get an account_tax_info by an account_id.""" account = models.Account.get_by_id_or_error(account_id) return response.Response( message=account_tax_info_detail_schema.dump(account.account_tax_info), status=200 ) def account_tax_info_export(account_ids=None): """Get account tax info in tsv format. Args: account_ids (list): account ids to filter the result by """ snapshot_header = ( 'account_tax_info_id', 'account_id', 'country_of_tax_residence', 'is_sba_signed', 'is_vat_exempt', 'is_tax_treaty_claimed', 'tax_employment_type', 'certificate_of_residence_expiration_date', 'is_wht_applicable', 'is_resident_of_spanish_islands', 'wht_rate_override' ) yield '{}\n'.format('\t'.join(snapshot_header)) for item in models.AccountTaxInfo.stream_all(account_ids): data = AccountTaxInfoDetailSchema().dump(item) yield '{}\n'.format('\t'.join([ str(data['account_tax_info_id']), str(data['account_id']), data['country_of_tax_residence'], str(int(data['is_sba_signed'])), str(int(data['is_vat_exempt'])), str(int(data['is_tax_treaty_claimed'])), str(data['tax_employment_type'] if data['tax_employment_type'] else ''), str(data['certificate_of_residence_expiration_date'] if data['certificate_of_residence_expiration_date'] else ''), str(int(data['is_wht_applicable'])), str( int(data['is_resident_of_spanish_islands']) if data['is_resident_of_spanish_islands'] else '' ), str( data['wht_rate_override'] if data['wht_rate_override'] else '' ), ])) def _validate_account_id_unique(account_id: int): """Check if account exists and account.account_tax_info doesn't exist.""" account = models.Account.get_by_id_or_error(account_id) if account.account_tax_info: raise ValidationError( error.ERROR_ACCOUNT_TAX_INFO_ALREADY_EXISTS.format(object_id=account_id) ) def get_account_tax_info_list( limit: int, offset: int, account_ids: typing.List[int], certificate_of_residence_expiration_date_start: date | None = None, certificate_of_residence_expiration_date_end: date | None = None ): """Get an account_tax_info list with optional filter by account ids.""" items, total_count = models.AccountTaxInfo.get_filtered_items( limit=limit, offset=offset, account_ids=account_ids, certificate_of_residence_expiration_date_start=certificate_of_residence_expiration_date_start, # noqa: E501 certificate_of_residence_expiration_date_end=certificate_of_residence_expiration_date_end # noqa: E501 ) return response.Response({ 'items': account_tax_info_detail_schema.dump(items, many=True), 'total_count': total_count })