"""Lambda create_vendor function module.""" from typing import List import boto3 from marshmallow import EXCLUDE from marshmallow import ValidationError from owsclient import M2MTokenManager from owsclient import OwsClient from secrets_manager.lambda_ext import LambdaSecretsManager from src import config from src.config import AWS_REGION from src.config import DYNAMO_TABLE from src.config import app_logger as logger from src.constants import general as constants from src.constants import oa_users from src.constants.features import DEFAULT_RESTRICTED_FEATURES from src.schemas.create_vendor import CreateVendorSchema secrets_manager = LambdaSecretsManager( environment=config.ENVIRONMENT, service_name=config.LAMBDA_NAME, ) m2m_token_manager = M2MTokenManager( secrets_manager=secrets_manager, environment=config.ENVIRONMENT, service_name=config.LAMBDA_NAME, ) ows_client = OwsClient( environment=config.ENVIRONMENT, service_name=config.LAMBDA_NAME, m2m_token_manager=m2m_token_manager, ) class RetryException(Exception): """Retry Exception.""" pass class BadRequest(Exception): """Bad Request cannot retry Exception.""" pass def set_correlation_id(correlation_id, result): """Set correlation_id for create_vendor in DynamoDB table logger.""" logger.info(f'Writing correlation id' f' {correlation_id} to dynamodb table.') if 'Attributes' in result: logger.info('This correlation id already exists in' ' the gda-account-creation-create-vendor table.') def set_restricted_features( action: str, vendor_id: int, feature_ids: List[int]) -> None: """Add or Remove VendorRestrictedFeatures.""" assert action in {'add', 'remove'} json_data = { 'feature_ids': feature_ids } set_restricted_feature_result = ows_client.post( config.OWS_SERVICE_NAME, f'/vendor/{vendor_id}/restricted_features/{action}', json=json_data, headers=config.OWS_REQUEST_HEADERS ) if 200 <= set_restricted_feature_result.status_code < 300: return None if 400 <= set_restricted_feature_result.status_code < 500: logger.info( f'Error {action} restricted feature response ' f'status_code={set_restricted_feature_result.status_code} ' f'error={set_restricted_feature_result.text} ') raise BadRequest( 'Invalid request.', set_restricted_feature_result.text) else: logger.info( f'Error ows response ' f'status_code={set_restricted_feature_result.status_code} ' f'error={set_restricted_feature_result.text}') raise RetryException( f'{action} restricted feature failed for valid request, so retry.') def handler(event, context): """Lambda entry point.""" input_data = event or {} if ( (input_data['source'] == constants.AWAL_PLUS_SOURCE or input_data['source'] == constants.KNR_SOURCE) and input_data['vendor_id'] and not input_data['vendor_name'] ): logger.info('vendor_id detected, skipping vendor creation.') return { 'vendor_id': int(input_data['vendor_id']) } try: # validate input and exclude extra properties that are not in schema. # this way we wont sent extra attributes to ows. result = CreateVendorSchema().load(input_data, unknown=EXCLUDE) logger.info( f"Successfully validated the request for {result['vendor_name']} " 'now calling create_vendor') # defaults for call ows to create vendor result['country'] = input_data.get('country') result['source'] = input_data.get('source') result['company_brand'] = input_data.get('brand') if result['source'] == constants.AWAL_PLUS_SOURCE: result['assigned_to'] = oa_users.GDA_ASSIGNED_TO result['assigned_reviewer'] = oa_users.GDA_QB_LABEL if result['source'] == constants.GDA_SOURCE: result['quarterback_label_manager'] = oa_users.GDA_QB_LABEL result['service_tier_uuid'] = constants.GDA_SERVICE_TIER_UUID result['assigned_to'] = oa_users.GDA_ASSIGNED_TO result['assigned_reviewer'] = oa_users.GDA_QB_LABEL # remove country from request for AWAL Plus and KNR if result['source'] == constants.AWAL_PLUS_SOURCE or \ result['company_brand'] == constants.KNR_BRAND: del result['country'] # input will be called brand but ows requires owner. if 'owner' in input_data: result['owner'] = input_data.get('owner') elif result['company_brand'] == constants.AWAL_BRAND: result['owner'] = constants.AWAL_CORE_ACCOUNTS else: result['owner'] = result['company_brand'] # Set closer id to whoever owns the referral code, or else the default voucher_code = input_data.get('voucher_code') if voucher_code: result['closer_id'] = oa_users.REFERRAL_CODE_TO_OA_USER_ID.get( voucher_code, oa_users.DEFAULT_CLOSER_ID ) else: result['closer_id'] = oa_users.DEFAULT_CLOSER_ID correlation_id = input_data.get('correlation_id') or None dynamo_client = boto3.client('dynamodb', region_name=AWS_REGION) if correlation_id: response = dynamo_client.get_item( TableName=DYNAMO_TABLE, Key={ 'correlation_id': { 'S': correlation_id} } ) if response.get('Item'): logger.info( f'Correlation id {correlation_id} has already successfully executed. \ Skipping Step Function Execution.') vendor_id = response.get('Item')['vendor_id']['N'] get_vendor_result = ows_client.get( config.OWS_SERVICE_NAME, f'/vendor/{vendor_id}', headers=config.OWS_REQUEST_HEADERS ) parsed_result = get_vendor_result.json() extra_fields = { 'name': parsed_result.get('account_name') } return get_vendor_result.json() | extra_fields # log payload to ows-account after param manipulation logger.info( f'Sending update/create payload to ows-account: {result}' ) create_vendor_result = ows_client.patch( config.OWS_SERVICE_NAME, config.OWS_SERVICE_ENDPOINT, json=result, headers=config.OWS_REQUEST_HEADERS ) if create_vendor_result.status_code >= 300: logger.info( f'Error create vendor response \ status_code={create_vendor_result.status_code}' f' error={create_vendor_result.text} ') raise BadRequest('Invalid request.', create_vendor_result.text) vendor_id = create_vendor_result.json().get('vendor_id') set_correlation_id(correlation_id, result) set_restricted_features( 'add', vendor_id, list(DEFAULT_RESTRICTED_FEATURES) ) dynamo_client.put_item( TableName=DYNAMO_TABLE, Item={ 'correlation_id': { 'S': correlation_id }, 'vendor_id': { 'N': str(vendor_id) }, }, ReturnValues='ALL_OLD' ) return create_vendor_result.json() except ValidationError as err: logger.error('Invalid request.', err.messages) raise BadRequest('Invalid request.', err.messages)