from dataclasses import dataclass, field from typing import Optional, List from models.media_plans import MediaPlan from models.media_plan_phases import MediaPlanPhase from models.campaign_approval import ApprovalRequest from services.project_history.history_service import HistoryService from media_plan.phases_repository import MediaPlanPhasesRepository from campaigns.services.campaigns_history_service import CampaignHistoryState, CampaignHistoryService from utils import list_utils @dataclass class MediaPlanPhaseState: id: int name: str order: int campaigns: List[CampaignHistoryState] def __init__(self, media_plan_phase): self.id = media_plan_phase.id self.name = media_plan_phase.name self.order = media_plan_phase.order self.campaigns = [CampaignHistoryState(campaign) for campaign in media_plan_phase.campaigns] @dataclass class MediaPlanHistoryState: id: int name: str order: int phases: List[MediaPlanPhaseState] @dataclass class ApprovalRequestHistoryState: id: int media_plan_id: int requester_id: int reviewer_id: int campaigns_uuids: List[str] def __init__(self, approval_request): self.id = approval_request.id self.media_plan_id = approval_request.media_plan_id self.requester_id = approval_request.requester_id self.reviewer_id = approval_request.reviewer_id self.campaigns_uuids = [ approval_request_campaign.campaign_uuid for approval_request_campaign in approval_request.approval_request_campaigns ] @dataclass class CampaignApprovalHistorySchema: campaign_approval_request_id: int campaign_uuid: str workflow_status: str @dataclass class SubmitApprovalHistoryState: campaigns: List[CampaignApprovalHistorySchema] class MediaPlanHistoryService: history_service = HistoryService() media_plan_phase_repository = MediaPlanPhasesRepository() campaign_history_service = CampaignHistoryService() def get_media_plan_state(self, media_plan: MediaPlan) -> MediaPlanHistoryState: old_phases = [MediaPlanPhaseState(media_plan_phase) for media_plan_phase in media_plan.phases] return MediaPlanHistoryState( id=media_plan.id, name=media_plan.name, order=media_plan.order, phases=old_phases, ) def get_media_plan_phase_state(self, phase: MediaPlanPhase): return MediaPlanPhaseState(phase) def log_media_plan_created( self, media_plan: MediaPlan, user_id: Optional[int] ): self.history_service.log_media_plan_created(media_plan, user_id) draft_phase = media_plan.phases[0] self.log_media_plan_phase_created(draft_phase, user_id) def log_media_plan_deleted( self, media_plan: MediaPlan, user_id: Optional[int] ): self.history_service.log_media_plan_deleted(media_plan, user_id) for phase in media_plan.phases: self.log_media_plan_phase_deleted(phase, user_id) def log_media_plan_updated(self, media_plan, media_plan_mask, user_id: Optional[int]): self.__log_media_plan_name_changed_if_needed(media_plan, media_plan_mask, user_id) self.__log_media_plan_order_changed_if_needed(media_plan, media_plan_mask, user_id) self.__log_media_plan_phases_changed_if_needed(media_plan, media_plan_mask, user_id) def __log_media_plan_name_changed_if_needed(self, media_plan, media_plan_mask, user_id: Optional[int]): if media_plan.name != media_plan_mask.name: self.history_service.log_media_plan_name_updated(media_plan, media_plan_mask.name, media_plan.name, user_id) def __log_media_plan_order_changed_if_needed(self, media_plan, media_plan_mask, user_id: Optional[int]): if media_plan.order != media_plan_mask.order: self.history_service.log_media_plan_order_updated( media_plan, media_plan.order, media_plan_mask.order, user_id ) def log_media_plan_phase_created(self, phase, user_id: Optional[int]): self.history_service.log_media_plan_phase_created(phase.media_plan, MediaPlanPhaseState(phase), user_id) territories_state = self.campaign_history_service.get_territories_state(phase.media_plan.project_id) self.campaign_history_service.log_campaign_created(phase.campaigns[0], territories_state, user_id) def log_media_plan_phase_deleted(self, phase, user_id: Optional[int]): self.history_service.log_media_plan_phase_deleted(phase.media_plan, MediaPlanPhaseState(phase), user_id) territories_state = self.campaign_history_service.get_territories_state(phase.media_plan.project_id) for campaign in phase.campaigns: self.campaign_history_service.log_campaign_deleted(campaign, territories_state, user_id) def log_media_plan_phase_updated(self, phase, phase_mask, user_id: Optional[int]): if phase.name != phase_mask.name: self.history_service.log_media_plan_phase_name_updated( media_plan=phase.media_plan, old_value=phase_mask.name, new_value=phase.name, user_id=user_id ) def __log_media_plan_phases_changed_if_needed(self, media_plan, media_plan_mask, user_id: Optional[int]): old_phases_ids = [phase.id for phase in media_plan_mask.phases] new_phases_ids = [phase.id for phase in media_plan.phases] if list_utils.has_changes(old_phases_ids, new_phases_ids): removed_id = set(old_phases_ids) - set(new_phases_ids) if removed_id: removed_media_plan_phase = list(filter(lambda p: p.id == removed_id, media_plan_mask.phases))[0] self.log_media_plan_phase_deleted(removed_media_plan_phase, user_id) new_ids = set(new_phases_ids) - set(old_phases_ids) if new_ids: added_media_plan_phase = list(filter(lambda p: p.id in new_ids, media_plan.phases))[0] self.log_media_plan_phase_created(added_media_plan_phase, user_id) def log_approval_request(self, approval_request: ApprovalRequest, user_id: Optional[int]): approval_request_mask = ApprovalRequestHistoryState(approval_request) self.history_service.log_approval_request_created( approval_request.media_plan.project_id, approval_request_mask, user_id ) def log_submit_approval( self, project_id, media_plan_id, campaigns_approval_history: List[CampaignApprovalHistorySchema], user_id: Optional[int] ): submit_approval_history = SubmitApprovalHistoryState(campaigns_approval_history) self.history_service.log_submit_approval(project_id, media_plan_id, submit_approval_history, user_id)