"""Demographic insights Logic.""" import collections from oto import response as oto_response from oto import status from analytics.consts import account as account_constants from analytics.consts import analytics from analytics.models import demographics from analytics.models import ows_account def get_demographic_insights( store_ids, feed_ids, start_date, end_date, account_type, account_id, isrcs=None, artist_ids=None, territory_code=None, distributors=None, top_audiences_size=5): """Get demographic insights. Args: store_ids (list[int]): list of store ids. feed_ids (list): list of available feed ids. start_date (str): start date (YYYY-MM-DD). end_date (str): end date (YYYY-MM-DD). account_type: Grass account type. account_id: Grass account id. isrcs (list[str]): list of track ISRCs. artist_ids (list[int]): list of artist ids. territory_code (str): territory code distributors(list[str]): list of distributors names. top_audiences_size (int): number of top cohorts. Returns: oto.Response: demographic insights data. """ if account_type == account_constants.SUBACCOUNT_TYPE: subaccountid = account_id ows_account_response = ows_account.get_vendor_id_by_subaccount_id( subaccount_id=subaccountid) if not ows_account_response: return ows_account_response labelid = ows_account_response.message else: subaccountid = None labelid = account_id cohorts_response = demographics.get_cohorts( store_ids, feed_ids, start_date, end_date, labelid=labelid, subaccountid=subaccountid, isrcs=isrcs, artist_ids=artist_ids, territory_code=territory_code, distributors=distributors) if not cohorts_response or cohorts_response.status == status.NO_CONTENT: return cohorts_response response = format_response_for_analytics_frontend( cohorts_response.message, top_audiences_size) return oto_response.Response(response) def _whole_percent(numerator, denominator): """Safely divide integers. numerator and denominator Args: numerator (int) denominator (int) Returns: int: whole number of percents """ if not denominator: return 0 return round(100 * numerator / denominator) def _get_age_breakdown(cohorts): """Get age breakdown data. Args: cohorts (list[demographics.Cohort]): Data from the fetch. Returns: list: List of age groups with extra data """ total_streams_number = 0 age_breakdown = collections.OrderedDict() for cohort in cohorts: total_streams_number += cohort.streams streams_gender_key = '{}_streams_number'.format(cohort.gender) if cohort.age_group not in age_breakdown: age_breakdown[cohort.age_group] = collections.defaultdict(int) age_breakdown[cohort.age_group][streams_gender_key] += cohort.streams age_breakdown[cohort.age_group]['all_streams_number'] += cohort.streams return [ { 'age_group': age_group, 'women_streams_number': group_data['women_streams_number'], 'women_percentage': _whole_percent( group_data['women_streams_number'], total_streams_number), 'men_streams_number': group_data['men_streams_number'], 'men_percentage': _whole_percent( group_data['men_streams_number'], total_streams_number), 'all_streams_number': group_data['all_streams_number'], 'all_percentage': _whole_percent( group_data['all_streams_number'], total_streams_number), } for age_group, group_data in age_breakdown.items() ] def _get_gender_breakdown(cohorts): """Get gender breakdown data. Args: cohorts (list[demographics.Cohort]): Data from the fetch. Returns: dict: Gender breakdown data """ gender_breakdown = collections.defaultdict(int) for cohort in cohorts: streams_gender_key = '{}_streams_number'.format(cohort.gender) gender_breakdown['streams_number'] += cohort.streams or 0 gender_breakdown[streams_gender_key] += cohort.streams or 0 if 'streams_number' not in gender_breakdown: gender_breakdown['streams_number'] = 0 for gender in analytics.GENDERS: gender_breakdown['{}_percentage'.format(gender)] = _whole_percent( gender_breakdown['{}_streams_number'.format(gender)], gender_breakdown['streams_number']) return dict(gender_breakdown) def _get_top_audiences(cohorts, top_audiences_size): """Create top audiences list from cohorts. Args: cohorts (list[demographics.Cohort]): Data from the fetch. top_audiences_size (int): Size of top_audiences list Returns: dict: List of top audiences """ sorted_cohorts = sorted( cohorts, key=lambda cohort: cohort.streams, reverse=True) total_streams_number = sum(cohort.streams for cohort in cohorts) return [ { 'gender': cohort.gender, 'age_group': cohort.age_group, 'total_streams_number': cohort.streams, 'percentage': _whole_percent( cohort.streams, total_streams_number), } for cohort in sorted_cohorts[:top_audiences_size] ] def format_response_for_analytics_frontend(cohorts, top_audiences_size=5): """Format the response for the current analytics frontend. Args: cohorts (list[demographics.Cohort]): Data from the fetch. top_audiences_size (int): Size of top_audiences list Returns: dict: Demographic insights response. """ return { 'gender_breakdown': _get_gender_breakdown(cohorts), 'age_breakdown': _get_age_breakdown(cohorts), 'top_audiences': _get_top_audiences(cohorts, top_audiences_size), }