"""Logic for GraphQL integration. Provides logic to take info from GraphQL. """ from typing import Any, Optional from payee.config import Config from payee.connectors.graphql import graphql_client from payee.constants.constants import ( PAYMENT_ENTITIES_FALLBACK_SIGNING_ENTITIES, PAYMENT_ENTITIES_LOGOS, ) from payee.constants.queries import ( ACCOUNT_DETAILS_FOR_TAX_RECEIPT, CORP_PAYMENT_ENTITY_NAME_BY_ACCOUNT_ID, PAYEE_ACTION_STATES, PAYEE_COUNTRY_OF_TAX_RESIDENCY, ) def get_payee_country_of_tax_residency(account_payee_id: int) -> Optional[str]: """Get payee country of tax residency from graphql.""" graphql_client.set_headers(Config.SERVICE_PROFILE_HEADERS) data = graphql_client.execute( PAYEE_COUNTRY_OF_TAX_RESIDENCY, {'accountPayeeId': account_payee_id} ) if not data['data']['abacusAccountPayee']: return None country_code = data['data']['abacusAccountPayee']['account']['accountTaxInfo'][ 'countryOfTaxResidence' ] return country_code def get_abacus_account_details(account_id: int) -> dict: """Get account details from graphql. Get details for a PDF tax receipt from abacus account graphQL service for a templates/tax_details.html template and specified template variables: account_name, signing_entity_name, signing_entity_vat_number. Args: account_id (int): account id for getting signing entity Returns: account_details (dict): account details """ # Note: Account signing entity is an internal field, so we cannot forward # the client headers and should use the service-specific headers to # make this request instead. graphql_client.set_headers(Config.SERVICE_PROFILE_HEADERS) data = graphql_client.execute( ACCOUNT_DETAILS_FOR_TAX_RECEIPT, {'accountId': account_id, 'accountIds': [account_id]}, ) abacus_account = data['data']['abacusAccount'] if not abacus_account: return {} response = { 'account_id': account_id, 'account_name': abacus_account['accountName'], 'signing_entity_name': None, 'signing_entity_vat_number': None, } if not abacus_account['accountPaymentTerm']['paymentEntity']: return response payment_entity_name = abacus_account['accountPaymentTerm']['paymentEntity'][ 'paymentEntityName' ] signing_entity = _get_signing_entity(data) account_details = { 'account_id': account_id, 'logo_path': PAYMENT_ENTITIES_LOGOS.get(payment_entity_name, ''), 'account_name': abacus_account['accountName'], 'signing_entity_name': signing_entity['legalName'] if signing_entity else None, 'signing_entity_vat_number': signing_entity['vatNumber'] if signing_entity else None, } return account_details def _get_signing_entity(data: dict[str, Any]) -> dict[str, Any] | None: """Get signing entity with fallback logic.""" abacus_account = data['data']['abacusAccount'] payment_entity_name = abacus_account['accountPaymentTerm']['paymentEntity'][ 'paymentEntityName' ] contracts = data['data']['abacusContracts']['items'] signing_entity = contracts[0]['referenceSigningEntity'] if contracts else None if signing_entity and signing_entity['vatNumber']: return signing_entity fallback_signing_entity_id = PAYMENT_ENTITIES_FALLBACK_SIGNING_ENTITIES.get( payment_entity_name ) if not fallback_signing_entity_id: return signing_entity reference_signing_entities = data['data']['abacusReferenceSigningEntities']['items'] signing_entity = next( ( entity for entity in reference_signing_entities if entity['referenceSigningEntityId'] == fallback_signing_entity_id ), None, ) return signing_entity def get_payment_entity_name_by_account_id(account_id: int) -> Optional[str]: """Get account's payment entity from graphql. Args: account_id (int): account id for getting payment entity Returns: payment_entity_name (str): account's payment entity name """ # Note: Account payment entity is an internal field, so we cannot forward # the client headers and should use the service-specific headers to # make this request instead. graphql_client.set_headers(Config.SERVICE_PROFILE_HEADERS) data = graphql_client.execute( CORP_PAYMENT_ENTITY_NAME_BY_ACCOUNT_ID, {'accountId': account_id} ) abacus_account = data['data']['abacusAccount'] if not abacus_account or not abacus_account['accountPaymentTerm']['paymentEntity']: return None return abacus_account['accountPaymentTerm']['paymentEntity']['paymentEntityName'] def get_payee_action_states(account_payee_id: int) -> Optional[list]: """Get payee action states list from graphql.""" graphql_client.set_headers(Config.SERVICE_PROFILE_HEADERS) data = graphql_client.execute( PAYEE_ACTION_STATES, {'accountPayeeId': account_payee_id} ) if not data['data']['abacusAccountPayee']: return None action_states = data['data']['abacusAccountPayee']['actionStates'] return action_states