diff --git a/src/usecase/analytics/get_placements_analytics.py b/src/usecase/analytics/get_placements_analytics.py index 3b8b745..5614899 100644 --- a/src/usecase/analytics/get_placements_analytics.py +++ b/src/usecase/analytics/get_placements_analytics.py @@ -1,7 +1,9 @@ -import datetime import logging +import uuid from typing import TYPE_CHECKING +from tortoise import timezone + from src import domain, dto if TYPE_CHECKING: @@ -122,6 +124,35 @@ async def get_placements_analytics( else {} ) + # Collect (channel_id, message_id) pairs for batch next post lookup + channel_message_pairs = [ + (pp.post.channel_id, pp.post.message_id) + for p in placements + for pp in p.placement_posts + if pp.post and pp.post.published_at + ] + next_posts_map = ( + await self.database.get_next_posts_after_batch(channel_message_pairs) + if channel_message_pairs + else {} + ) + + # Calculate time_on_top for each placement_post + time_on_top_map: dict[uuid.UUID, int] = {} + now = timezone.now() + for placement in placements: + for pp in placement.placement_posts: + post = pp.post + if not post or not post.published_at: + continue + published_at = post.published_at + key = (post.channel_id, post.message_id) + next_post = next_posts_map.get(key) + if next_post and next_post.published_at: + time_on_top_map[pp.id] = int((next_post.published_at - published_at).total_seconds()) + else: + time_on_top_map[pp.id] = int((now - published_at).total_seconds()) + results: list[dto.PlacementAnalyticsOutput] = [] for placement in placements: placement_post = placement.placement_posts[0] if placement.placement_posts else None @@ -200,7 +231,7 @@ async def get_placements_analytics( views_count=views_count, cpf=cpf_value, cpm=cpm_value, - time_on_top=placement_post.time_on_top if placement_post else None, + time_on_top=time_on_top_map.get(placement_post.id) if placement_post else None, time_in_feed=None, invite_link=placement.invite_link, invite_link_created_at=placement.invite_link_created_at,