"""Aggregate Stats Logic.""" from collections import OrderedDict from analytics.consts import analytics from analytics.utils import date def unpack_line(lines, series): """Unpack data from lines. For each line, get the timestamp and do some validation on the dataset before yielding each line. Args: lines (list): data of all the lines. series (dict): the list of the existing series. Yield: tuple: contains the timestamp (date) and the data of each point that has been validated (on each line, we have n points available.) """ for line in lines: for attribute_name, point in line.items(): if not attribute_name.isdigit(): continue line_date = '{}-{}'.format( line.get('month'), attribute_name.replace('day_', '')) timestamp = int(date.get(line_date).timestamp()) if timestamp not in series: continue yield timestamp, point def format_response(data, owner=None): """Return a default format response for analytics. This format response provides the necessary information for the frontend to display the totals, series and graph information (title). For the previous frontend of analytics, please see format_response_for_analytics_frontend. Optional: pass in owner. If the owner is passed in but the first row does not match any of the information, we break the response right away. Args: data (obj): the data that is coming back from the fetch. owner (tuple): the information about the owner (type of account and related id). Returns: dict: contains all the data. """ if not data: return lines = data.get('source') if not lines: return sum_activities = 0 transaction = data.get('transaction_type') date_start = data.get('date_start') date_end = data.get('date_end') series = date.create_empty_date_ranges(date_start, date_end) # Check owner information if owner: owner_id = lines[0].get(owner[0]) if not owner_id or owner_id != str(owner[1]): return for timestamp, point in unpack_line(lines, series): sum_activities += int(point.get('all')) series[timestamp] = int(point.get('all')) # The frontend requires the data to be ordered per day. series = OrderedDict(sorted(series.items(), key=lambda item: item[0])) return dict( total_units=int(sum_activities), transaction_abbr=transaction.abbr, transaction_name=transaction.name, sequence_id=transaction.sequence_id, series=list(series.items())) def format_response_for_analytics_frontend(data, owner=None): """Format the response for the current analytics frontend. Speeding up analytics with dynamodb requires us to write a response that is identical to the current StatsController response until we can start rewriting part of the frontend to consume lighter responses. A lot of this code needs to be refactored to be lighter. Args: data (obj): The data that is coming back from the fetch. Returns: dict: Matches the current StatsController response. """ if not data: return transaction_type = data.get('transaction_type') date_start = data.get('date_start') date_end = data.get('date_end') sum_activities = 0 sum_paid_activities = 0 lines = data.get('source') if not lines: return # Check owner information if owner: owner_id = lines[0].get(owner[0]) if not owner_id or owner_id != str(owner[1]): return all_activities = date.create_empty_date_ranges(date_start, date_end) for timestamp, line in unpack_line(lines, all_activities): sum_activities += int(line.get('all')) sum_paid_activities += int(line.get('paid')) all_activities[timestamp] = int(line.get('all')) # The frontend requires the data to be ordered per day. all_activities = OrderedDict( sorted(all_activities.items(), key=lambda item: item[0])) object_id = transaction_type.source_id or transaction_type.id # Social transaction provides a social_action_id that is not present on the # other dictionaries. line_extension = dict() if transaction_type.source_type == analytics.SOURCE_SOCIAL_MEDIA: line_extension.update( social_action_id=transaction_type.id) return dict( activities=int(sum_activities), date_scope=dict( point='day', mark='month', zebra='week'), # Refactor: this could just be one key instead of 4. object_id=object_id, sequence_id=transaction_type.sequence_id, transaction_type_id=transaction_type.id, stat_id=transaction_type.id, title=transaction_type.name, source_type=transaction_type.source_type, lines=[dict( # Some of those informations are already available in the parent. activities=int(sum_activities), activities_paid=int(sum_paid_activities), all_line=True, all_line_activities=int(sum_activities), display_date=date_start, name=transaction_type.name, title=transaction_type.name, total_reported_sales_count=[ [k, v] for k, v in all_activities.items()], transaction_type_abbr=transaction_type.abbr, transaction_type_id=transaction_type.id, # The frontend is not consistent when it comes to use this specific # data: it does not represent the object_id passed to the parent # dictionary. object_id=transaction_type.id, # Extensions. **line_extension)])