from flask import g from typing import List import utils.session_utils as session_utils from media_plan.repositories.media_plan_repository import MediaPlanRepository from models.campaign import Campaign from media_plan.schemas import ( CreateUpdatePhaseRequest, MediaPlanPhaseSchema, PhaseSchema ) from media_plan.phases_repository import MediaPlanPhasesRepository from projects.repositories.projects_repository import ProjectsRepository from media_plan.validators import PhaseValidator from services.project_history.history_service import HistoryService from campaigns.services.campaigns_service import CampaignsService from models.media_plan_phases import DEFAULT_PHASE_NAME from media_plan.exceptions import PhaseNotFound, SinglePhaseDeletionError from handlers.enums import CampaignWorkflowStatus from media_plan.services.media_plan_history_service import MediaPlanHistoryService, MediaPlanPhaseState class PhasesService: projects_repository: ProjectsRepository phases_repository: MediaPlanPhasesRepository media_plan_repository = MediaPlanRepository history_service: HistoryService phase_validator: PhaseValidator campaigns_service: CampaignsService media_plan_history_service: MediaPlanHistoryService def __init__( self, projects_repository: ProjectsRepository = ProjectsRepository(), phases_repository: MediaPlanPhasesRepository = MediaPlanPhasesRepository(), media_plan_repository: MediaPlanRepository = MediaPlanRepository(), history_service: HistoryService = HistoryService(), phase_validator: PhaseValidator = PhaseValidator(), campaigns_service: CampaignsService = CampaignsService(), media_plan_history_service: MediaPlanHistoryService = MediaPlanHistoryService() ): self.projects_repository = projects_repository self.phases_repository = phases_repository self.media_plan_repository = media_plan_repository self.history_service = history_service self.phase_validator = phase_validator self.campaigns_service = campaigns_service self.media_plan_history_service = media_plan_history_service def get_phase(self, media_plan_id: int, phase_id: int) -> MediaPlanPhaseSchema: phase = self.phases_repository.get_media_plan_phase_by_id(phase_id) if not phase: raise PhaseNotFound() return MediaPlanPhaseSchema(phase) def get_phases(self, media_plan_id: int) -> List[PhaseSchema]: phases = self.phases_repository.get_media_plan_phases(media_plan_id) return [PhaseSchema(phase) for phase in phases] def get_next_phase_order_number(self, media_plan_id: int) -> int: last_phase = self.phases_repository.get_last_media_plan_phase(media_plan_id) if last_phase is None: return 1 return last_phase.order + 1 def get_last_phase_order_number(self, media_plan_id: int) -> int: last_phase = self.phases_repository.get_last_media_plan_phase(media_plan_id) if last_phase is None: return 0 return last_phase.order + 1 def update_phase(self, project_id: int, phase_id: int, params: CreateUpdatePhaseRequest) -> MediaPlanPhaseSchema: phase = self.phases_repository.get_media_plan_phase_by_id(phase_id) old_phase = self.media_plan_history_service.get_media_plan_phase_state(phase) self.phases_repository.update_phase(phase_id=phase_id, name=params.name) self.media_plan_history_service.log_media_plan_phase_updated(phase, old_phase, g.user_id) self.projects_repository.touch_project_last_edit(project_id) session_utils.session_commit() return MediaPlanPhaseSchema(phase) def create_phase(self, project_id: int, media_plan_id: int, params: CreateUpdatePhaseRequest) -> MediaPlanPhaseSchema: media_plan = self.media_plan_repository.get_media_plan_by_id(media_plan_id) order = self.get_last_phase_order_number(media_plan_id) if params.order is not None: self.phase_validator.validate_user_order(order, params.order) order = params.order self.phases_repository.shift_phases(media_plan_id, start_order=order) phase = self.phases_repository.add_new_phase( name=params.name if params.name else DEFAULT_PHASE_NAME, media_plan_id=media_plan_id, order=order, ) phase.campaigns = [ Campaign( project_id=media_plan.project_id, order_in_phase=0, workflow_status=CampaignWorkflowStatus.DRAFT.value, create_user_id=g.user_id, uuid=params.campaign_uuid )] session_utils.session_flush() self.media_plan_history_service.log_media_plan_phase_created(phase, g.user_id) self.projects_repository.touch_project_last_edit(project_id) session_utils.session_commit() return MediaPlanPhaseSchema(phase) def delete_phase(self, project_id: int, media_plan_id: int, phase_id: int): phase = self.phases_repository.get_media_plan_phase_by_id(phase_id) if phase is None or phase.media_plan_id != media_plan_id: raise PhaseNotFound() all_phases = self.phases_repository.get_media_plan_phases(media_plan_id) if len(all_phases) == 1: raise SinglePhaseDeletionError() self.media_plan_history_service.log_media_plan_phase_deleted(phase, g.user_id) # soft phase campaigns delete for campaign in phase.campaigns: campaign.is_deleted = True campaign.media_plan_phase_id = None campaign.order_in_phase = None session_utils.session_flush() self.phases_repository.delete_phase(phase_id=phase_id) session_utils.session_flush() self.phases_repository.shift_phases(media_plan_id, phase.order, increase=False) self.projects_repository.touch_project_last_edit(project_id) session_utils.session_commit()