from collections.abc import Sequence from dataclasses import dataclass from anydi import singleton from fansifter_common.auth.services import AuthService from fansifter_common.auth.types import Permission from dmp.ad_reporting.dtos import ( AdReportingAdCriteria, AdReportingAdGroup, AdReportingSummary, ) from dmp.ad_reporting.handlers import GetAdReportingReportAdsRequest from dmp.ad_reporting.repositories import ( AdReportingAdRepository, ) from dmp.ad_reporting.services import ( AdReportingAccountService, AdReportingBenchmarkService, AdReportingReportService, ) @dataclass class GetAdReportingReportAdsGroupedResponse: items: Sequence[AdReportingAdGroup] total: int summary: AdReportingSummary @singleton class GetAdReportingReportAdsGroupedHandler: access_permission = Permission( "ad_campaign", "view" ) # TODO: upd after ad report logic change permission = Permission("ad_report", "view") def __init__( self, auth_service: AuthService, ad_repository: AdReportingAdRepository, account_service: AdReportingAccountService, report_service: AdReportingReportService, benchmark_service: AdReportingBenchmarkService, ) -> None: self.auth_service = auth_service self.ad_repository = ad_repository self.account_service = account_service self.report_service = report_service self.benchmark_service = benchmark_service def handle( self, request: GetAdReportingReportAdsRequest ) -> GetAdReportingReportAdsGroupedResponse: report = self.report_service.get_report( report_id=request.report_id, identity_id=request.identity_id, ) self.auth_service.check_owned_resource( report.identity_id, permission=self.permission, resource_id=report.id, ) if not report.campaign_ids: return GetAdReportingReportAdsGroupedResponse( items=[], summary=AdReportingSummary(), total=0 ) criteria = AdReportingAdCriteria( search=request.search, global_participant_id=request.global_participant_id, platform=request.platform, objective=request.objective, campaign_ids=( set(report.campaign_ids) if request.campaign_id is None else {request.campaign_id} ), ad_set_id=request.ad_set_id, countries=request.countries, ) summary = self.ad_repository.summary_by_criteria(criteria) if summary.total == 0: return GetAdReportingReportAdsGroupedResponse( items=[], summary=AdReportingSummary(), total=0 ) total = self.ad_repository.count_by_criteria_grouped(criteria) grouped_ads = self.ad_repository.find_by_criteria_grouped( criteria, order_by=request.order_by, limit=request.limit, offset=request.offset, ) self._calculate_total_actions_ratio(grouped_ads, summary) account_access = self.auth_service.authorize_for_permission( request.identity_id, permission=self.access_permission ) ad_account_labels = self.account_service.get_allowed_ad_account_labels( account_access=account_access, platform=request.platform, ) for ads_group in grouped_ads: for ad in ads_group.items: ad.accounts = ad_account_labels.get(ad.account_id, set()) ad.report_id = report.id ad.report_name = report.name if not request.countries or len(request.countries) <= 1: for ads_group in grouped_ads: self.benchmark_service.prefetch_campaign_benchmarks( items=ads_group.items, allowed_ad_account_labels=ad_account_labels, countries=request.countries, ) return GetAdReportingReportAdsGroupedResponse( summary=summary, items=grouped_ads, total=total, ) @staticmethod def _calculate_total_actions_ratio( grouped_ads: list[AdReportingAdGroup], summary: AdReportingSummary ) -> None: if not summary.actions: return for ads_group in grouped_ads: if ads_group.actions is not None: ads_group.total_actions_ratio = ads_group.actions / summary.actions