U
    oԐhl                     @   s  d Z ddlmZ ddlmZ ddlmZmZ ddlm	Z	 ddl
mZ ddlmZ ddlmZmZmZ dd	lmZ dd
lmZmZ ddlZddlmZ ddlmZ ddlmZmZmZ ddl m!Z!m"Z"m#Z#m$Z$ e%e&Z'G dd dZ(G dd dZ)G dd dej*Z+G dd dej*Z,G dd dej*Z-G dd dej*Z.G dd dej*Z/G dd deZ0G d d! d!eZ1G d"d# d#eZ2G d$d% d%eZ3G d&d' d'eZ4d(d) Z5d*d+ Z6d1d-d.Z7G d/d0 d0Z8dS )2a  
Django models for broadcast playlist and advertising management system.

This module contains models that manage the lifecycle of broadcast playlists,
advertising windows, avails, ad spots placement, and verification data for
a television/media broadcasting platform.

Models hierarchy:
    Playlists -> Windows -> Avails -> AdspotsInAvail
    
Author: Development Team
Created: [Date]
Last Modified: [Date]
Version: 1.1 - Applied all TODO improvements
    )default)models)MinValueValidatorMaxValueValidator)ValidationError)timezone)gettext_lazy)QCountSum)ContentType)timedatetimeN)	BaseModel)Adspots)ChannelChannelZoneChannelZoneRelation)convert_date_string_to_date#convert_duration_string_to_durationconvert_time_string_to_timeplaylist_xml_upload_pathc                   @   s0   e Zd ZdZdZdZeedfeedfgZdS )PlaylistStatusz%Constants for playlist status values.   r   Draft	PublishedN)__name__
__module____qualname____doc__DRAFT	PUBLISHED_CHOICES r$   r$   0/var/www/html/Focus/src/apps/playlists/models.pyr   )   s   

r   c                   @   sL   e Zd ZdZdZdZdZdZeedfeedfeedfeed	fgZ	d
S )VerificationStatusz)Constants for verification status values.pendingcompletefailedpartialPendingCompleteFailedZPartialN)
r   r   r   r   PENDINGZCOMPLETEFAILEDPARTIALr"   r#   r$   r$   r$   r%   r&   5   s   



r&   c                   @   s8   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d ZdS )PlaylistManagerz=Custom manager for Playlists model with useful query methods.c                 C   s   | j tjdS )zGet only published playlists.is_draft)filterr   r!   selfr$   r$   r%   	publishedI   s    zPlaylistManager.publishedc                 C   s   | j tjdS )zGet only draft playlists.r2   )r4   r   r    r5   r$   r$   r%   draftsM   s    zPlaylistManager.draftsc                 C   s   | j |dS )z%Get playlists for a specific channel.)
channel_idr4   )r6   r9   r$   r$   r%   for_channelQ   s    zPlaylistManager.for_channelc                 C   s*   |  t||dt||dB t||dB S )z+Get playlists within a specific date range.)Zstart_date__gtestart_date__lte)end_date__gteZend_date__lte)r<   r=   )r4   r	   )r6   
start_dateend_dater$   r$   r%   for_date_rangeU   s    


zPlaylistManager.for_date_rangec                 C   s   t  }| j||tjdS )z(Get playlists that are currently active.)r<   r=   r3   )r   nowr4   r   r!   r6   rA   r$   r$   r%   
active_now]   s    zPlaylistManager.active_nowN)	r   r   r   r   r7   r8   r;   r@   rC   r$   r$   r$   r%   r1   F   s   r1   c                   @   s(   e Zd ZdZdd Zdd Zdd ZdS )	WindowsManagerz!Custom manager for Windows model.c                 C   s   | j |dS )z$Get windows for a specific playlist.)playlist_idr:   )r6   rE   r$   r$   r%   for_playlistj   s    zWindowsManager.for_playlistc                 C   s   | j dd S )zGet windows that have avails.F)Zavails__isnullr4   distinctr5   r$   r$   r%   with_availsn   s    zWindowsManager.with_availsc                 C   s
   |  dS )zOrder windows by start time.window_startorder_byr5   r$   r$   r%   by_start_timer   s    zWindowsManager.by_start_timeN)r   r   r   r   rF   rI   rM   r$   r$   r$   r%   rD   g   s   rD   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )AvailsManagerz Custom manager for Avails model.c                 C   s   | j |dS )z!Get avails for a specific window.)	window_idr:   )r6   rO   r$   r$   r%   
for_windowz   s    zAvailsManager.for_windowc                 C   s   | j dd S )z%Get avails that have ad spots placed.FZadspots_in_avail__isnullrG   r5   r$   r$   r%   with_adspots~   s    zAvailsManager.with_adspotsc                 C   s   | j ddS )z;Get avails that have no ad spots (available for placement).TrQ   r:   r5   r$   r$   r%   	available   s    zAvailsManager.availablec                 C   s
   |  dS )zOrder avails by start time.avail_startrK   r5   r$   r$   r%   rM      s    zAvailsManager.by_start_timeN)r   r   r   r   rP   rR   rS   rM   r$   r$   r$   r%   rN   w   s
   rN   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )AdSpotsInAvailManagerz(Custom manager for AdspotsInAvail model.c                 C   s   | j |dS )z,Get ad spot placements for a specific avail.)avail_idr:   )r6   rV   r$   r$   r%   	for_avail   s    zAdSpotsInAvailManager.for_availc                 C   s   | j |dS )z&Get placements for a specific ad spot.)	adspot_idr:   )r6   rX   r$   r$   r%   
for_adspot   s    z AdSpotsInAvailManager.for_adspotc                 C   s
   |  dS )z&Order placements by position in avail.positioninavailrK   r5   r$   r$   r%   by_position   s    z!AdSpotsInAvailManager.by_positionc                 C   s   | j |dS )zGet placements by traffic ID.)	trafficidr:   r6   
traffic_idr$   r$   r%   for_traffic_id   s    z$AdSpotsInAvailManager.for_traffic_idN)r   r   r   r   rW   rY   r[   r_   r$   r$   r$   r%   rU      s
   rU   c                   @   sH   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dS )VerifsManagerz Custom manager for Verifs model.c                 C   s   | j |dS )z)Get verifications for a specific network.)networknamer:   )r6   Znetwork_namer$   r$   r%   for_network   s    zVerifsManager.for_networkc                 C   s   | j |dS )z&Get verifications for a specific zone.)zonenamer:   )r6   	zone_namer$   r$   r%   for_zone   s    zVerifsManager.for_zonec                 C   s   | j |dS )z0Get verifications for a specific broadcast date.)broadcast_dater:   )r6   rf   r$   r$   r%   for_date   s    zVerifsManager.for_datec                 C   s   | j ddddgdS )z!Get only completed verifications.r(   yes1trueZvercomplete__inr:   r5   r$   r$   r%   	completed   s    zVerifsManager.completedc                 C   s   | j ddddgdS )zGet pending verifications.r(   rh   ri   rj   rk   )excluder5   r$   r$   r%   r'      s    zVerifsManager.pendingc                 C   s   | j |dS )z,Get verifications for a specific traffic ID.)	trafficIdr:   r]   r$   r$   r%   r_      s    zVerifsManager.for_traffic_idc                 C   s
   |  dS )z Order verifications by air time.air_timerK   r5   r$   r$   r%   by_air_time   s    zVerifsManager.by_air_timeN)r   r   r   r   rb   re   rg   rl   r'   r_   rp   r$   r$   r$   r%   r`      s   r`   c                	       sZ  e Zd ZdZejeejddddddZeje	ejddddddZ
ejd	d
edgdZejdddddZejddddZejddddZejeddddZejddddZejdedgdZe ZG dd dZdd Z fddZ fddZed d! Z ed"d# Z!ed$d% Z"ed&d' Z#ed(d) Z$d*d+ Z%d,d- Z&d3d/d0Z'd4d1d2Z(  Z)S )5	Playlistsa  
    Model representing broadcast playlists for television channels.
    
    A playlist contains the scheduling information for a specific broadcast period,
    including windows where advertisements can be placed. Each playlist is associated
    with a channel and potentially a specific zone within that channel.
    
    Attributes:
        channel (ForeignKey): Reference to the broadcasting channel
        id_zone_channel (ForeignKey): Reference to specific zone within the channel
        version (str): Version identifier for playlist tracking
        broadcast_date (DateField): Date when the playlist is scheduled to broadcast
        start_date (datetime): Start datetime for the playlist broadcast
        end_date (datetime): End datetime for the playlist broadcast
        filepath (str): File system path to the playlist file
        is_draft (bool): Flag indicating if playlist is in draft state
        draft_version (int): Version number for draft iterations 
    channelTz$The channel this playlist belongs to	playlists)	on_delete	db_columnblanknull	help_textrelated_namezone_channelz+Specific zone within the channel (optional)r   z*Version identifier for playlist versioningr   )r   rx   
validatorszScheduled broadcast date)rv   rw   rx   db_indexz%Start datetime for playlist broadcast)rv   rw   rx   z#End datetime for playlist broadcastz-Generated XML schedule file for this playlist)	upload_torv   rw   rx   z/Draft status flag (True=draft, False=published))r   rx   r|   z#Version number for draft management)rx   r{   c                   @   s   e Zd ZdZedZedZddgZej	ddgddej	d	d
gddej	ddgddej	dgddej	dgddgZ
ejdddgddejeed
deddB eddB ddgZdS )zPlaylists.Metarq   Playlistz-created_atz-idrr   rf   Zplaylist_channel_date_idxfieldsnamer>   r?   Zplaylist_datetime_range_idxr3   
created_atZplaylist_draft_created_idxversionZplaylist_version_idxrz   Zplaylist_zone_idxZ(unique_playlist_version_per_channel_date)Zstart_date__ltT)Zstart_date__isnull)Zend_date__isnullZplaylist_valid_date_rangecheckr   N)r   r   r   db_tabler"   verbose_nameverbose_name_pluralorderingr   IndexindexesUniqueConstraintCheckConstraintr	   Fconstraintsr$   r$   r$   r%   Meta   s&   	"r   c                 C   s>   | j r| j jnd}| jrdnd}| d| j d| d| j S )z&String representation of the playlist.z
No Channelr   r    -  (z) - )rr   channel_namer3   r   rf   )r6   r   statusr$   r$   r%   __str__9  s    zPlaylists.__str__c                    st   t    | jr2| jr2| j| jkr2tdtdi| jrVt| jdkrVtdtdit	d| j
 d| j  dS )	 Custom validation for the model.r?   z"End date must be after start date.   r   z0Version identifier cannot exceed 255 characters.zValidating playlist z: N)supercleanr>   r?   r   r"   r   lenloggerdebugidr5   	__class__r$   r%   r   ?  s    
  zPlaylists.cleanc                    sl   | j s@| jr@tjj| j| jdjt	ddd }|p8dd | _
td| j d| j  t j|| d	S )
)Custom save method with additional logic.)rr   rf   draft_version)	max_draftr   r   r   zSaving playlist z for channel N)pkr3   rq   objectsr4   rr   rf   	aggregater   Maxr   r   infor   r   save)r6   argskwargsr   r   r$   r%   r   R  s    zPlaylists.savec                 C   s   | j  S )z2Check if the playlist is published (not in draft).r2   r5   r$   r$   r%   is_publishedd  s    zPlaylists.is_publishedc                 C   s:   | j r| jsdS t }| j |  ko.| jkn  o8| jS )z*Check if the playlist is currently active.F)r>   r?   r   rA   r   rB   r$   r$   r%   	is_activei  s    zPlaylists.is_activec                 C   s.   | j r*| jr*| j| j  }t| d dS dS )z'Calculate playlist duration in minutes.<      N)r>   r?   roundtotal_seconds)r6   deltar$   r$   r%   duration_minutesq  s    zPlaylists.duration_minutesc                 C   s   | j }|rt|d dS dS )z%Calculate playlist duration in hours.r   r   N)r   r   )r6   minutesr$   r$   r%   duration_hoursy  s    zPlaylists.duration_hoursc                 C   s   | j r
dS dS )zGet human-readable status.r   r   r2   r5   r$   r$   r%   status_display  s    zPlaylists.status_displayc                 C   s
   | j  S )z&Get count of windows in this playlist.)windowscountr5   r$   r$   r%   get_windows_count  s    zPlaylists.get_windows_countc                 C   s   | j jtddd pdS )z-Get total count of avails across all windows.avails)total_availsr   r   )r   r   r
   r5   r$   r$   r%   get_total_avails_count  s    z Playlists.get_total_avails_countNc                 C   s:   | j r6d| _ | jdgd td| j d|  dS dS )zPublish a draft playlist.Fr3   update_fields	Playlist z published by user T)r3   r   r   r   r   r6   userr$   r$   r%   publish  s    zPlaylists.publishc                 C   sp   t | j| j|p| jd | j| j| j| jddd	}|  | j	
 D ]}|| qBtd| j d|j  |S )z2Create a copy of this playlist with a new version.r   T)	rr   rz   r   rf   r>   r?   filepathr3   r   zCreated copy of playlist z as )rq   rr   rz   r   rf   r>   r?   r   r   r   allcreate_copyr   r   r   )r6   Znew_versionnew_playlistwindowr$   r$   r%   r     s     zPlaylists.create_copy)N)N)*r   r   r   r   r   
ForeignKeyr   
DO_NOTHINGrr   r   rz   IntegerFieldr   r   	DateFieldrf   DateTimeFieldr>   r?   	FileFieldr   Zxml_fileBooleanFieldr3   r   r1   r   r   r   r   r   propertyr   r   r   r   r   r   r   r   r   __classcell__r$   r$   r   r%   rq      s   





	rq   c                
       s   e Zd ZdZejeejdddeddeddZ	ej
ddeded	dd
Zej
ddededdZejddededdZe ZG dd dZdd Z fddZdd Zdd Zdd Z  ZS )Windowsau  
    Model representing advertising windows within a playlist.
    
    Windows are time segments within a playlist where advertisements can be scheduled.
    Each window has a defined start time, end time, and duration within the broader
    playlist timeframe.
    
    Attributes:
        id_window (AutoField): Primary key for the window
        id_playlist (ForeignKey): Reference to the parent playlist
        window_start (TimeField): Start time of the advertising window
        window_end (TimeField): End time of the advertising window  
        window_duration (DurationField): Duration of the advertising window
    playlistTz#The playlist this window belongs tor   r~   rt   ru   rv   rw   rx   ry   r   z$Start time of the advertising windowzWindow Startrv   rw   rx   r   r|   z"End time of the advertising windowz
Window End)rv   rw   rx   r   z"Duration of the advertising windowzWindow Durationc                   @   sx   e Zd ZdZedZedZdgZej	ddgddej	dgddgZ
ejeed	d
eddB eddB ddgZdS )zWindows.Metar   zAdvertising WindowzAdvertising WindowsrJ   r   Zwindow_playlist_start_idxr   Zwindow_start_idx
window_end)Zwindow_start__ltTZwindow_start__isnullZwindow_end__isnullZwindow_valid_time_ranger   N)r   r   r   r   r"   r   r   r   r   r   r   r   r	   r   r   r$   r$   r$   r%   r     s   "r   c                 C   s:   | j rd| j j nd}d| j d| d| j d| j S )z0String representation of the advertising window.r   zNo PlaylistWindow r   z): r   )r   r   r   rJ   r   )r6   Zplaylist_infor$   r$   r%   r     s    zWindows.__str__c                    s   t    | jr2| jr2| j| jkr2tdtdi| jr| jr| jstt	 | j}tt	 | j}||krtt	 t
jdd | j}|| | _dS )r   r   z)Window end time must be after start time.r   daysN)r   r   rJ   r   r   r"   window_durationr   combinetodayr   	timedelta)r6   Zstart_dtZend_dtr   r$   r%   r     s    
 zWindows.cleanc                 C   s
   | j  S )z#Get count of avails in this window.)r   r   r5   r$   r$   r%   get_avails_count  s    zWindows.get_avails_countc                 C   s   | j jtddd pdS )z=Get total count of ad spots across all avails in this window.adspots_in_avail)total_spotsr   r   )r   r   r
   r5   r$   r$   r%   get_total_adspots_count  s    zWindows.get_total_adspots_countc                 C   s<   t || j| j| jd}|  | j D ]}|| q(|S )z0Create a copy of this window for a new playlist.)r   rJ   r   r   )r   rJ   r   r   r   r   r   r   )r6   r   
new_windowavailr$   r$   r%   r     s    zWindows.create_copy)r   r   r   r   r   r   rq   CASCADEr"   r   	TimeFieldrJ   r   DurationFieldr   rD   r   r   r   r   r   r   r   r   r$   r$   r   r%   r     sJ   r   c                
   @   s   e Zd ZdZejeejdddeddeddZ	ej
ddeded	dd
ZejdddededdZe ZG dd dZdd Zdd Zdd Zdd Zdd ZdS )Availsa=  
    Model representing available advertising slots within windows.
    
    Avails are specific time slots within advertising windows where individual
    advertisements can be placed. They represent the granular inventory units
    for ad placement scheduling.
    
    Attributes:
        id_window (ForeignKey): Reference to the parent advertising window
        avail_start (TimeField): Start time of the available slot
        availinwindow (str): Position or identifier of avail within the window
        datetime (datetime): Timestamp associated with the avail
    r   Tz,The advertising window this avail belongs tor   Windowr   z,Start time of the available advertising slotzAvail Startr   ZavailInWindowz1Position or identifier of avail within the windowzAvail in Window)ru   rv   rw   rx   r   c                   @   sJ   e Zd ZdZedZedZddgZej	ddgddej	dgd	dgZ
d
S )zAvails.Metar   zAvailable SlotzAvailable SlotsrT   availinwindowr   Zavail_window_start_idxr   Zavail_position_idxN)r   r   r   r   r"   r   r   r   r   r   r   r$   r$   r$   r%   r   Y  s   r   c                 C   s2   | j rd| j j nd}d| j d| d| j S )z,String representation of the available slot.r   z	No WindowAvail r   z) at )r   r   rT   )r6   Zwindow_infor$   r$   r%   r   c  s    zAvails.__str__c                 C   s
   | j  S )z$Get count of ad spots in this avail.r   r   r5   r$   r$   r%   get_adspots_counth  s    zAvails.get_adspots_countc                 C   s   | j  dkS )z+Check if this avail has no ad spots placed.r   r   r5   r$   r$   r%   is_availablel  s    zAvails.is_availablec                 C   s$   | j jtddd }|pdd S )z6Get the next available position for ad spot placement.rZ   )max_posr   r   r   )r   r   r   r   )r6   Zmax_positionr$   r$   r%   get_next_positionp  s    zAvails.get_next_positionc                 C   s8   t || j| jd}|  | j D ]}|| q$|S )z-Create a copy of this avail for a new window.)r   rT   r   )r   rT   r   r   r   r   r   )r6   r   	new_availZadspot_placementr$   r$   r%   r   x  s    zAvails.create_copyN)r   r   r   r   r   r   r   r   r"   r   r   rT   r   r   rN   r   r   r   r   r   r   r   r$   r$   r$   r%   r   +  s@   	
r   c                
       s   e Zd ZdZejeejdddeddeddZ	eje
ejddded	d
eddZejdddedededgddZejdddededddZe ZG dd dZdd Z fddZ fddZdd Z  ZS ) AdspotsInAvaila;  
    Model representing the placement of specific ad spots within available slots.
    
    This is the junction model that connects advertising spots to specific avails,
    managing the actual placement and positioning of advertisements within the
    broadcast schedule.
    
    Attributes:
        id_avail (ForeignKey): Reference to the available slot
        id_adspot (ForeignKey): Reference to the advertisement spot
        positioninavail (int): Position of the ad spot within the avail
        trafficid (int): Traffic system identifier for the placement
    r   Tz/The available slot where this ad spot is placedr   ZAvailr   adspotz#The advertisement spot being placedZplacements_in_availzAd Spot)ru   rv   rw   rx   ry   r   ZpositionInAvailz2Position of the ad spot within the avail (1-based)zPosition in Availr   )ru   rv   rw   rx   r   r{   r|   rn   z+Traffic system identifier for the placement
Traffic ID)ru   rv   rw   rx   r   r|   c                   @   st   e Zd ZdZedZedZddgZej	ddgddej	d	gd
dej	dgddgZ
ejddgdedddgZdS )zAdspotsInAvail.MetaZAdspots_in_availzAd Spot PlacementzAd Spot PlacementsrZ   r   r   Zadspot_avail_position_idxr   r   Zadspot_spot_idxr\   Zadspot_traffic_idxZ unique_adspot_position_per_availF)Zpositioninavail__isnull)r   r   	conditionN)r   r   r   r   r"   r   r   r   r   r   r   r   r	   r   r$   r$   r$   r%   r     s   r   c                 C   sV   | j rd| j  nd}| jr(d| j nd}| jr>d| j nd}| d| d| S )	z/String representation of the ad spot placement.zAdSpot z	No AdSpotr   zNo Availz	Position zNo Positionz in z at )rX   rV   rZ   )r6   Zadspot_infoZ
avail_infoZposition_infor$   r$   r%   r     s    zAdspotsInAvail.__str__c                    sp   t    | jr*| jdkr*tdtdi| jrl| jrltjj| j| jdj	| j
d}| rltdtdidS )r   d   rZ   zPosition cannot exceed 100.)r   rZ   )r   z0This position is already occupied in this avail.N)r   r   rZ   r   r"   r   r   r   r4   rm   r   exists)r6   Zconflictingr   r$   r%   r     s$    
  zAdspotsInAvail.cleanc                    sD   | j s| jr| j | _ td| j d| j  t j|| dS )r   zSaving ad spot placement: z
 in avail N)	rZ   r   r   r   r   rX   rV   r   r   r6   r   r   r   r$   r%   r     s    zAdspotsInAvail.savec                 C   s"   t || j| j| jd}|  |S )z0Create a copy of this placement for a new avail.)r   r   rZ   r\   )r   r   rZ   r\   r   )r6   r   Znew_placementr$   r$   r%   r     s    zAdspotsInAvail.create_copy)r   r   r   r   r   r   r   r   r"   r   r   r   r   r   r   rZ   r\   rU   r   r   r   r   r   r   r   r$   r$   r   r%   r     sX   
r   c                	       s  e Zd ZdZejdededddZejdededddZej	ed	ed
ddZ
ejededddZejdededddZejededddZejededdZejdededddZejdedededgddZejddddededddZe ZG d d! d!Zd"d# Z fd$d%Z fd&d'Zed(d) Zed*d+ Zed,d- Zd7d/d0Z d1d2 Z!e"d3d4 Z#d5d6 Z$  Z%S )8Verifsa  
    Model for storing advertisement verification and broadcast confirmation data.
    
    This model tracks the actual broadcast verification of advertisements,
    recording when ads were aired, their duration, status, and other verification
    metadata for billing and compliance purposes.
    
    Attributes:
        networkname (str): Name of the broadcasting network
        zonename (str): Name of the broadcasting zone
        broadcast_date (DateField): Date when the ad was broadcast
        trafficId (int): Traffic system identifier
        spotId (str): Unique identifier for the advertisement spot
        air_time (TimeField): Time when the ad was aired
        air_length (DurationField): Duration of the aired advertisement
        airStatuscode (str): Status code indicating broadcast result
        revision (int): Revision number for the verification record
        vercomplete (str): Verification completion status
    r   z Name of the broadcasting networkzNetwork NameT)
max_lengthrx   r   r|   zName of the broadcasting zonez	Zone Namez)Date when the advertisement was broadcastzBroadcast Date)rx   r   r|   z/Traffic system identifier for the advertisementr   z,Unique identifier for the advertisement spotzSpot IDz%Time when the advertisement was airedzAir Timez#Duration of the aired advertisementz
Air Length)rx   r   z'Status code indicating broadcast resultzAir Status Coder   z+Revision number for the verification recordZRevision)r   rx   r   r{   r|   ZverComplete2   zVerification completion statuszVerification Complete)ru   r   rv   rw   rx   r   r|   c                	   @   s   e Zd ZdZedZedZdddgZej	ddgd	d
ej	ddgdd
ej	ddgdd
ej	ddgdd
ej	dgdd
ej	dgdd
gZ
ejdddgdd
gZdS )zVerifs.Metar   zAdvertisement VerificationzAdvertisement Verificationsz-broadcast_datez	-air_time	-revisionra   rc   Zverif_network_zone_idxr   rf   ro   Zverif_broadcast_air_idxrn   revisionZverif_traffic_revision_idxspotIdZverif_spot_date_idxairStatuscodeZverif_status_idxvercompleteZverif_complete_idxZ&unique_verif_per_traffic_spot_revisionN)r   r   r   r   r"   r   r   r   r   r   r   r   r   r$   r$   r$   r%   r   w  s    

r   c                 C   s:   | j r
dnd}d| j d| j d| j d| j d| dS )	z1String representation of the verification record.r,   r+   Verification r   / on r   ))is_verification_completer   ra   rc   rf   )r6   r   r$   r$   r%   r     s    zVerifs.__str__c                    sN   t    | jr&| js&tdtdi| jrJt| jdkrJtdtdidS )r   r   z0Spot ID is required when Traffic ID is provided.r   r   z(Status code cannot exceed 50 characters.N)r   r   rn   r   r   r"   r   r   r5   r   r$   r%   r     s    
  zVerifs.cleanc                    s,   t d| j d| j  t j|| dS )r   zSaving verification for spot r  N)r   r   r   rf   r   r   r   r   r$   r%   r     s    zVerifs.savec                 C   s   | j s
dS | j  dkS )z,Check if verification is marked as complete.F)r(   rh   ri   rj   )r   lowerr5   r$   r$   r%   r    s    zVerifs.is_verification_completec                 C   s*   | j rtdS | jr| j S tdS dS )z'Get human-readable verification status.r,   r+   N)r  r"   r   titler5   r$   r$   r%   r     s
    
zVerifs.status_displayc                 C   s"   dddddg}| j o | j  |kS )z;Check if the broadcast was successful based on status code.successokZ200Zaired	broadcast)r   r  )r6   Zsuccess_codesr$   r$   r%   is_successful_broadcast  s    zVerifs.is_successful_broadcastNc                 C   s0   d| _ | jdgd td| j d|  dS )zMark verification as complete.r(   r   r   r   z marked complete by user N)r   r   r   r   r   r   r$   r$   r%   mark_complete  s    zVerifs.mark_completec                 C   sX   t | j| j| j| j| j| j| j| j| j	d dd
}|
  td|j	 d| j  |S )z+Create a new revision of this verification.r   N)
ra   rc   rf   rn   r   ro   
air_lengthr   r   r   zCreated revision z for verification )r   ra   rc   rf   rn   r   ro   r  r   r   r   r   r   )r6   Znew_revisionr$   r$   r%   create_revision  s    zVerifs.create_revisionc                 C   s   | j j||dd S )z>Get the latest revision for a specific traffic ID and spot ID.)rn   r   r   )r   r4   rL   first)clsr^   spot_idr$   r$   r%   get_latest_revision  s    zVerifs.get_latest_revisionc              	   C   s&   | j | j| j| j| j| j| j| jdS )z'Get a summary of broadcast information.)networkzonedater   durationr   r(   
successful)ra   rc   rf   ro   r  r   r  r
  r5   r$   r$   r%   get_broadcast_summary  s    zVerifs.get_broadcast_summary)N)&r   r   r   r   r   	CharFieldr"   ra   rc   r   rf   r   rn   r   r   ro   r   r  r   r   r   r   r`   r   r   r   r   r   r   r  r   r
  r  r  classmethodr  r  r   r$   r$   r   r%   r     s   	

	


r   c                   C   s2   t j t j  t j  t j  dS )z%Get overall statistics for playlists.)Ztotal_playlistsZpublished_playlistsZdraft_playlistsZactive_playlists)rq   r   r   r7   r8   rC   r$   r$   r$   r%   get_playlist_statistics  s
    r  c                   C   sF   t j t j  t j  t j  tt j d d dS )z)Get overall statistics for verifications.r   r   )Ztotal_verificationsZcompleted_verificationsZpending_verificationsZcompletion_rate)r   r   r   rl   r'   maxr$   r$   r$   r%   get_verification_statistics  s
     r     c                 C   sP   t  t j| d }tjjd|d}| }|  t	d| d|  d |S )zClean up old draft playlists.r   T)r3   Zcreation_at__ltzCleaned up z  old draft playlists older than z days)
r   rA   r   rq   r   r4   r   deleter   r   )r   cutoff_dateZ
old_draftsr   r$   r$   r%   cleanup_old_drafts  s    r   c                   @   s4   e Zd ZdZedd Zedd Zedd ZdS )	DataTypeMigrationHelperz
    Helper class for migrating data when changing field types.
    Use this in Django data migrations to convert existing string data
    to proper field types.
    c               	   C   sj   ddl m}  |  B tjjddd}|D ]&}t|j}|r*||_|j	dgd q*W 5 Q R X t
d d	S )
z;Migrate playlist broadcastdate from CharField to DateField.r   transactionTF)broadcast_date__isnullZbroadcastdate__isnullrf   r   z!Completed playlist date migrationN)	django.dbr#  atomicrq   r   r4   r   Zbroadcastdaterf   r   r   r   )r#  rs   r   converted_dater$   r$   r%   migrate_playlist_dates  s    

z.DataTypeMigrationHelper.migrate_playlist_datesc               	   C   s   ddl m}  |   tjtjddtjddB }|D ]x}t|drb|j	rbt
|j	}|rb||_t|dr|jrt
|j}|r||_t|dr|jrt|j}|r||_|  q:W 5 Q R X td	 d
S )z1Migrate window times from CharField to TimeField.r   r"  Tr   r   window_start_oldwindow_end_oldwindow_duration_oldz Completed window times migrationN)r%  r#  r&  r   r   r4   r   r	   hasattrr)  r   rJ   r*  r   r+  r   r   r   r   r   )r#  r   r   Zconverted_startZconverted_endconverted_durationr$   r$   r%   migrate_window_times  s(    



z,DataTypeMigrationHelper.migrate_window_timesc               	   C   s   ddl m}  |   tjtjddtjddB tjddB }|D ]x}t|drn|j	rnt
|j	}|rn||_t|dr|jrt|j}|r||_t|d	r|jrt|j}|r||_|  qFW 5 Q R X td
 dS )z=Migrate verification data from string fields to proper types.r   r"  T)r$  )Zair_time__isnull)Zair_length__isnullbroadcastDateairTime	airLengthz%Completed verification data migrationN)r%  r#  r&  r   r   r4   r   r	   r,  r/  r   rf   r0  r   ro   r1  r   r  r   r   r   )r#  ZverifsZverifr'  Zconverted_timer-  r$   r$   r%   migrate_verification_data  s0    






z1DataTypeMigrationHelper.migrate_verification_dataN)r   r   r   r   staticmethodr(  r.  r2  r$   r$   r$   r%   r!    s   

r!  )r  )9r   email.policyr   r%  r   Zdjango.core.validatorsr   r   django.core.exceptionsr   django.utilsr   django.utils.translationr   r"   django.db.modelsr	   r
   r   "django.contrib.contenttypes.modelsr   r   r   loggingapps.common.modelsr   Zapps.campaigns.modelsr   apps.channels.modelsr   r   r   Zapps.playlists.utilsr   r   r   r   	getLoggerr   r   r   r&   Managerr1   rD   rN   rU   r`   rq   r   r   r   r   r  r  r   r!  r$   r$   r$   r%   <module>   sH   
!" n}]    (

