import asyncio from datetime import date, timedelta from typing import List, Optional from server.client import services from server.client.utils import str_to_date from server.constants import DSP from server.constants.charts import CHART_MIN_DATE, ChartBreakdown, ChartType from server.domains.charts.misc import get_chart_id def generate_response( analytics_data: List[dict], market: str, start_date: date, end_date: date, with_extra_date: bool ) -> List[dict]: """Generate GTP charts response. Args: analytics_data: Charts analytics data. market: Market code. start_date: Date range start - 1 day. end_date: Date range end. with_extra_date: With 1 additional day or from min date. Returns: GTP charts data. """ result = [] for item in analytics_data: min_date, max_date = str_to_date(item["min_date"]), str_to_date(item["max_date"]) result_positions = [] positions_data = item["metrics"]["positions"] # extract extra (-1 day) position extra_position = None if min_date == start_date and with_extra_date: extra_position = positions_data[0] positions_data = positions_data[1:] min_date = min_date + timedelta(days=1) previous_position = extra_position for index, position in enumerate(positions_data): if position is not None: result_positions.append( { "date": (min_date + timedelta(days=index)).isoformat(), "change": None if previous_position is None else position - previous_position, "position": position, } ) previous_position = position previous_position = positions_data[-2] if len(positions_data) > 1 else extra_position result.append( { "isrc": item["isrc"], "market": market, "start_date": min_date, "end_date": max_date, "positions": result_positions, "trend": result_positions[-1]["change"] if result_positions and max_date == end_date else None, "is_entered": ( result_positions and max_date == end_date and result_positions[-1]["position"] is not None and previous_position is None ), } ) return result async def get_chart( isrc_list: List[str], market: str, start_date: Optional[date], end_date: Optional[date], date_shift: Optional[int] ) -> dict: """GTP charts endpoint logic. Args: isrc_list: ISRC list. market: Market code. start_date: Date range start. end_date: Date range end. date_shift: Date shift. Returns: GTP charts response. """ chart_id = get_chart_id(market) if date_shift: end_date = end_date or start_date + timedelta(date_shift - 1) chart_available, latest_date = await asyncio.gather( *[ services.dsp.get_dsp_charts(dsp=DSP.SPOTIFY, chart_id=chart_id), services.dsp.get_charts_latest_date( dsp=DSP.SPOTIFY, chart_type=ChartType.REGIONAL.value, chart_breakdown=ChartBreakdown.DAILY.value, country_code=market, ), ], ) if not latest_date or not chart_available: return {"chart_available": bool(chart_available), "data": []} if not end_date or end_date > latest_date: end_date = latest_date if date_shift: start_date = end_date - timedelta(date_shift - 1) if start_date: # get 1 extra day to calculate 1st day trend start_date = start_date - timedelta(days=1) extra_date = True else: start_date = CHART_MIN_DATE[ChartBreakdown.DAILY] extra_date = False response = await services.dsp.get_charts_analytics( dsp=DSP.SPOTIFY.value, chart_id=chart_id, isrc=isrc_list, start_date=start_date, end_date=end_date, group_by="isrc", ) result = generate_response(response, market, start_date, end_date, extra_date) return {"chart_available": True, "data": result}