"""Geographic insights Logic.""" from datetime import timedelta from dateutil.parser import parse from oto import response as oto_response from analytics.consts import account as account_constants from analytics.models import product_summary from analytics.models import ows_account def get_product_summary( start_date, end_date, upc, search_filter, account_type, account_id, group_daily, transaction, include_growth): """Get geographics data by region from model layer. Args: start_date (str): Start date. end_date (str): End date. upc (list): An upc. search_filter (str): account_type (str): Grass account type. account_id (str): Grass account id. Returns: response.Response: containing the geographics data by region dict. """ if account_type == account_constants.SUBACCOUNT_TYPE: ows_account_response = ows_account.get_vendor_id_by_subaccount_id( account_id) if not ows_account_response: return ows_account_response subaccount_id = account_id account_id = ows_account_response.message else: subaccount_id = None previous_time_period = _compute_previous_time_period(start_date, end_date) result = product_summary.get_product_summary( start_date, end_date, upc, search_filter, account_id, subaccount_id, group_daily, transaction) if result.status != 200: return result if not group_daily and include_growth: previous_result = product_summary.get_product_summary( previous_time_period.start_date, previous_time_period.end_date, upc, search_filter, account_id, subaccount_id, group_daily, transaction) if previous_result.status == 200: return oto_response.Response( message=_calculate_product_summary_response( result.message, previous_result.message, transaction, search_filter ) ) return oto_response.Response( message=_calculate_product_summary_response( result.message, None, transaction, search_filter ) ) def _calculate_product_summary_response( current_result, previous_result, transaction, search_filter): """Calculate and format the response message for geographic insights. Args: current_geographics_result (list): current geographic insights previous_geographics_result (list): previous geographic insights Returns: dict: streams and listeners totals and growth and list of insights """ total_current_streams = _calculate_totals(current_result, transaction) total_previous_streams = _calculate_totals(previous_result, transaction) _calculate_increase_decrease_percentage(current_result, previous_result, transaction, search_filter) payload = { 'total_'+transaction: total_current_streams, 'items': current_result, 'total_growth': _calculate_percentage(total_current_streams, total_previous_streams) } return payload def _calculate_totals(items, transaction): """Calculate and return the total streams. Args: geographic_insights (list): List of dictionary of Geographic Insights Returns: total_streams (int): the total streams """ if not items: return 0 total_streams = sum( [item.get(transaction) for item in items]) return total_streams def _compute_previous_time_period(start_date, end_date): """Work out what the previous time period is and if there should be one. Args: start_date (str): Start date. end_date (str): End date. Returns: dict: start_date and end_date for previous period if there is one """ start_date_as_date = parse(start_date) end_date_as_date = parse(end_date) date_difference = end_date_as_date - start_date_as_date one_day = timedelta(days=1) return TimePeriod( (start_date_as_date - date_difference - one_day).strftime( '%Y-%m-%d'), (end_date_as_date - date_difference - one_day).strftime( '%Y-%m-%d')) def _calculate_increase_decrease_percentage( current, previous, transaction, search_filter): """Calculate inc/dec percentage for the current and previous time periods. Args: current (dict): Current insights result. previous (dict): Previous insights result. Returns: (dict): containing insights with growth percentage. """ if not previous: return matching_field_name = None if search_filter == 'by_store': matching_field_name = 'storeid' elif search_filter == 'by_country': matching_field_name = 'country_code' if not matching_field_name: if len(current) > 1 or len(previous) > 1: return current[0]['growth'] = ( _get_growth_percentage_from_insights( current[0], previous[0], transaction)) return for current_insight in current: current_streams = current_insight.get(transaction, None) current_code = current_insight.get(matching_field_name, None) if None in [current_code, current_streams]: continue for previous_insight in previous: previous_streams = previous_insight.get(transaction, None) previous_code = previous_insight.get(matching_field_name, None) if None in [previous_code, previous_streams]: continue if current_code != previous_code: continue current_insight['growth'] = ( _get_growth_percentage_from_insights( current_insight, previous_insight, transaction)) break return def _get_growth_percentage_from_insights( current_insight, previous_insight, attribute): """Calculate percentage for the current and previous numbers. Args: current_insight (dict): Current insight from which to get growth. previous_insight (dict): Previous insight from which to get growth. attribute (str): Property within dict from which to get growth. Returns: (int): containing the rounded signed percentage number. """ percentage = None current_streams = current_insight.get(attribute, None) previous_streams = previous_insight.get(attribute, None) if previous_streams and current_streams: percentage = _calculate_percentage( current_streams, previous_streams) return percentage def _calculate_percentage(current, previous): """Calculate percentage for the current and previous numbers. Args: current (int): Current number. previous (int): Previous number. Returns: (int): containing the rounded signed percentage number. """ if not previous: return None diff = current - previous growth_percentage = diff / previous * 100 return round(growth_percentage, 2) class TimePeriod: """Represents a time period with a start and end date.""" def __init__(self, start_date, end_date): """Initialise a time period.""" self.start_date = start_date self.end_date = end_date