# flake8: noqa """find_or_create_account.""" import uuid from common.connectors.snowfalke_connector import execute_snowflake_query from common.constants.product_nfd import SME_ANALYTICS_DUMMY from common.schemas.state_machine_schema import StateMachineSchema import config from src.constants.general import PALM_TREE_RECORDS_IMPRINT_PREFIX from src.constants.snowflake_queries import \ GET_COUNTRY_ID_BY_PARENT_REPERTOIRE_OWNER_NAME from src.helpers.graphql_requests import ( create_new_subaccount, create_new_vendor, get_product_by_upc, get_subaccount_for_vendor, get_vendor_for_rep_owner_code, update_external_identifier_1, update_vendor_country_id) from src.helpers.vendor_mapping import ( get_parent_repertoire_owner_mapping, get_vendor_and_subaccount_for_rep_owner_code_rows, insert_vendor_and_subaccount_mapping) from src.exceptions import LambdaException, RetryableException, \ VendorDoNotIngestException, ProductExistUnderDifferentVendorException logger = config.app_logger def handler(event, context): """Find_or_create_account handler.""" logger.info(f'Triggered find_or_create_account: {event}') logger.info(f'Triggered create_project: {event}') sm_context = StateMachineSchema().load(event) if sm_context.product.vendor_id and sm_context.product.subaccount_id: logger.info(f'Found vendor {sm_context.product.vendor_id} and' f' subaccount {sm_context.product.subaccount_id}') return StateMachineSchema().dump(sm_context) correlation_id = sm_context.correlation_id or str(uuid.uuid4()) sm_context.correlation_id = correlation_id logger.info('Getting the vendor/subaccount.') try: # Verify if the product already exists under a different vendor than in the mapping table. # If so, update the existing product without modifying the mapping. # If upc is None then the product will be inserted as a new product # with a new upc using set_product as a placeholder upc if sm_context.product.upc: vendor_id, subaccount_id = \ get_vendor_and_subaccount_for_existing_product(sm_context) else: vendor_id, subaccount_id = None, None # Check if the parent_rep_owner_name is needed to be remapped check_remapping_parent_rep_owner(sm_context) if vendor_id is None: # check if mapping exists in inbound_major_label_mapping table vendor_id, subaccount_id = get_vendor_and_subaccount_in_mapping_table( sm_context) # in case there is no mapping in the table if not vendor_id or not subaccount_id: # save the correlation_id in s3_context to use it in the graphql requests vendor_id = get_vendor_via_graphql(sm_context) if vendor_id: subaccount_id = get_subaccount_via_graphql(sm_context, vendor_id) # if vendor_id is not found, create a new vendor elif not vendor_id: vendor_id = create_vendor(sm_context) if vendor_id and not subaccount_id: # if vendor_id is found, create a new subaccount subaccount_id = create_subaccount(sm_context, vendor_id) if vendor_id and subaccount_id: logger.info( f'Inserting vendor {vendor_id} and subaccount {subaccount_id} into mapping table.') insert_vendor_and_subaccount_mapping( logger, vendor_id, subaccount_id, sm_context) if not vendor_id or not subaccount_id: logger.info( f'Vendor_id {vendor_id} and/or subaccount_id {subaccount_id} is empty.') raise LambdaException( f'Vendor_id {vendor_id} and/or subaccount_id {subaccount_id} is empty.') except LambdaException: # this will raise ProductExistUnderDifferentVendorException, VendorDoNotIngestException logger.exception("LambdaException : ") raise except Exception as err: # try to catch the error like timeout or connection error # and retry the lambda function in terraform logger.error(f'Error getting vendor/subaccount: {err}') logger.exception("Error getting vendor/subaccount") raise RetryableException(f'Error getting vendor/subaccount: {err}') sm_context.product.vendor_id = vendor_id sm_context.product.subaccount_id = subaccount_id return StateMachineSchema().dump(sm_context) def get_vendor_and_subaccount_in_mapping_table(sm_context): """Return the SME vendor/subaccount.""" vendor_id, subaccount_id = None, None logger.info('Getting vendor and subaccount in mapping_table.') rows = get_vendor_and_subaccount_for_rep_owner_code_rows( logger, sm_context) # There should only be one row for label mapping if len(rows) > 1: raise LambdaException( f'Multiple label mappings found in the mapping table: {rows}') if len(rows) == 1: do_not_ingest = rows[0].get('do_not_ingest', None) if do_not_ingest and \ not sm_context.product.imprint.startswith( PALM_TREE_RECORDS_IMPRINT_PREFIX): raise VendorDoNotIngestException( f'Parent rep owner code {sm_context.product.parent_repertoire_owner_code} ' f'and rep owner code {sm_context.product.repertoire_owner_code} ' f'are not for ingestion.' ) if sm_context.product.imprint.startswith( PALM_TREE_RECORDS_IMPRINT_PREFIX): logger.info('Found "Palm Tree Records" ignore do_not_ingest flag') vendor_id = rows[0].get('vendor_id', None) subaccount_id = rows[0].get('subaccount_id', None) logger.info(f'Getting vendor {vendor_id} and ' f'subaccount {subaccount_id} in mapping_table.') return vendor_id, subaccount_id def get_vendor_via_graphql(sm_context): """Get vendor via graphql request.""" logger.info('Getting the vendor via graphql.') vendors = get_vendor_for_rep_owner_code(logger, sm_context) # There should only be one row for label mapping if len(vendors) > 1: raise LambdaException(f'Multiple label mappings found: {vendors}') if len(vendors) == 1: vendor = vendors[0].get('vendorId') logger.info(f'Found vendor {vendor} via graphql.') return vendors[0].get('vendorId') def get_subaccount_via_graphql(sm_context, vendor_id: int): """Get subaccount via graphql request.""" logger.info('Getting the subaccount via graphql.') subaccounts = get_subaccount_for_vendor(logger, sm_context, vendor_id) # There should only be one subaccount if len(subaccounts) > 1: raise LambdaException(f'Multiple subaccounts for vendor: {vendor_id}') if len(subaccounts) == 1: subaccount = subaccounts[0].get('subaccountId') logger.info(f'Found subaccount {subaccount} via graphql.') return subaccounts[0].get('subaccountId') def get_vendor_and_subaccount_for_existing_product(sm_context): """Get vendor and subaccount if product exists.""" logger.info('Getting the vendor and subaccount if product exists.') product = get_product_by_upc(logger, sm_context) if product and product['notForDistribution'] == SME_ANALYTICS_DUMMY: return product['vendorId'], product['subaccountId'] if product and product['notForDistribution'] != SME_ANALYTICS_DUMMY: raise ProductExistUnderDifferentVendorException( f'Product with UPC {sm_context.product.upc} already exists under a different vendor. ' f'Vendor ID: {product["vendorId"]}, Subaccount ID: {product["subaccountId"]}, ' f'not_for_distribution: {product["notForDistribution"]}' ) return None, None def check_remapping_parent_rep_owner(sm_context): """Check if the parent_rep_owner_name is remapped.""" logger.info( 'Checking if the parent_rep_owner_name is needed to be remapped.') # Get parent repertoire owner mapping in REP_OWNER_HIERARCHY table check_mapping = get_parent_repertoire_owner_mapping(logger, sm_context) if not check_mapping: logger.info('No mapping found for parent repertoire owner code.') return if len(check_mapping) > 1: raise LambdaException( f'Multiple parent repertoire owner mappings found: {check_mapping}') remapped_parent_repertoire_owner_code = check_mapping[0][ 'REP_OWNER_PARENT_CD'] # Check if the parent_repertoire_owner_code is remapped if sm_context.product.parent_repertoire_owner_code != remapped_parent_repertoire_owner_code: sm_context.product.parent_repertoire_owner_code = remapped_parent_repertoire_owner_code def create_vendor(sm_context): """Create vendor.""" logger.info('Creating vendor.') country_id = get_vendor_country_id(sm_context) vendor = create_new_vendor(logger, sm_context) if not vendor: raise LambdaException('Vendor creation failed.') vendor_id, vendor_uuid = vendor['vendorId'], vendor['uuid'] # Update external_identifier_1 for the new vendor update_external_identifier_1(logger, sm_context, vendor_uuid) if country_id: update_vendor_country_id(logger, country_id, vendor_uuid) return vendor_id def create_subaccount(sm_context, vendor_id: int): """Create subaccount.""" logger.info('Creating subaccount.') subaccount = create_new_subaccount(logger, sm_context, vendor_id) if not subaccount: raise LambdaException('Subaccount creation failed.') return subaccount['subaccountId'] def get_vendor_country_id(sm_context): """Get vendor country id.""" parent_repertoire_owner_name = sm_context.product.parent_repertoire_owner_name logger.info(f'Getting country id for {parent_repertoire_owner_name}') result = execute_snowflake_query( GET_COUNTRY_ID_BY_PARENT_REPERTOIRE_OWNER_NAME, {'parent_repertoire_owner_name': parent_repertoire_owner_name}) if len(result) == 0: logger.warning( f'Can not find country id for {parent_repertoire_owner_name}') return None return result[0]['ID']