"""Product utils.""" from datetime import datetime from datetime import timezone import json from content_utils.constants.product import STATUS_MAP def get_lock_fields(review_queue_item): """Get fields related to locking.""" fields = { 'locked_by_user_id': None, 'locked_until_datetime': None } if not review_queue_item: return fields if review_queue_item.get('lockedByUserId'): fields['locked_by_user_id'] = review_queue_item.get('lockedByUserId') if review_queue_item.get('lockedUntilDatetime'): fields['locked_until_datetime'] = review_queue_item.get('lockedUntilDatetime') return fields def get_queue_fields(review_queue_item): """Get fields related to the queue review_queue_item is in.""" queue_fields = { 'queue_name': None, 'moved_to_queue_by_user_id': None, 'moved_to_queue_by_user_name': None, 'moved_to_target_email': None, 'moved_to_target_id': None, 'moved_to_target_name': None, 'moved_to_group_name': None, 'escalation_type': None, 'submission_datetime': None, } if not review_queue_item: return queue_fields queue_fields['queue_name'] = review_queue_item['queueName'] queue_fields['submission_datetime'] = review_queue_item.get('submissionDatetime') moved_to_queue_by_identity = review_queue_item['movedToQueueByIdentity'] if not moved_to_queue_by_identity: return queue_fields user_id = moved_to_queue_by_identity['id'] user_first_name = (moved_to_queue_by_identity['firstName'] or '').strip() user_last_name = (moved_to_queue_by_identity['lastName'] or '').strip() moved_to_target_email = review_queue_item.get('movedToTargetEmail') moved_to_target_name = review_queue_item.get('movedToTargetName') moved_to_target_id = ( format_moved_to_target_id(moved_to_target_name) if moved_to_target_name else None ) moved_to_group_name = None escalation_type = None if review_queue_item.get('movedToTarget'): moved_to_group_name = review_queue_item['movedToTarget']['targetGroup']['displayName'] escalation_type = review_queue_item['movedToTarget']['escalationType'] return { **queue_fields, 'moved_to_queue_by_user_id': user_id, 'moved_to_queue_by_user_name': f'{user_first_name} {user_last_name}'.strip() or None, 'moved_to_target_email': moved_to_target_email, 'moved_to_target_id': moved_to_target_id, 'moved_to_target_name': moved_to_target_name, 'moved_to_group_name': moved_to_group_name, 'escalation_type': escalation_type } def get_indexable_document(row_data, product_metadata, review_queue_item=None): """Build an indexable product.""" account_names = get_account_names_from_metadata(product_metadata) artist_names = get_artist_names_from_metadata(product_metadata) label_owner = get_label_owner_from_metadata(product_metadata) account_country = get_account_country_from_metadata(product_metadata) account_country_code = get_account_country_code_from_metadata(product_metadata) bulk_session_id = get_bulk_session_id_from_metadata(product_metadata) label_id = product_metadata.get('label').get('id').get('vendorId') subaccount_id = product_metadata.get('label').get('id').get('subaccountId') metadata_language = product_metadata.get('metadataLanguage') if metadata_language is None: metadata_language = {} notices = get_notices(product_metadata) submission_count = get_submission_count(row_data, review_queue_item) submission_type = get_submission_type(review_queue_item) service_tier = get_vendor_service_tier(product_metadata) genre_id, genre_name = get_genre_from_metadata(product_metadata) if service_tier is None: service_tier = {} company_brand = get_vendor_company_brand(product_metadata) assigned_to_id, assigned_to_name = get_assigned_to_details(product_metadata) secondary_contact_id, secondary_contact_name = get_secondary_contact_details(product_metadata) assigned_reviewer_id, assigned_reviewer_name = get_assigned_reviewer_details(product_metadata) release_correction_status = get_release_correction_status(product_metadata) added_at = row_data.get('added_at') if row_data.get('added_at') is None and review_queue_item is not None: added_at = review_queue_item.get('createdDatetime') product_document = { 'added_at': get_added_at_datetime(added_at), 'account_id': f'{label_id}:{subaccount_id}', 'account_name': account_names.get('account'), 'account_country': account_country, 'account_country_code': account_country_code, 'assigned_reviewer_id': assigned_reviewer_id, 'assigned_reviewer_name': assigned_reviewer_name, 'assigned_to_id': assigned_to_id, 'assigned_to_name': assigned_to_name, 'bulk_session_id': bulk_session_id, 'company_brand': company_brand, 'company_brand_name': company_brand.get('name'), 'company_brand_display_name': company_brand.get('displayName'), 'company_brand_uuid': company_brand.get('uuid'), 'configuration': product_metadata.get('productConfiguration'), 'display_status': product_metadata.get('displayStatus'), 'distribution_format_id': product_metadata.get('distributionFormatId'), 'featuring_artist': ', '.join(artist_names.get('featuring')), 'format': product_metadata.get('format'), 'genre_id': genre_id, 'genre_name': genre_name, 'image_location': product_metadata.get('imageLocation'), 'imprint': product_metadata.get('imprint'), 'label_id': label_id, 'label_name': account_names.get('label'), 'label_owner': label_owner, 'metadata_language_code': metadata_language.get('code'), 'metadata_language_name': metadata_language.get('name'), 'notices': notices, 'preorder_date': product_metadata.get('preorderDate'), 'primary_artist': ', '.join(artist_names.get('primary_artist')), 'product_id': row_data.get('product_id') or product_metadata.get('productId'), 'product_name': product_metadata.get('productName'), 'release_correction_status': release_correction_status, 'review_queue_id': row_data.get('review_queue_id'), **get_queue_fields(review_queue_item), **get_lock_fields(review_queue_item), 'sale_start_date': product_metadata.get('saleStartDate'), 'secondary_internal_contact_id': secondary_contact_id, 'secondary_internal_contact_name': secondary_contact_name, 'service_tier_name': service_tier.get('displayName'), 'service_tier_uuid': service_tier.get('uuid'), 'special_instructions': product_metadata.get('specialInstructions'), 'subaccount_id': subaccount_id, 'subaccount_name': account_names.get('subaccount'), 'submission_count': submission_count, 'submission_type': submission_type, 'upc': product_metadata.get('upc'), 'version': product_metadata.get('version'), } return product_document def get_genre_from_metadata(product_metadata): """Get genre from metadata.""" subgenre = product_metadata.get('subgenre') or {} genre = subgenre.get('genre') or {} return genre.get('id', 0), genre.get('name', '') def get_added_at_datetime(added_at): """Handle string and integer timestamps.""" if not added_at or isinstance(added_at, str): return added_at try: added_at_datetime = datetime.fromtimestamp(added_at / 1000) except ValueError: added_at_datetime = datetime.fromtimestamp(added_at / 1000000) return added_at_datetime.astimezone(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ') def get_release_correction_status(product_metadata): """Get release correction status.""" correction_data = product_metadata.get('releaseCorrection') if correction_data and 'status' in correction_data: return correction_data['status'] return '' def format_product_corrections(corrections): """Format release corrections response.""" fields_dict = { 'release_name': 'product_name', 'meta_language': 'metadata_language_code', 'label': 'imprint', 'featuring': 'featuring_artist', 'performer': 'primary_artist', 'coverart': 'image_location', 'genre_id': 'genre_id', } formatted_corrections = {} for correction in corrections: field_name = fields_dict.get(correction['fieldName']) if correction['tableName'] != 'releases' or field_name is None: continue new_correction = json.loads(correction['keyValue']) if field_name in ['featuring_artist', 'primary_artist']: role = 'performer' if field_name == 'primary_artist' else 'featuring' artists = [ item['artistName'] for item in new_correction if item['role'] == role ] formatted_corrections[field_name] = ', '.join(artists) else: formatted_corrections[field_name] = new_correction return formatted_corrections def get_base_product(row_data, product_metadata): """Build a base product object.""" indexable_document = get_indexable_document(row_data, product_metadata) base_product_keys = { 'company_brand', 'configuration', 'display_status', 'distribution_format_id', 'format', 'label_id', 'label_owner', 'product_id', 'product_name', 'release_correction_status', 'service_tier_name', 'service_tier_uuid', 'subaccount_id', 'upc', 'assigned_to_id', 'assigned_reviewer_id' } return { product_key: product_value for product_key, product_value in indexable_document.items() if product_key in base_product_keys } def get_notices(product_metadata): """Get an array of notices from product metadata.""" notices = [] for level in ['errors', 'warnings']: for product_validation in ( product_metadata.get('validation', {}).get(level, [])): notices.append(format_notice(product_validation, level)) for track in product_metadata.get('tracks', []): for track_validation in track.get('validation').get(level): notices.append(format_notice(track_validation, level)) return notices def format_notice(notice, level): """Format a notice for the ES index.""" return { 'level': level, 'code': notice.get('code'), 'reason': notice.get('reason') } def get_artist_names_from_metadata(product_metadata): """Get artist names from product metadata.""" names = { 'primary_artist': [], 'featuring': [], } for artist in product_metadata.get('artists') or []: if artist.get('artistType') in names: names[artist.get('artistType')].append(artist.get('artistName')) return names def get_label_owner_from_metadata(product_metadata): """Get label owner from product metadata.""" if product_metadata['label'].get('vendor'): return product_metadata['label']['vendor']['owner'] return product_metadata['label']['owner'] def get_submission_type(review_queue_item): """Get submission type from product data.""" if not review_queue_item: return None return STATUS_MAP.get(review_queue_item.get('submissionType')) def get_submission_count(row_data, review_queue_item): """Get submission count from input.""" if row_data and 'submission_count' in row_data: return row_data['submission_count'] if review_queue_item: return review_queue_item['submissionCount'] return 1 def get_vendor_service_tier(product_metadata): """Get vendor service tier from product data.""" if product_metadata['label'].get('vendor'): return product_metadata['label'].get('vendor')['serviceTier'] return product_metadata['label']['serviceTier'] def get_vendor_company_brand(product_metadata): """Get vendor company brand from product data.""" if product_metadata['label'].get('vendor'): return product_metadata['label'].get('vendor')['companyBrand'] return product_metadata['label']['companyBrand'] def get_account_names_from_metadata(product_metadata): """Get account names from product metadata.""" names = { 'label': product_metadata.get('label').get('name'), 'subaccount': '', 'account': product_metadata.get('label').get('name') } if 'vendor' in product_metadata.get('label'): names.update({ 'label': product_metadata.get('label').get('vendor').get('name'), 'subaccount': product_metadata.get('label').get('name') }) return names def get_account_country_from_metadata(product_metadata): """Get account country from product metadata.""" if product_metadata['label'].get('vendor'): return product_metadata['label']['vendor'].get('country') return product_metadata['label'].get('country') def get_account_country_code_from_metadata(product_metadata): """Get account country code from product metadata.""" if product_metadata['label'].get('vendor'): return product_metadata['label']['vendor'].get('countryCode') return product_metadata['label'].get('countryCode') def get_bulk_session_id_from_metadata(product_metadata): """Get bulk session id from product metadata.""" if product_metadata.get('bulkSession'): if product_metadata['bulkSession'].get('ingestion'): ingestion = product_metadata['bulkSession'].get('ingestion') # Only return the bulk session id if the number of submitted products is greater than 1 if ingestion.get('submittedProductsCount') > 1: return product_metadata['bulkSession'].get('id') return None def get_assigned_to_details(product_metadata): """Get assigned to name from product metadata.""" assigned_to = product_metadata['label'].get('assignedTo') if product_metadata['label'].get('vendor'): assigned_to = product_metadata['label'].get('vendor').get('assignedTo') return format_assigned_to(assigned_to) def get_secondary_contact_details(product_metadata): """Get secondary internal contact from product metadata.""" assigned_to = product_metadata['label'].get('secondaryInternalContact') if product_metadata['label'].get('vendor'): assigned_to = product_metadata['label'].get('vendor').get('secondaryInternalContact') return format_assigned_to(assigned_to) def get_assigned_reviewer_details(product_metadata): """Get assigned reviewer name from product metadata.""" assigned_to = product_metadata['label'].get('assignedReviewer') if product_metadata['label'].get('vendor'): assigned_to = product_metadata['label'].get('vendor').get('assignedReviewer') return format_assigned_to(assigned_to) def format_assigned_to(assigned_to): """Parse common assigned-to structure into an id and name.""" assigned_to_id = 0 assigned_to_name = '' if assigned_to: if assigned_to.get('id'): assigned_to_id = assigned_to.get('id') if assigned_to.get('firstName') or assigned_to.get('lastName'): assigned_to_name = f'{assigned_to.get("firstName")} {assigned_to.get("lastName")}' return assigned_to_id, assigned_to_name.strip() def format_moved_to_target_id(moved_to_target_name): """Format moved_to_target_id into .""" formatted_string = moved_to_target_name.lower().replace(' ', '_') formatted_string = ''.join(c for c in formatted_string if c.isalnum() or c == '_') return formatted_string def get_complete_product_document(product_metadata): """Build a complete product document from the complete product query.""" document = { 'product_id': product_metadata.get('productId'), 'product_name': product_metadata.get('productName'), 'product_code': product_metadata.get('productCode'), 'imprint': product_metadata.get('imprint'), 'upc': product_metadata.get('upc'), 'delivered_version': product_metadata.get('deliveredVersion'), 'format': product_metadata.get('format'), 'version': product_metadata.get('version'), 'c_line': product_metadata.get('cLine'), 'special_instructions': product_metadata.get('specialInstructions'), 'image_location': product_metadata.get('imageLocation'), 'release_date': product_metadata.get('releaseDate'), 'sale_start_date': product_metadata.get('saleStartDate'), 'preorder_date': product_metadata.get('preorderDate'), 'previewable': product_metadata.get('previewable'), } metadata_language = product_metadata.get('metadataLanguage') document['metadata_language'] = { 'code': metadata_language.get('code'), 'name': metadata_language.get('name') } if metadata_language else None bulk_session = product_metadata.get('bulkSession') document['bulk_session'] = { 'id': bulk_session.get('id'), 'ingestion': bulk_session.get('ingestion') } if bulk_session else None label = product_metadata.get('label') if label: label_id = label.get('id', {}) document['label'] = { 'vendor_id': label_id.get('vendorId'), 'subaccount_id': label_id.get('subaccountId'), 'name': label.get('name'), 'country_code': label.get('countryCode'), 'content_review_note': label.get('contentReviewNote'), 'service_tier': None, 'vendor': None, } service_tier = label.get('serviceTier') if service_tier: document['label']['service_tier'] = { 'name': service_tier.get('name'), 'display_name': service_tier.get('displayName') } vendor = label.get('vendor') if vendor: document['label']['vendor'] = { 'name': vendor.get('name'), 'content_review_note': vendor.get('contentReviewNote'), 'service_tier': None, } vendor_service_tier = vendor.get('serviceTier') if vendor_service_tier: document['label']['vendor']['service_tier'] = { 'name': vendor_service_tier.get('name'), 'display_name': vendor_service_tier.get('displayName') } else: document['label'] = None document['label_participations'] = product_metadata.get('labelParticipations') or [] document['product_localizations'] = product_metadata.get('productLocalizations') or [] document['artists'] = product_metadata.get('artists') or [] document['tracks'] = product_metadata.get('tracks') or [] validation = product_metadata.get('validation') document['validation'] = validation if validation else None review_history = product_metadata.get('reviewHistory') document['review_history'] = review_history if review_history else None subgenre = product_metadata.get('subgenre') if subgenre: document['subgenre'] = { 'id': subgenre.get('id'), 'name': subgenre.get('name'), 'genre': None, } genre = subgenre.get('genre') if genre: document['subgenre']['genre'] = { 'id': genre.get('id'), 'name': genre.get('name') } else: document['subgenre'] = None # Handle pricing tiers album_pricing_tier = product_metadata.get('albumPricingTier') document['album_pricing_tier'] = album_pricing_tier if album_pricing_tier else None track_pricing_tier = product_metadata.get('trackPricingTier') document['track_pricing_tier'] = track_pricing_tier if track_pricing_tier else None document['release_schedule'] = product_metadata.get('releaseSchedule') document['release_correction'] = product_metadata.get('releaseCorrection') return document