import os from payee.config import Config, secrets_manager_client from payee.constants.constants import ( BANK_DETAILS_PAYEE_TYPE, COUNTRIES_REQUIRED_FIELD_PROVINCE, PAYONEER_COUNTRY_MAPPING, ) from payee.constants.features import is_account_payee_flow from payee.utils.exception import NoPayoneerCredentialsException class PayoneerDataHelper: @classmethod def get_register_strategy(cls, payee_type: str): return { BANK_DETAILS_PAYEE_TYPE.INDIVIDUAL: cls.build_individual_payee, BANK_DETAILS_PAYEE_TYPE.COMPANY: cls.build_company_payee, }[payee_type] @staticmethod def build_payout_method(params: dict): return { 'bank_account_type': params['bank_account_type'], 'country': PAYONEER_COUNTRY_MAPPING.get( params['country'], params['country'] ), 'currency': params['currency'], 'bank_field_details': params['bank_field_details'], } @staticmethod def build_individual_payee_contact(params: dict): phone_data = {} if is_account_payee_flow(): phone_data = { 'phone': params.get('phone'), 'phone_country': PAYONEER_COUNTRY_MAPPING.get( params.get('phone_country'), params.get('phone_country') ), } contact = { 'last_name': params['last_name'], 'first_name': params['first_name'], 'date_of_birth': params['date_of_birth'], 'email': params.get('email'), **phone_data, } return {'contact': contact} @staticmethod def build_company_payee_contact(params: dict): if not is_account_payee_flow(): return {} contact = { 'email': params.get('email'), 'phone': params.get('phone'), 'phone_country': PAYONEER_COUNTRY_MAPPING.get( params.get('phone_country'), params.get('phone_country') ), } return {'contact': contact} @staticmethod def build_individual_address(params: dict, add_empty_fields=False): country_code = PAYONEER_COUNTRY_MAPPING.get( params['country_code'], params['country_code'] ) address = { 'address_line_1': params['address_1'], 'city': params['city'], 'country': country_code, 'zip_code': params['zip'], } if address_2 := params.get('address_2'): address['address_line_2'] = address_2 elif add_empty_fields: address['address_line_2'] = '' if country_code in COUNTRIES_REQUIRED_FIELD_PROVINCE: address['state'] = params['province'] elif add_empty_fields: address['state'] = '' return {'address': address} @classmethod def build_individual_payee(cls, params: dict): return { **cls.build_individual_address(params), **cls.build_individual_payee_contact(params), } @staticmethod def build_company_payee(params: dict): company_info = PayoneerDataHelper.build_company_address(params) company_info['company']['name'] = params['name'] return { **company_info, **PayoneerDataHelper.build_company_payee_contact(params), } @staticmethod def build_company_address(params: dict, add_empty_fields=False): country_code = params['country_code'] address_info = { 'incorporated_country': PAYONEER_COUNTRY_MAPPING.get( country_code, country_code ), 'incorporated_address_1': params['address_1'], 'incorporated_city': params['city'], 'incorporated_zipcode': params['zip'], } if address_2 := params.get('address_2'): address_info['incorporated_address_2'] = address_2 elif add_empty_fields: address_info['incorporated_address_2'] = '' if params['country_code'] in COUNTRIES_REQUIRED_FIELD_PROVINCE: address_info['incorporated_state'] = params['province'] elif add_empty_fields: address_info['incorporated_state'] = '' return {'company': address_info} @classmethod def format_register_payee_request(cls, payee_id: str | int, params: dict): payout_method = cls.build_payout_method(params) payout_method['type'] = 'BANK' payee = cls.get_register_strategy(params['type'])(params) payee['type'] = params['type'] return { 'payee_id': payee_id, 'payee': payee, 'payout_method': payout_method, } @staticmethod def format_update_payee_request(params: dict): body = { 'type': 'BANK', 'bank_account_type': params.get('bank_account_type'), 'country': PAYONEER_COUNTRY_MAPPING.get( params.get('country'), params.get('country') ), 'currency': params.get('currency'), 'bank_field_details': params.get('bank_field_details'), } return body @classmethod def get_address_strategy(cls, payee_type: str): return { BANK_DETAILS_PAYEE_TYPE.INDIVIDUAL: cls.build_individual_address, BANK_DETAILS_PAYEE_TYPE.COMPANY: cls.build_company_address, }[payee_type] @classmethod def format_edit_profile_request(cls, params: dict): edit_profile_info = cls.get_address_strategy(params['type'])(params, True) contact = {} if email := params.get('email'): contact['email'] = email if is_account_payee_flow() and (phone := params.get('phone')): contact['phone'] = phone contact['phone_country'] = PAYONEER_COUNTRY_MAPPING.get( params.get('phone_country'), params.get('phone_country') ) if contact: edit_profile_info['contact'] = contact return edit_profile_info class PayoneerAuthHelper: """Payoneer Auth helper to for operations with token and auth headers.""" @classmethod def build_headers(cls) -> dict: """Build Payoneer headers. This logic can't be in the config because that logic only runs when the micro-service is deployed. Since the token expires, we need to retrive the latest token from secrets manager every time we need to use it in the headers. Raises NoPayoneerCredentialsException if no credentials found. """ token = os.environ.get('PAYONEER_AUTH_TOKEN') if Config.ENVIRONMENT in [ Config.QA_ENVIRONMENT, Config.UAT_ENVIRONMENT, Config.PROD_ENVIRONMENT, ]: token = cls.get_secret_token() # Ignore staged dummy credentials if token and len(token) > 20: payoneer_headers = { 'content-type': 'application/json', 'Authorization': f'Bearer {token}', } else: raise NoPayoneerCredentialsException() return payoneer_headers @staticmethod def get_secret_token() -> str: """Return latest payoneer auth token form secrets manager.""" return secrets_manager_client.get_secret_value( SecretId=Config.PAYONEER_AUTH_TOKEN_ARN, VersionStage='AWSCURRENT' )['SecretString']