import decimal from dataclasses import dataclass from typing import Any from anydi import singleton from fansifter_common.auth.types import Permission from pydantic import TypeAdapter from dmp.adapters.db import ReportingDB from dmp.artists.cache import ArtistCache, cached_artist_data from dmp.artists.dtos import FansShareByAgeRange from dmp.artists.requests import ArtistFanReportFilterRequest from dmp.artists.services import ArtistAccessService from dmp.fandata.enums import AgeRange @dataclass class GetArtistFansShareByAgeRangeRequest(ArtistFanReportFilterRequest): countries: list[str] | None = None @dataclass class GetArtistFansShareByAgeRangeResponse: available_fans_share: decimal.Decimal items: list[FansShareByAgeRange] AgeRangeFansShareListValidator = TypeAdapter(list[FansShareByAgeRange]) @singleton class GetArtistFansShareByAgeRangeHandler: permission = Permission("fan_data_list", "view") def __init__( self, db: ReportingDB, artist_access_service: ArtistAccessService, artist_cache: ArtistCache, ) -> None: self.db = db self.artist_access_service = artist_access_service self.artist_cache = artist_cache def handle( self, request: GetArtistFansShareByAgeRangeRequest ) -> GetArtistFansShareByAgeRangeResponse: artist_access = self.artist_access_service.check_artist_access( request.identity_id, request.global_participant_id, request.account, permission=self.permission, ) available_fans_share = self._get_available_fans_share( request.global_participant_id, vendor_id=request.vendor_id, subaccount_id=request.subaccount_id, countries=request.countries, is_global=artist_access.is_global, ) age_ranges = self._get_age_ranges( request.global_participant_id, vendor_id=request.vendor_id, subaccount_id=request.subaccount_id, countries=request.countries, is_global=artist_access.is_global, ) if max(age_range.fans_share for age_range in age_ranges) == 0: age_ranges = [] return GetArtistFansShareByAgeRangeResponse( available_fans_share=available_fans_share, items=age_ranges, ) @cached_artist_data("age-range-available-fans-share") def _get_available_fans_share( self, global_participant_id: str, vendor_id: int | None, subaccount_id: int | None, countries: list[str] | None, is_global: bool, ) -> decimal.Decimal: context = self._get_query_context( vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, countries=countries, is_global=is_global, ) if countries: template_name = ( "artist/get-artist-age-range-available-fans-share-by-country.sql" ) else: template_name = "artist/get-artist-age-range-available-fans-share.sql" query = self.db.query_from_template(template_name, context=context) return decimal.Decimal(self.db.session.execute(query).scalar_one_or_none() or 0) @cached_artist_data("fans-share-by-age-range") def _get_age_ranges( self, global_participant_id: str, vendor_id: int | None, subaccount_id: int | None, countries: list[str] | None, is_global: bool, ) -> list[FansShareByAgeRange]: context = self._get_query_context( vendor_id=vendor_id, subaccount_id=subaccount_id, global_participant_id=global_participant_id, countries=countries, is_global=is_global, ) if countries: template_name = "artist/get-artist-fans-share-by-age-range-country.sql" else: template_name = "artist/get-artist-fans-share-by-age-range.sql" query = self.db.query_from_template(template_name, context=context) result = self.db.session.execute(query).mappings() return AgeRangeFansShareListValidator.validate_python(result) @staticmethod def _get_query_context( vendor_id: int | None, subaccount_id: int | None, global_participant_id: str, countries: list[str] | None, is_global: bool, ) -> dict[str, Any]: return { "vendor_id": vendor_id, "subaccount_id": subaccount_id, "global_participant_id": global_participant_id, "age_range_enum": AgeRange, "countries": countries, "is_global": is_global, }