"""Main entry point for SME extended metadata generation.""" import uuid from lxml import etree from owsclient import M2MTokenManager from secrets_manager.lambda_ext import LambdaSecretsManager import config from config import graphql_gateway from constants.generate_ddex import MARKETING_BLURB_PROGRAM_ID from constants.queries import ( GET_MARKETING_PROGRAM_INFO, PRODUCT_BY_UPC, SUBACCOUNT_WITH_SONY_METADATA, VENDOR_WITH_SONY_METADATA, ) from constants.vendors import SANTA_ANNA_VENDORS from ddex.e import E from ddex.product import generate_product from ddex.project import generate_project def fetch_sony_metadata(data: dict) -> dict: """Fetch Sony financial metadata from vendor or subaccount. Args: data: Product data containing label.id with vendorId and subaccountId. Returns: Sony financial metadata dict, or empty dict if not available. """ label_id = data.get('label', {}).get('id', {}) subaccount_id = label_id.get('subaccountId') vendor_id = label_id.get('vendorId') if isinstance(subaccount_id, int) and subaccount_id > 0: response = graphql_gateway.execute( SUBACCOUNT_WITH_SONY_METADATA, {'subaccountId': subaccount_id} ) subaccount = response.get('data', {}).get('subaccount', {}) return subaccount.get('sonyFinancialMetadata') or {} if vendor_id: response = graphql_gateway.execute( VENDOR_WITH_SONY_METADATA, {'vendorId': vendor_id} ) vendor = response.get('data', {}).get('vendor', {}) return vendor.get('sonyFinancialMetadata') or {} return {} def should_include_project(data: dict) -> bool: """Decide whether to include a Project node in the root OrchardMessage. Currently we only omit the Project node for Santa Anna vendor IDs. """ label_id = data.get('label', {}).get('id', {}) vendor_id = label_id.get('vendorId') if vendor_id in SANTA_ANNA_VENDORS: return False return True def handler(event, context): """Lambda entry point.""" m2m_token_manager = M2MTokenManager( secrets_manager=LambdaSecretsManager( environment=config.ENVIRONMENT, service_name=config.LAMBDA_NAME, ), environment=config.ENVIRONMENT, service_name=config.LAMBDA_NAME, leeway_seconds=60, ) token = m2m_token_manager.get_token_string() upc = event.get('pathParameters', {}).get('upc') if not upc: return {'statusCode': 400, 'body': 'UPC is required'} correlation_id = str(uuid.uuid4()) headers = { 'Orchard-User-Id': config.OA_USER, 'Correlation-Id': correlation_id, 'Authorization': f'Bearer {token}', } graphql_gateway.set_headers(headers) try: data = graphql_gateway.execute(PRODUCT_BY_UPC, {'upc': upc})['data'][ 'productByUpc' ] if data is None: return { 'statusCode': 404, 'body': f'Product not found for UPC: {upc}', } marketing_blurbs = graphql_gateway.execute( GET_MARKETING_PROGRAM_INFO, { 'productId': data.get('productId'), 'programId': MARKETING_BLURB_PROGRAM_ID, }, )['data']['getProductMarketingProgramInfoByProgram'] sony_metadata = fetch_sony_metadata(data) children = [] if should_include_project(data): children.append(generate_project(data)) children.append(generate_product(data, marketing_blurbs, sony_metadata)) root = E('OrchardMessage', {'Version': '1.0'}, *children) etree.indent(root, space=' ') xml_body = etree.tostring( root, encoding='utf-8', doctype='', pretty_print=True, ).decode('utf-8') return { 'statusCode': 200, 'headers': {'Content-Type': 'application/xml; charset=utf-8'}, 'body': xml_body, } except Exception as e: return { 'statusCode': 500, 'headers': {'Content-Type': 'text/plain; charset=utf-8'}, 'body': str(e), }