U
    th                    @   s  d dl Z d dlZd dlZd dlZd dlZd dlmZ d dlmZ d dl	m
Z
 d dlmZ d dlmZ d dlmZ d dlmZmZ d d	lmZmZm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#m$Z$m%Z%m&Z&m'Z' d dl(m)Z) d dl*m+Z+ d dl,m-Z- d dl.m/Z/ d dl0m1Z1m2Z2 d dl3m4Z4m5Z5m6Z6m7Z7m8Z8m9Z9 G dd dZ:d dl;m<Z< e!dd Z=e!dd Z>e!dQddZ?e!dRddZ@e!dSd d!ZAe!d"d# ZBe!d$d% ZCe!d&d' ZDe!dTd(d)ZEe!d*d+ ZFe!dUd,d-ZGe!dVd.d/ZHe!dWd0d1ZIe!d2d3 ZJe!d4d5 ZKe!d6d7 ZLe!dXd9d:ZMe!dYd;d<ZNe!d=d> ZOd?d@ ZPd d
lmZ d dAlmZmZmZ d dBlQmRZRmSZSmTZTmUZU d dClmVZV d dDlWmXZX G dEdF dFeeZYG dGdH dHeeZZdIdJ Z[G dKdL dLeeZ\G dMdN dNeeZ]G dOdP dPeeZ^dS )Z    N)import_main_path)View)settings
connection)timezone)messages)renderredirect)	Paginator	EmptyPagePageNotAnInteger)LoginRequiredMixin)gettext_lazy)DictAny)login_required)FExpressionWrapper
FloatFieldQCountSubstr)get_client_ip)Channel)Activity)	CampaignsAdspots)AgencyBrand
AdvertiserBrandCategoryBrandStatus
AgencyTypec                   @   s   e Zd ZdZdd ZdS )EmptyAgencyz4Empty agency object for template use in create mode.c                 C   s|   d | _ d | _d| _d| _d| _d| _d| _d| _d| _d| _	d| _
d| _d| _d| _d| _d| _d| _d| _d | _d | _d S )N UTCen)pkidname
legal_namedescriptionemailphonewebsitefounded_yearagency_sizeemployee_countstreet_addresscitystatepostal_codecountry	time_zonelanguagelogoagency_type_idself r?   apps/agencies/views.py__init__"   s(    zEmptyAgency.__init__N)__name__
__module____qualname____doc__rA   r?   r?   r?   r@   r%       s   r%   )handle_uploaded_filec              
   C   s`   | j }tjj| j dd}tj|dd|r,|jnd d| t| | j	ddi d	 t
| d
d|iS )Nr   owner
is_deletedview_agenciesUser Systemz performed view_agenciesHTTP_USER_AGENTr&   useractionr-   requestZ
ip_addressZ
user_agentZmetadataagencies/agency/list.htmlagency)rO   r   objectsfilterr   log_activityr.   r   METAgetr	   )rQ   rO   agenciesr?   r?   r@   rJ   A   s    	rJ   c                 C   s   | j }| jdkr| jd}| jd}|s@t| d tdS tjj	|||t
 d}tj|dd|rl|jnd	 d
| t| | jddt|j||dd tdS t| dS )NPOSTname_agencydescription_agencyAgency name is required.zagencies:add_agencyrH   r+   r-   datetime
add_agencyrK   rL   z performed add_agencyrM   r&   	agency_idagency_nameZagency_descrN   agencies:view_agencieszagencies/agency/add.html)rO   methodrZ   rX   r   errorr
   r   rT   creater   nowr   rV   r.   r   rW   strr*   r	   rQ   rO   r[   r\   rS   r?   r?   r@   r`   W   s6    
r`   c                 C   s   | j }| jdkr|d k	rtjj|d}|j|krDt| d tdS d|i}t	j
|dd|r`|jnd d	| | t| | jd
dt|j|j|jdd t| dd|iS tdS )NrZ   r)   z%You are not the owner of this agency.agencies:edit_agencyrS   edit_agencyrK   rL   z  performed view_agency with id: rM   r&   ra   rN   zagencies/agency/edit.htmldatard   )rO   re   r   rT   rX   rH   r   rf   r
   r   rV   r.   r   rW   ri   r*   r+   r-   r	   )rQ   	id_agencyrO   rS   rn   r?   r?   r@   rm   ~   s,    

rm   c                 C   s   | j }| jdkr|d k	r| jd}| jd}|sHt| d tdS tjj|d}|r^|n|j	|_	|rn|n|j
|_
|  tj|dd|r|jnd	 d
| | t| | jddt|j|j	|j
dd tdS )NrZ   r[   r\   r]   rl   rk   rm   rK   rL   z  performed edit_agency with id: rM   r&   ra   rN   rd   )rO   re   rZ   rX   r   rf   r
   r   rT   r+   r-   saver   rV   r.   r   rW   ri   r*   )rQ   ro   rO   r+   r-   rS   r?   r?   r@   update_agency   s2    
rq   c                 C   s   | j }| jdkr|d k	rtjj|d}tj |_d|_|  t	j
|dd|rT|jnd d| | t| | jdd	t|j|j|jd
d tdS )NrZ   rk      delete_agencyrK   rL   z" performed delete_agency with id: rM   r&   ra   rN   rd   )rO   re   r   rT   rX   r_   rh   rI   rp   r   rV   r.   r   rW   ri   r*   r+   r-   r
   )rQ   ro   rO   rS   r?   r?   r@   rs      s(    
rs   c                 C   s   t | ddtjj| jddiS )N1agencies/components/dropdown_agency_campaign.htmlrY   r   rG   )r	   r   rT   rU   rO   rQ   r?   r?   r@   load_agency   s
    rv   c                 C   sD   | j }| jd}| jd}t|||t d}|  t| dS )Nr[   r\   r^   rt   )rO   rZ   rX   r   r   rh   rp   r	   rj   r?   r?   r@   send_agency   s    rw   c                 C   s   t jj| jddddd}g }|D ]d}i }|d |d< tjj|d d}tjj|dd	}t|dkr$|d
 |d< t||d< || q$|S )Nr   rG   ro   r+   r_   rr   ro   T)Zid_brand__inZpacing   date	campaigns)	r   rT   rU   rO   values_listr    r   lenappend)rQ   ZagencesresultZagencerbrandsr{   r?   r?   r@   active_agency  s&      r   c              
   C   s  | j }|dkr|d krtjj|d}tjj|dd }dd t|D }t	jj|d}tjj|d
d}tj|dd	|r|jnd
 d| | t| | jddi d t| dd||t|diS tjj|dd}dd |D }tjj|d
d}g }	|D ]d}d}
ztjj|d}t|}
W n tjk
rD   d }Y nX t|j|j|
|jd}|	| qtj|dd	|r|jnd
 d| t| | jddi d t| dd|	iS d S )Nr&   rk   brandZchannelc                 S   s   g | ]}|d  qS r   r?   .0ir?   r?   r@   
<listcomp>%  s     z$views_advertiser.<locals>.<listcomp>pk__inZview_advertiserrK   rL   z# performed view_advertiser with id rM   rN   z&agencies/advertiser/views_adspots.htmlrn   )adspotsr   channelsid_userr   c                 S   s   g | ]}|d  qS r   r?   )r   Zbrand_tupler?   r?   r@   r   >  s     -created_atr   id_brand
name_brandtotal_adspotsr;   Zview_advertisersz performed view_advertiserszagencies/advertiser/views.htmlr   )rO   r    rT   rX   r   rU   r|   Zdistinctlistr   order_byr   rV   r.   r   rW   r	   r!   r}   DoesNotExistri   r*   r+   logo_urlr~   )rQ   r   rO   r   r   r   Zbrands_tuples	brands_idr   Z	brand_dicr   ZadspotZ
brand_datar?   r?   r@   views_advertiser  sp    	


r   c              
   C   s2  | j }tjj| j dd}| jdkrz| jdd }| jdd }| jdd }| jdd	 }| jd
dk}| jd}g }	|s|	d nt	|dkr|	d |s|	d n|t
tjkr|	d |t
tjkr|	d |rt	|dkr|	d d}
d| jkr~| jd }
d}|
j|krH|	d dddddg}|
jdd  }||kr~|	d  |	r|	D ]}t| | qtd!W S z2tjj|d"}| dkrtjj| j dd}W n, tk
r   t| d# td$ Y W S X t| t|  | }tjj||d% }|st||||||d&}|
r|
jdd  }t j d'|dd(  d| }|jj ||
d)d* |   zHt!j"|d+d,|r|j#nd- d.| t$| | j%d/dd0t&|j'id1 W n t(k
r   Y nX ntjj||d%}zt)|||d2}|   W n t(k
rH   Y nX zHt!j"|d3d,|rb|j#nd- d4| t$| | j%d/dd3t&|j'id1 W n t(k
r   Y nX t*| d5|j d6 td$W S  t+k
r } z&t| d7t&|  td! W Y S d}~X Y nX n|tjtjd8}t,| d9|S dS ):zT
    Handle brand/advertiser creation with proper validation and error handling
    r   rG   rZ   r+   r&   categoryr-   statusactiveis_featuredZonrS   zBrand name is required.   z(Brand name cannot exceed 255 characters.zCategory is required.zInvalid category selected.zInvalid status selected.i  z*Description cannot exceed 1000 characters.Nr;     P !Logo file size cannot exceed 5MB.jpgjpegpngsvgwebp.4Logo must be in JPG, JPEG, PNG, SVG, or WebP format.zagencies:add_advertiserrk   z'User is not associated with any agency.agencies:views_advertiser)r+   rS   )r+   rS   r-   r   r   r   _2   F)rp   Zcreate_brandrK   rL   z performed create_brandrM   r   rN   )r   r   r   Zcreate_advertiserz performed create_advertiserzBrand " " has been created successfully!z,An error occurred while creating the brand: )rY   Zbrand_categoriesZbrand_statuseszagencies/advertiser/add.html)-rO   r   rT   rU   re   rZ   rX   stripr~   r}   dictr"   choicesr#   FILESsizer+   splitlowerr   rf   r
   countAttributeErrorprintfirstr    existsuuidZuuid4hexr;   rp   r   rV   r.   r   rW   ri   r*   ImportErrorAdvertiserssuccess	Exceptionr	   )rQ   rO   rY   r+   r   r-   r   r   ro   errors	logo_filemax_sizeallowed_extensionsfile_extensionrf   rS   Zbrand_existr   Zunique_filenameZadvertiser_userecontextr?   r?   r@   add_advertiserf  s    









	" 
 

 r   c                 C   s   t | j | jdkr:t | tjj|d}t| dd|iS tjj| jd	d}dd |D }tjj|d	
d
}t| dd|iS d S )NrZ   rk   zcore/edit_advertiser_id.htmlr   r   r   c                 S   s   g | ]}|d  qS r   r?   r   xr?   r?   r@   r     s     z#edit_advertiser.<locals>.<listcomp>r   	-id_brandzagencies/advertiser/edit.htmlr   )r   re   r    rT   rX   r	   r   rU   rO   r|   r   )rQ   r   r   r   r   r?   r?   r@   edit_advertiser  s    

r   c                 C   sH  t jj|d}| jd}| jd}| jd}| jd}tj }z\d}t|dd}	|	d	d
}	|d |	 d }
t| j	d d| |
 d| d |
 |_
W n   Y nX |dkr||_|dkr||_|dkr||_|dkr||_d}dt|j }t|||d}|  |  tjj| jd djddd }tdS )Nrk   advertiser_namer   advertiser_desc
active_0_1ZAdvertisers_imgs r   :-__.pngZadvertiser_logozstatic//r&   zEdit AdvertirerzAdmin edit advertiser  id: activityrz   r-   r   r   1r   r   r   )r    rT   rX   rZ   r_   rh   ri   replacerF   r   r;   
brand_namer   r-   r   r   r   rp   r   rU   sessionselect_relatedallr
   )rQ   r   r   r   r   r   r   rh   path
now_infilefilenameactivitedescr   r   r?   r?   r@   update_advertiser  s<    
&r   c           
      C   s   | j dkrltj }d}dt| }t|||d}|  tjj|d}dt	|j
 d }t||_
|  tjj| jd d	d
}dd |D }tjj|dd}	t| dd|	iS )NrZ   zDisable AdvertirerzAdmin disable advertiser  id: r   rk   rr   ry   r   r   r   c                 S   s   g | ]}|d  qS r   r?   r   r?   r?   r@   r   R  s     z&disable_advertiser.<locals>.<listcomp>r   r   zcore/advertiser/disable.htmlr   )re   r_   rh   ri   r   rp   r    rT   rX   intr   r   rU   r   r|   r   r	   )
rQ   r   rh   r   r   r   r   r   r   r   r?   r?   r@   disable_advertiser@  s    


r   c                 C   s*   | j d}tjj|d}t| dd|iS )NrS   rx   'core/dropdown_advertisers_campaign.htmlr   )GETrX   r    rT   rU   r	   )rQ   rb   Zadvertisersr?   r?   r@   load_advertisersX  s    r   c                 C   s   | j d}t| | j d}t| | j d}| j d}tj }d}t|dd}|dd	}|d
 | d }| j d}	tjj|	d}	|
|	|||||d | d}
|
	  t
| jd |
j||d}|	  t| dS )Nr+   r   r-   r   zstatic/Advertisers_imgsr   r   r   r   r   r   rS   rx   r   )ro   r   r-   r   r   r;   r   )Z
id_user_idZid_brand_idr   r_   r   )rZ   rX   r   r_   rh   ri   r   r   rT   rp   r   r   r   r	   )rQ   r   r   r   r   rh   r   r   r   rS   r    ZAdvertiser_userr?   r?   r@   send_advertisers_  s<    

r   c                 C   s   t jj| jd dd}dd |D }tjj|dd}g }g }g }|D ]J}tjj|d}t|}|	| |j
|j||jd	}	t|	 |	|	 qLt| td
dD ].}t|}
||
}||}|	||  qt| |S )Nr   r   r   c                 S   s   g | ]}|d  qS r   r?   r   r?   r?   r@   r     s     z$most_advertisers.<locals>.<listcomp>r   r   r   r   r      )r   rT   rU   r   r|   r    r   r   r}   r~   r   r   r;   r   rangemaxindexpop)rQ   r   r   Ztotalsdicr   r   r   toutalr   Z	max_valueZ	max_indexar?   r?   r@   most_advertisers  s2    


r   r&   c           &   	      s|  ddl m}m}m} ddlm} ddlm} dd } fdd}| jd	krdd
lm}	 dd l	}
|	
 }|d}|
d}|	
|}|  d }tdt| d | jddd}| jddd}| jd}|dkrd}d}d}d}ddlm    }d| d||f}||| d}||}g }d }|D ]N}|	|d d }|r~||kr~|dddddd || |}q@|D ].}|d  d krt| n|t|d  7 }qt| d!||||d"S tjj| jd# d$ d%}d&d' |D }t!jj|dd("d)} g }!| D ]F}"t#jj|"d*}#t$|#}$|"j%|"j&|"j'|$|"j(d+}%t|% |!|% q t| d,d-|!iS d S ).Nr   )r   r   r   r   )	timedeltac                    s&   dd | j D   fdd|  D S )'Return all rows from a cursor as a dictc                 S   s   g | ]}|d  qS r   r?   r   colr?   r?   r@   r     s     zBreport_advertiser_backup.<locals>.dictfetchall.<locals>.<listcomp>c                    s   g | ]}t t |qS r?   r   zipr   rowcolumnsr?   r@   r     s   r-   fetchallcursorr?   r   r@   dictfetchall  s    
z.report_advertiser_backup.<locals>.dictfetchallc              
      sx   z:   (}|| | | }|W  5 Q R  W S Q R X W n8 tk
rr } ztd|  g  W Y S d }~X Y nX d S NzAn error occurred: )r   executer   r   r   queryZparamsr   Zrowsr   r   r?   r@   my_custom_sql  s    
z/report_advertiser_backup.<locals>.my_custom_sqlrZ   )r_   %Y-%m-%dEurope/Paris  -Current UTC offset for France (Paris) is GMT+r   	start_dayr   r&   end_dayselected_brandrr   az  
            SELECT networkname, spotId, DATE_SUB(Verifs.airTime, INTERVAL 1 HOUR) as airTime, airStatusCode, purcent AS sfr_percentage, purcent*1.25*4500000/17 AS total_volume, Epg.emission_name
            FROM Verifs
            LEFT JOIN SFR_analytics ON SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(SFR_analytics.`minute`, 1, 5)
            AND SUBSTRING(Verifs.airTime, 1, 10) = SUBSTRING(SFR_analytics.`day`, 1, 10)
            AND SFR_analytics.sfr_channel_name = '2M Maroc'
            LEFT JOIN Epg ON (Verifs.airTime < DATE_ADD(Epg.End_time, INTERVAL 1 HOUR) AND Verifs.airTime > DATE_ADD(Epg.Start_time, INTERVAL 1 HOUR))
            WHERE Verifs.spotId LIKE %s AND Verifs.airStatusCode = '0001' AND Verifs.broadcastDate > %s AND Verifs.broadcastDate < %s
            GROUP BY networkname, spotId, airTime, airStatusCode, purcent, Epg.emission_name ORDER BY airTime
            a  
            SELECT networkname, spotId, DATE_SUB(Verifs.airTime, INTERVAL 1 HOUR) as airTime, airStatusCode, purcent AS sfr_percentage, CAST(purcent * 1.25 * 4500000 / 17 AS UNSIGNED) AS total_volume, Epg.emission_name
            FROM Verifs
            LEFT JOIN SFR_analytics ON SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(SFR_analytics.`minute`, 1, 5)
            AND SUBSTRING(Verifs.airTime, 1, 10) = SUBSTRING(SFR_analytics.`day`, 1, 10)
            AND SFR_analytics.sfr_channel_name = '2M Maroc'
            LEFT JOIN Epg ON (Verifs.airTime < DATE_ADD(Epg.End_time, INTERVAL 1 HOUR) AND Verifs.airTime > DATE_ADD(Epg.Start_time, INTERVAL 1 HOUR))
            WHERE Verifs.spotId LIKE %s AND Verifs.airStatusCode = '0001' AND Verifs.broadcastDate > %s AND Verifs.broadcastDate < %s
            GROUP BY networkname, spotId, airTime, airStatusCode, purcent, Epg.emission_name
            ORDER BY airTime
            a  
            SELECT networkname, spotId, DATE_SUB(Verifs.airTime, INTERVAL 1 HOUR) as airTime, airStatusCode, purcent AS sfr_percentage, CAST(purcent * 1.25 * 4500000 / 17 AS UNSIGNED) AS total_volume, Epg.emission_name
            FROM Verifs
            LEFT JOIN SFR_analytics ON SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(SFR_analytics.`minute`, 1, 5)
            AND SUBSTRING(Verifs.airTime, 1, 10) = SUBSTRING(SFR_analytics.`day`, 1, 10)
            AND SFR_analytics.sfr_channel_name = '2M Maroc'
            Inner JOIN Epg ON (Verifs.airTime < DATE_ADD(Epg.End_time, INTERVAL 2 HOUR) AND Verifs.airTime > DATE_ADD(Epg.Start_time, INTERVAL 2 HOUR))
            WHERE Verifs.spotId LIKE %s AND Verifs.airStatusCode = '0001' AND Verifs.broadcastDate > %s AND Verifs.broadcastDate < %s
            GROUP BY networkname, spotId, airTime, airStatusCode, purcent, Epg.emission_name
            ORDER BY airTime
              
            SELECT networkname,
            spotId,
            DATE_SUB(Verifs.airTime, INTERVAL 1 HOUR) as airTime,
            airStatusCode,
            purcent AS sfr_percentage,
            CAST(MAX(purcent) * 1.25 * 4500000 / 17 AS UNSIGNED) AS total_volume,
            Epg.emission_name
            FROM Verifs
            LEFT JOIN (
            SELECT sfr_channel_name,
            `minute`,
            `day`,
            MAX(purcent) as purcent
            FROM SFR_analytics
            WHERE sfr_channel_name = '2M Maroc'
            GROUP BY sfr_channel_name, `minute`, `day`
            ) AS SFR_analytics ON SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(SFR_analytics.`minute`, 1, 5)
            AND SUBSTRING(Verifs.airTime, 1, 10) = SUBSTRING(SFR_analytics.`day`, 1, 10)
            Inner JOIN Epg ON (Verifs.airTime < DATE_ADD(Epg.End_time, INTERVAL 2 HOUR) AND Verifs.airTime > DATE_ADD(Epg.Start_time, INTERVAL 2 HOUR))
            WHERE Verifs.spotId LIKE %s
            AND Verifs.airStatusCode = '0001'
            AND Verifs.broadcastDate > %s
            AND Verifs.broadcastDate < %s
            GROUP BY networkname, spotId, airTime, airStatusCode, purcent, Epg.emission_name
            ORDER BY airTime
            r   %airTime%Y-%m-%d %H:%M:%S--ZnetworknamespotIdr  total_volumeZemission_namer  core/view_report.htmlrn   totalr  report_dater   r   r   c                 S   s   g | ]}|d  qS r   r?   r   r?   r?   r@   r   v  s     z,report_advertiser_backup.<locals>.<listcomp>r   r   r   r   r   r   r-   r   r;   zcore/advertiser/report.htmlr   ))django.db.modelsr   r   r   django.db.models.functionsr   r_   r   re   pytzrh   strftimer   	utcoffsettotal_secondsr   r   rZ   rX   r   	django.dbr   r   r  strptimerz   r~   r	   r!   rT   rU   r   r|   r    r   r   r}   r   r   r-   r;   )&rQ   r   r   r   r   r   r   r  r  r_   r  current_datetimer  paris_tz
paris_time
utc_offsetr  r  r  	query_oldZ	query_ol3Z
query_old4r  r   
data_tupler  rn   processed_data	last_dater   row_dater   r   r   r   r   r   r   r?   r   r@   report_advertiser_backup  sr    


,

r-  c              	   C   s  dd }dd }| j dkrxt }|d}td}t|}|  d }td	t	| d
 | j
ddd}	| j
ddd}
| j
d}|dkrd}d}d}d}t }| }d| d|	|
f}||| ||}g }d }d}|D ]h}t|d d }|r6||kr6|dddddd || |}|d d k	r|t	|d 7 }qt| d||||dS tjj| jd djd d!d"}tjj|d#d$d%}g }|D ]>}tjj|d&}t|}|j|j|j ||j!d'}|| qt| d(d)|iS d S )*Nc                    s&   dd | j D   fdd|  D S )r   c                 S   s   g | ]}|d  qS r   r?   r   r?   r?   r@   r     s     z;report_advertiser.<locals>.dictfetchall.<locals>.<listcomp>c                    s   g | ]}t t |qS r?   r   r   r   r?   r@   r     s   r   r   r?   r   r@   r    s    
z'report_advertiser.<locals>.dictfetchallc              
   S   sx   z:t  (}|| | | }|W  5 Q R  W S Q R X W n8 tk
rr } ztd|  g  W Y S d }~X Y nX d S r  )r   r   r  r   r   r   r  r?   r?   r@   r    s    
z(report_advertiser.<locals>.my_custom_sqlrZ   r  r  r	  r
  r   r  r   r&   r  r  ry   r  ay  
            SELECT networkname,
            spotId,
            DATE_SUB(Verifs.airTime, INTERVAL 1 HOUR) as airTime,
            airStatusCode,
            purcent AS sfr_percentage,
            CAST(MAX(purcent) * 1.25 * 4500000 /
            CASE
            WHEN DATE(Verifs.airTime) < '2024-03-18' THEN 17
            ELSE 14
            END AS UNSIGNED) AS total_volume,
            Epg.emission_name
            FROM Verifs
            LEFT JOIN (
            SELECT sfr_channel_name,
            `minute`,
            `day`,
            MAX(purcent) as purcent
            FROM SFR_analytics
            WHERE sfr_channel_name = '2M Maroc'
            GROUP BY sfr_channel_name, `minute`, `day`
            ) AS SFR_analytics ON SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(SFR_analytics.`minute`, 1, 5)
            AND SUBSTRING(Verifs.airTime, 1, 10) = SUBSTRING(SFR_analytics.`day`, 1, 10)
            INNER JOIN Epg ON (Verifs.airTime < DATE_ADD(Epg.End_time, INTERVAL 2 HOUR) AND Verifs.airTime > DATE_ADD(Epg.Start_time, INTERVAL 2 HOUR) AND Epg.verif_channel_id = Verifs.zonename)
            WHERE Verifs.spotId LIKE %s
            AND Verifs.airStatusCode = '0001'
            AND Verifs.broadcastDate > %s
            AND Verifs.broadcastDate < %s
            GROUP BY networkname, spotId, airTime, airStatusCode, purcent, Epg.emission_name
            ORDER BY airTime
            a  
            Select

            MIN(networkname) AS networkname,
            MIN(networkname) AS networkname,
            MIN(spotId) AS spotId,

            MIN(Epg.emission_name) AS emission_name,
            SUBSTRING(DATE_SUB(Verifs.airTime, INTERVAL 2 HOUR), 1, 19) as airTime,

            CAST(MAX(purcent) * 1.25 * 4500000 /
            CASE
                WHEN DATE(Verifs.broadcastDate) < '20240317' THEN 17
            ELSE 14 END AS UNSIGNED) AS total_volume

            FROM Verifs
            INNER JOIN SFR_analytics ON SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(SFR_analytics.`minute`, 1, 5)
                         AND SUBSTRING(Verifs.airTime, 1, 10) = SUBSTRING(SFR_analytics.`day`, 1, 10)
                         AND SFR_analytics.sfr_channel_name = '2M Maroc'
            INNER JOIN Epg ON (Verifs.airTime < DATE_ADD(Epg.End_time, INTERVAL 1 HOUR) AND Verifs.airTime > DATE_ADD(Epg.Start_time, INTERVAL 1 HOUR))
            WHERE Verifs.spotId LIKE %s
            AND Verifs.airStatusCode = '0001'
            AND Verifs.broadcastDate > %s
            AND Verifs.broadcastDate < %s
            GROUP BY SUBSTRING(Verifs.airTime, 1, 19), Verifs.broadcastDate
            ORDER BY airTime;
            a  

            SELECT
            MIN(Verifs.networkname) AS networkname,
            MIN(spotId) AS spotId,
            CASE
            WHEN DATE(Verifs.airTime) > '2024-03-30' THEN SUBSTRING(Verifs.airTime, 1, 19)
            ELSE SUBSTRING(DATE_SUB(Verifs.airTime, INTERVAL 1 HOUR), 1, 19)
            END AS airTime,
            MIN(Epg.emission_name) AS emission_name,
            CAST(MAX(purcent) * 1.25 * 4500000 /
            CASE
            WHEN DATE(Verifs.broadcastDate) < '2024-03-17' THEN Channels_zone.market_share
            ELSE Channels_zone.market_share
            END AS UNSIGNED) AS total_volume
            FROM Verifs
            INNER JOIN Channels_zone ON Channels_zone.id_zone_channel = Verifs.zonename
            Inner JOIN (
            SELECT sfr_channel_name, `minute`, `day`, MAX(purcent) AS purcent
            FROM SFR_analytics
            INNER JOIN Channels_zone ON Channels_zone.sfr_name = SFR_analytics.sfr_channel_name
            WHERE sfr_channel_name = Channels_zone.sfr_name
            GROUP BY sfr_channel_name, `minute`, `day`
            ) AS SFR_analytics ON (
            SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(SFR_analytics.`minute`, 1, 5)
            OR SUBSTRING(Verifs.airTime, 12, 5) = SUBSTRING(ADDTIME(SFR_analytics.`minute`, '00:01:00'), 1, 5)
            )
            AND SUBSTRING(Verifs.airTime, 1, 10) = SUBSTRING(SFR_analytics.`day`, 1, 10)
            AND Channels_zone.sfr_name = SFR_analytics.sfr_channel_name
            INNER JOIN Epg ON (
            Epg.verif_channel_id = Verifs.networkname
            AND Verifs.airTime < DATE_ADD(Epg.End_time, INTERVAL 2 HOUR)
            AND Verifs.airTime > DATE_ADD(Epg.Start_time, INTERVAL 2 HOUR)
            )
            WHERE Verifs.spotId LIKE %s
            AND Verifs.airStatusCode = '0001'
            AND Verifs.broadcastDate > %s
            AND Verifs.broadcastDate < %s
            GROUP BY
            CASE
            WHEN DATE(Verifs.airTime) > '2024-03-30' THEN SUBSTRING(Verifs.airTime, 1, 19)
            ELSE SUBSTRING(DATE_SUB(Verifs.airTime, INTERVAL 1 HOUR), 1, 19)
            END,
            Verifs.broadcastDate,
            Channels_zone.market_share,
            SFR_analytics.sfr_channel_name
            ORDER BY airTime;



            r  r   r  r  r  r  r  r  r  r   r   r   T)Zflatrr   r  r   r   r  zcore/report_advertiser.htmlr   )"re   r_   rh   r  r  r   r   r!  r   r   rZ   rX   r   r   r   
capitalizer  r#  rz   r~   r	   r   rT   rU   r   r|   Brandsr   r   r}   r   r   r-   r;   )rQ   r   r  r  r$  r  r%  r&  r'  r  r  r  r(  Zquery_11Zquery11r  r   r)  rn   r*  r+  r  r   r,  r   r   r   r   r   r   Z
brand_infor?   r?   r@   report_advertiser  s`    



"4
r0  c           	         s   ddl m} tjjdd}tjj| jd ddj|dd	d}g }g }dd l
d	  fd
dtt|D }|D ],}|tjj|d dj ||d  qz|||d}t| dd|iS )Nr   r   rr   r   r   r   dcount-dcount0123456789ABCDEFc              	      s"   g | ]}d d  d qS #r&      joinZsampler   charsrandomr?   r@   r   v  s     zstatsbrands.<locals>.<listcomp>r   r3  )labelrn   colorzcore/stats_brands.htmlr   )r  r   r   rT   rU   r   r   valuesannotater   r=  r   r}   r~   r/  rX   r   r	   )	rQ   r   chadsr?  rn   r@  adr   r?   r;  r@   statsbrandsl  s     ,rF  c                     s   ddl m}  tjjdd}tjj|ddd}dd	 |D }tjjt|d
	dj
| ddd}dd ld  fdd	tt|D }g }g }|D ],}|tjj|d dj ||d  qd S )Nr   r1  rr   r   Z0001)Znetworkname__inZairStatuscoder  c                 S   s   g | ]}|d  qS r   r?   )r   Zverifr?   r?   r@   r     s     z brand_adspot.<locals>.<listcomp>)Zname__inZchannel__inr   r2  r4  r5  c              	      s"   g | ]}d d  d qS r6  r9  r   r;  r?   r@   r     s     r   r>  r3  )r  r   r   rT   rU   ZVerifsr|   r   vrA  rB  r   r=  r   r}   r~   r/  rX   r   )r   rC  ZverifsrD  r@  r?  rn   rE  r?   r;  r@   brand_adspot  s    (rH  )r   r   r   )HttpRequestHttpResponseJsonResponseHttp404)get_object_or_404)reversec                       s:  e Zd ZdZdgZdZdddddd	Z fd
dZee	dddZ
edddZdd Zdd Zdd Zdd Zdd Zdd Zeeeef dddZd d! Zd"d# Zd$d% Zeeeef dd&d'Zed(d)d*Zeeef d(d+d,Zeeejf d(d-d.Z eedd/d0Z!edd1d2Z"ee#dd3d4Z$  Z%S )5AgencyListViewa  
    Agency List View

    This view is responsible for rendering the agencies list page of the application.
    It extends the Django View class and defines the HTTP GET method to handle
    the request and return the rendered agencies list page template with advanced
    filtering, searching, pagination, and AJAX support.

    Methods:
        get(request): Handles the HTTP GET request and returns the rendered
            agencies list page template.

    Template:
        - 'agencies/agency/list.html': The HTML template used to render the agencies list page.

    Features:
        - Advanced filtering by agency type, status, size, and date ranges
        - Full-text search across agency name, legal name, and description
        - Pagination with customizable items per page
        - AJAX support for dynamic updates
        - Statistics and analytics
        - Export functionality
        - Real-time updates
    rX   rR   zAgencies - FocuszFocus Development TeamzsAgency management for Focus advertising solutions. This page provides comprehensive agency management and insights.zXFocus, agencies, advertising solutions, agency management, marketing, data visualizationrY   )titleZauthorr-   keywordsactive_menuc                    s$   t  jf |}|dtdi |S )z
        Add agencies page context data.
        
        Args:
            **kwargs: Additional keyword arguments
            
        Returns:
            dict: Updated context data
        rP  ZAgencies)superget_context_dataupdater   )r>   kwargsr   	__class__r?   r@   rT    s    
 zAgencyListView.get_context_datarQ   returnc           	   	   O   s   |j ddkr| |S | |}t|| |}|jdd}z||}W n" tt	fk
rr   |d}Y nX | 
| | |||}t|| j|S )a  
        Handles the HTTP GET request and returns the rendered agencies list page template.

        Args:
            request (HttpRequest): The HTTP request object.
            *args: Variable length argument list.
            **kwargs: Arbitrary keyword arguments.

        Returns:
            HttpResponse: The rendered agencies list page template.

        Query Parameters:
            - search: Search term for agency name/legal_name/description
            - agency_type: Filter by agency type ID
            - status: Filter by agency status
            - size: Filter by agency size
            - date_from: Start date for filtering
            - date_to: End date for filtering
            - date_range: Predefined date range
            - sort_by: Sorting field and direction
            - page: Page number for pagination
            - per_page: Number of items per page (default: 20)
        zX-Requested-WithZXMLHttpRequestpagerr   )ZheadersrX   _handle_ajax_request_get_filtered_querysetr   _get_items_per_pager   get_pager   r   _log_user_activity_build_contextr	   template_name)	r>   rQ   argsrV  queryset	paginatorpage_numberpage_objr   r?   r?   r@   rX     s    


zAgencyListView.getru   c                 C   sx   t j dd}|jjs,|j|jd}| ||}| 	||}| 
||}| ||}| ||}| ||}|S )z
        Build filtered queryset based on request parameters.
        
        Args:
            request: Django HTTP request object
            
        Returns:
            QuerySet: Filtered agency queryset
        agency_typeZteam_membersrH   )r   rT   r   r   Zprefetch_relatedrO   is_superuserrU   _apply_search_filter_apply_agency_type_filter_apply_status_filter_apply_size_filter_apply_date_filters_apply_sorting)r>   rQ   rd  r?   r?   r@   r]    s    z%AgencyListView._get_filtered_querysetc                 C   sH   |j dd }|rD|t|dt|dB t|dB t|dB }|S )z
        Apply search filter to queryset.
        
        Args:
            queryset: Base queryset
            request: Django HTTP request object
            
        Returns:
            QuerySet: Filtered queryset
        searchr&   )Zname__icontains)Zlegal_name__icontains)Zdescription__icontains)Zemail__icontains)r   rX   r   rU   r   )r>   rd  rQ   search_queryr?   r?   r@   rk  %  s    z#AgencyListView._apply_search_filterc              	   C   sT   |j dd }|rP|dkrPzt|}|j|d}W n ttfk
rN   Y nX |S )z
        Apply agency type filter to queryset.
        
        Args:
            queryset: Base queryset
            request: Django HTTP request object
            
        Returns:
            QuerySet: Filtered queryset
        rh  r&   r   )r<   )r   rX   r   r   rU   
ValueError	TypeError)r>   rd  rQ   rh  r<   r?   r?   r@   rl  <  s    z(AgencyListView._apply_agency_type_filterc                 C   s   |j dd }|r|dkr|dkr6|jddd}q|dkrN|jddd}q|d	krf|jddd
}q|dkr~|jddd}q|dkr|jdd}n|jdd}|S )z
        Apply status filter to queryset.
        
        Args:
            queryset: Base queryset
            request: Django HTTP request object
            
        Returns:
            QuerySet: Filtered queryset
        r   r&   r   r   TF	is_activerI   inactiveverifiedis_verifiedrI   featuredr   rI   deletedrI   r   rX   r   rU   )r>   rd  rQ   Zstatus_filterr?   r?   r@   rm  R  s    z#AgencyListView._apply_status_filterc                 C   s.   |j dd }|r*|dkr*|j|d}|S )z
        Apply agency size filter to queryset.
        
        Args:
            queryset: Base queryset
            request: Django HTTP request object
            
        Returns:
            QuerySet: Filtered queryset
        r   r&   r   )r2   r  )r>   rd  rQ   Zsize_filterr?   r?   r@   rn  p  s    z!AgencyListView._apply_size_filterc                 C   sd  |j d}|j d}|j d}|rt  }|dkrJ|j|d}n|dkrp|tjdd }|j|d}np|d	kr|tj| d }|j|d
}nF|dkr|j	dd}	|j|	d
}n$|dkr|tjdd }
|j|
d
}|r z"tj
|d }|j|d
}W n tk
r   Y nX |r`z"tj
|d }|j|d}W n tk
r^   Y nX |S )z
        Apply date range filters to queryset.
        
        Args:
            queryset: Base queryset
            request: Django HTTP request object
            
        Returns:
            QuerySet: Filtered queryset
        	date_fromdate_to
date_rangetoday)Zcreated_at__date	yesterdayrr   ZdaysZ	this_week)created_at__date__gteZ
this_monthZdaylast_30_days   r  )Zcreated_at__date__lte)r   rX   r   rh   rz   rU   r_   r   weekdayr   r#  rs  )r>   rd  rQ   r  r  r  r  r  
week_startmonth_startr  Z	from_dateZto_dater?   r?   r@   ro    s@    z"AgencyListView._apply_date_filtersc                 C   sX   |j dd}dddddddd	d
dddddddddg}||krJ||}n
|d}|S )z
        Apply sorting to queryset.
        
        Args:
            queryset: Base queryset
            request: Django HTTP request object
            
        Returns:
            QuerySet: Sorted queryset
        sort_byr+   -namer,   -legal_nameagency_type__name-agency_type__namer1   -founded_yearr3   -employee_countrz  -is_verifiedr   -is_featured
created_atr   Z
updated_at-updated_at)r   rX   r   )r>   rd  rQ   r  Zvalid_sort_fieldsr?   r?   r@   rp    s0             
zAgencyListView._apply_sortingc                 C   s   |j }|j|||jdk|  |  |  | ||  | || 	 |j
|j|j|jdd|jdd|jdd|jddd}|| j |S )a  
        Build template context with all necessary data.
        
        Args:
            request: Django HTTP request object
            page_obj: Paginated page object
            paginator: Paginator instance
            
        Returns:
            dict: Template context
        rr   rq  r&   rh  r   r   )rY   rg  re  Zis_paginatedagency_typesZstatus_choicessize_choicesZfilter_paramsZsort_optionsZstatsr  total_resultscurrent_pagetotal_pagesrr  Zselected_agency_typeZselected_statusZselected_size)rO   object_list	num_pages_get_agency_types_get_status_choices_get_size_choices_get_current_filters_get_sort_options
_get_stats_get_date_ranger   numberr   rX   rU  extra_context)r>   rQ   rg  re  rO   r   r?   r?   r@   ra    s,     zAgencyListView._build_contextc              	   C   s`   zt j W S  tk
rZ   z$t   t jjddddW  Y S    g  Y  Y S X Y nX dS )z
        Get available agency types for dropdown filter.
        
        Returns:
            QuerySet: AgencyType objects ordered by sort_order and name
        Fr~  
sort_orderr+   N)r$   rT   r   r   create_default_typesrU   r   r=   r?   r?   r@   r    s    z AgencyListView._get_agency_typesc                 C   s@   dt dfdt dfdt dfdt dfd	t d
fdt dfgS )z
        Get available status choices for dropdown filter.
        
        Returns:
            list: Status choice tuples
        r   z
All Statusr   ZActiverw  ZInactiverx  ZVerifiedr{  ZFeaturedr}  ZDeletedr   r=   r?   r?   r@   r    s    





z"AgencyListView._get_status_choicesc                 C   s@   dt dfdt dfdt dfdt dfd	t d
fdt dfgS )z
        Get available agency size choices for dropdown filter.
        
        Returns:
            list: Agency size choice tuples
        r   z	All SizesstartupStartup (1-10 employees)smallSmall (11-50 employees)mediumMedium (51-200 employees)largeLarge (201-1000 employees)
enterpriseEnterprise (1000+ employees)r  r=   r?   r?   r@   r  (  s    





z AgencyListView._get_size_choicesc                 C   sr   |j dd|j dd|j dd|j dd|j dd|j dd|j d	d|j d
d|j ddd	S )z
        Get current filter parameters for template.
        
        Args:
            request: Django HTTP request object
            
        Returns:
            dict: Current filter values
        rq  r&   rh  r   r   r   r  r  r  r  r+   per_pageZ20)	rq  rh  r   r   r  r  r  r  r  )r   rX   r>   rQ   r?   r?   r@   r  8  s    z#AgencyListView._get_current_filtersrZ  c                 C   s   dt dddt dddt dddt d	dd
t dddt dddt dddt dddt dddt dddt dddt dddt dddt dddt ddgS ) z
        Get available sorting options for dropdown.
        
        Returns:
            list: Sort options for template
        r+   z
Name (A-Z))valuer?  r  z
Name (Z-A)r,   zLegal Name (A-Z)r  zLegal Name (Z-A)r  z
Type (A-Z)r  z
Type (Z-A)r  zFounded (Newest)r1   zFounded (Oldest)r  zSize (Largest)r3   zSize (Smallest)r  zVerified Firstr  zFeatured Firstr   zNewest Firstr  zOldest Firstr  zRecently Updatedr  r=   r?   r?   r@   r  N  s     z AgencyListView._get_sort_optionsc                 C   s   t j }|js|j|d}t  }|tj	dd }|
 |jddd
 |jddd
 |jddd
 |jddd
 |jdd	
 |j|dd

 |jdd	djtddd|jdd	djtddd|jddd
 d
S )z
        Get agencies statistics for dashboard.

        Args:
            user: Current user object

        Returns:
            dict: Agencies statistics
        ri     r  TFru  ry  r|  r~  )r  rI   r  r*   )r   z-countr2   )Zagency_type__is_premiumrI   )
Ztotal_agenciesZactive_agenciesZinactive_agenciesZverified_agenciesZfeatured_agenciesZdeleted_agenciesZrecent_agenciesZagencies_by_typeZagencies_by_sizeZpremium_types_count)r   rT   r   rj  rU   r   rh   rz   r_   r   r   rA  rB  r   r   )r>   rO   Zbase_querysetr  Zweek_agor?   r?   r@   r  g  sD    
  zAgencyListView._get_statsc                 C   sL   t   }||tjdd |tj| d |jdd|tjdd dS )zz
        Get date range information for filtering.
        
        Returns:
            dict: Date range options
        rr   r  r  r  )r  r  r  r  r  )r   rh   rz   r_   r   r  r   )r>   r  r?   r?   r@   r    s    
zAgencyListView._get_date_rangec              	   C   sD   z$t |jdd}tdt|dW S  ttfk
r>   Y dS X dS )z
        Get number of items per page from request.
        
        Args:
            request: Django HTTP request object
            
        Returns:
            int: Number of items per page (default 20, max 100)
        r     
   d   N)r   r   rX   r   minrs  rt  )r>   rQ   r  r?   r?   r@   r^    s
    
z"AgencyListView._get_items_per_pagec                 C   s   zt j|jdd|jr|jjnd d|t||jdd|jdd|jdd|jd	d|jd
d|jdd|jdd|jdddd W n0 tk
r } zt	d|  W 5 d}~X Y nX dS )z
        Log user activity for auditing purposes.
        
        Args:
            request: Django HTTP request object
        Zview_agencies_listrK   rL   z viewed agencies listrM   r&   rq  rh  r   r   r  r+   r[  rr   r  r  )rq  rh  r   r   r  r[  r  rN   Failed to log activity: N)
r   rV   rO   r.   r   rW   rX   r   r   r   )r>   rQ   r   r?   r?   r@   r`    s&    
z!AgencyListView._log_user_activityc           
      C   s  zP|  |}t|| |}|jdd}||}g }|jD ]}t|j|j	|j
pXd|jp`d|j|jpld|jptd|jr|jjnd|jr|jj	nd|jr|jjnd|jr|jjndd|j|j|j|j|j|j|jr|j nd|jr|jjndd}|| q@td	||j|j|j |! |" |! r4|# nd|" rH|$ ndd
	W S  t%k
r }	 ztdt|	ddd W Y S d}	~	X Y nX dS )z
        Handle AJAX requests for dynamic updates.
        
        Args:
            request: Django HTTP request object
            
        Returns:
            JsonResponse: JSON response with agencies data
        r[  rr   r&   Nz#007bffF)r*   r+   
color_code
is_premium)r*   r+   r,   r-   r.   r/   r0   rh  rv  rz  r   r2   r3   r1   r  r   T)	r   rY   r  r  r  has_previoushas_nextprevious_page_numbernext_page_number)r   rf   i  r   )&r]  r   r^  r   rX   r_  r  ri   r*   r+   r,   r-   r.   r/   r0   rh  r  r  rv  rz  r   r2   r3   r1   r  Z	isoformatr;   urlr~   rK  r   r  r  r  r  r  r  r   )
r>   rQ   rd  re  rf  rg  Zagencies_datarS   agency_datar   r?   r?   r@   r\    s^    




z#AgencyListView._handle_ajax_request)&rB   rC   rD   rE   http_method_namesrb  r  rT  rI  rJ  rX   r]  rk  rl  rm  rn  ro  rp  r   ri   r   ra  r  r  r  r  r   r  r   r  r_   rz   r  r^  r`  rK  r\  __classcell__r?   r?   rW  r@   rO    s:   13 2'rO  c                   @   s,   e Zd ZdZdgZdZeeedddZ	dS )AgencyDetailViewz_Agency Detail View with related brands summary.

    Template: agencies/agency/detail.html
    rX   zagencies/agency/detail.htmlrQ   r)   rZ  c              
   C   s   t t|d}|jjs(|j|jkr(tdtjj|d	d
d}tj|jdd|j |t||jdd	d
t|jid |||j ddd}t|| j|S )Nrk   Agency not found)rS   rS   r+   Zview_agency_detail_cbvzViewed agency detail (CBV): rM   r&   rb   rN   z
 - DetailsrY   )rS   r   rP  rR  )rM  r   rO   rj  rH   rL  r    rT   rU   r   r   r   rV   r+   r   rW   rX   ri   r*   r	   rb  )r>   rQ   r)   rS   r   r   r?   r?   r@   rX     s&    

zAgencyDetailView.getN)
rB   rC   rD   rE   r  rb  rI  ri   rJ  rX   r?   r?   r?   r@   r    s   r  c                   C   s6   zt jjddddW S  tk
r0   g  Y S X dS )z
    Helper function to get agency types for form dropdowns.
    
    Returns:
        QuerySet: AgencyType objects ordered by sort_order and name
    Fr~  r  r+   N)r$   rT   rU   r   r   r?   r?   r?   r@   get_agency_types0  s    r  c                   @   s  e Zd ZdZddgZdZeedddZeeddd	Z	ee
dd
dZe
eedddZedddZe
edddZdd Zeee
edddZeedddZdd Zdd  Zd!d" Zd#d$ Zd%d& Zd'd( Zeed)d*d+Zeed,d-d.Zeedd/d	Z	ee
dd0dZe
eedd1dZedd2dZe
edd3dZd4d Zeee
edd5dZeedd6dZd7d Zd8d  Zd9d" Zd:d$ Zd;d& Zd<d( Zeed)d=d+Zeed,d>d.Zd?S )@AgencyCreateViewa  
    Create a new Agency with comprehensive form handling.
    
    This view handles all agency form fields including:
    - Basic information (name, legal name, description)
    - Contact information (email, phone, website)
    - Business information (agency type, size, employee count, specializations)
    - Address information (street, city, state, country, postal code)
    - Localization (time zone, language)
    - Logo upload
    
    Template: agencies/agency/form.html
    rX   postagencies/agency/form.htmlrY  c           	      C   s^   |   }|  }|  }|  }|  }|  }ddd||||||dt dd}t|| j|S )z
        Render the agency creation form with all necessary dropdowns populated.
        
        Args:
            request: HTTP request object
            
        Returns:
            HttpResponse: Rendered form template
        Create New AgencyCreate AgencyTCreate Agency - FocusrY   )
form_titlesubmit_text	is_creater  r  specialization_choicestimezone_choiceslanguage_choicescountry_choicesrP  rS   rR  )	r  r  _get_specialization_choices_get_timezone_choices_get_language_choices_get_country_choicesr%   r	   rb  )	r>   rQ   r  r  r  r  r  r  r   r?   r?   r@   rX   P  s(    zAgencyCreateView.getc              
   C   s  z|  |}| ||}|r,| |||W S | ||}d|jkrT| ||jd  | ||d t|d|j	 d t
d|jdW S  tk
r } z(t|dt|  | | W Y S d}~X Y nH tk
r } z(t|d	t|  | | W Y S d}~X Y nX dS 
a   
        Handle agency creation with comprehensive validation and error handling.
        
        Args:
            request: HTTP request object
            
        Returns:
            HttpResponse: Redirect to agency detail or form with errors
        r;   rg   Agency "r   agencies:agency_detailrk   Validation error: NAn unexpected error occurred: _extract_form_data_validate_form_data_render_form_with_errors_create_agencyr   _handle_logo_upload_log_activityr   r   r+   r
   r)   ValidationErrorrf   ri   rX   r   r>   rQ   	form_datavalidation_errorsrS   r   r?   r?   r@   r  u  s"    


zAgencyCreateView.postc                 C   s   |j dd |j dd |j dd |j dd |j dd |j dd |j dd |j d	d |j d
d |j dd |j dd |j dd |j d|j dd |j dd |j dd |j dd |j dd dS z
        Extract all form data from the request.
        
        Args:
            request: HTTP request object
            
        Returns:
            dict: Extracted form data
        r+   r&   r,   r-   rh  r.   r/   r0   r1   r2   r3   r9   r'   r:   r(   specializationsr4   r5   r6   r7   r8   )r+   r,   r-   r<   r.   r/   r0   r1   r2   r3   r9   r:   r  r4   r5   r6   r7   r8   rZ   rX   r   Zgetlistr  r?   r?   r@   r    s&    
z#AgencyCreateView._extract_form_datar  rQ   rZ  c           
      C   s  g }|d s| d nt|d dkr2| d |d sF| d n| |d s^| d |d sr| d	 n8ztjj|d d
 W n  tjk
r   | d Y nX |d rt|d dkr| d |d rt|d dkr| d |d r| |d s| d |d r8t|d dkr8| d |d rzHt|d }t	
 j}|dk sr||d kr| d|d  d W n  tk
r   | d Y nX |d rz.t|d }|dk s|dkr| d W n  tk
r   | d Y nX |d  r,t|d  d!kr,| d" |d# rRt|d# d$krR| d% |d& rxt|d& d$krx| d' |d( rt|d( dkr| d) d*|jkr|jd* }| |}|| |d rtjj|d |jd+d, }	|	r| d- |S .a   
        Validate all form data and return list of errors.
        
        Args:
            form_data: Extracted form data
            request: HTTP request object
            
        Returns:
            list: List of validation error messages
        r+   r]      )Agency name cannot exceed 200 characters.r.   Email address is required.#Please enter a valid email address.r<   Agency type is required.r*    Selected agency type is invalid.r,   (Legal name cannot exceed 200 characters.r-     *Description cannot exceed 2000 characters.r0   !Please enter a valid website URL.r/   r  )Phone number cannot exceed 20 characters.r1   l  rr   &Founded year must be between 1900 and r   $Founded year must be a valid number.r3   @B /Employee count must be between 1 and 1,000,000.&Employee count must be a valid number.r4   r   ,Street address cannot exceed 255 characters.r5   r  "City cannot exceed 100 characters.r6   #State cannot exceed 100 characters.r7   (Postal code cannot exceed 20 characters.r;   FZname__iexactrH   rI   z*You already have an agency with this name.r~   r}   _is_valid_emailr$   rT   rX   r   _is_valid_urlr   r   rh   yearrs  r   _validate_logo_fileextendr   rU   rO   r   
r>   r  rQ   r   r  current_yearr   r   logo_errorsexistingr?   r?   r@   r    sv    


















z$AgencyCreateView._validate_form_datar  c                 C   sb   g }d}|j |kr|d dddddg}d|jkrH|jdd	  nd
}||kr^|d |S z
        Validate uploaded logo file.
        
        Args:
            logo_file: Uploaded file object
            
        Returns:
            list: List of validation errors
        r   r   r   r   r   r   r   r   r   r&   r   r   r~   r+   r   r   r>   r   r   r   r   r   r?   r?   r@   r  #  s    


"
z$AgencyCreateView._validate_logo_filer  rQ   c                 C   s   t jj|d d}|d |j||d dd}ddd	d
ddddddddg}|D ]}|| rL|| ||< qL|d r~t|d |d< |d rt|d |d< |d r|d |d< tjjf |}|S z
        Create the agency with validated data.
        
        Args:
            form_data: Validated form data
            request: HTTP request object
            
        Returns:
            Agency: Created agency instance
        r<   r  r+   r.   T)r+   rH   rh  r.   rv  r,   r-   r/   r0   r2   r9   r:   r4   r5   r6   r7   r8   r1   r3   r  r$   rT   rX   rO   r   r   rg   r>   r  rQ   rh  r  optional_fieldsfieldrS   r?   r?   r@   r  =  s>    
         zAgencyCreateView._create_agencyc                 C   s   ||_ |  dS z
        Handle logo file upload.
        
        Args:
            agency: Agency instance
            logo_file: Uploaded logo file
        Nr;   rp   r>   rS   r   r?   r?   r@   r  o  s    z$AgencyCreateView._handle_logo_uploadrQ   r   r  rZ  c                 C   sv   |D ]}t || q|  }|  }|  }|  }|  }	|  }
ddd|||||	|
|t ddd}t	|| j
|S a.  
        Render form with validation errors and preserve user input.
        
        Args:
            request: HTTP request object
            errors: List of error messages
            form_data: Form data to preserve
            
        Returns:
            HttpResponse: Form with errors
        r  r  Tr  rY   )r  r  r  r  r  r  r  r  r  r  rS   rP  rR  r   rf   r  r  r  r  r  r  r%   r	   rb  r>   rQ   r   r  rf   r  r  r  r  r  r  r   r?   r?   r@   r  z  s.    z)AgencyCreateView._render_form_with_errorsrQ   rP   c                 C   s   zZt j|j| dd|jj d| d|j |t||jddt|j	|j|dd W n0 t
k
r } ztd	|  W 5 d
}~X Y nX d
S z
        Log user activity.
        
        Args:
            request: HTTP request object
            agency: Agency instance
            action: Action type ('create', 'update', etc.)
        Z_agency_cbvrK   r   z
d agency: rM   r&   )rb   rc   rP   rN   r  Nr   rV   rO   r.   r+   r   rW   rX   ri   r*   r   r   r>   rQ   rS   rP   r   r?   r?   r@   r    s    	
zAgencyCreateView._log_activityc              	   C   sl   zt jjddddW S  tk
rf   z$t   t jjddddW  Y S    g  Y  Y S X Y nX dS zGet agency types for dropdown.Fr~  r  r+   Nr$   rT   rU   r   r   r  r=   r?   r?   r@   r    s    z"AgencyCreateView._get_agency_typesc                 C   s   ddddddgS zGet agency size choices.)r&   zSelect agency size...)r  r  )r  r  )r  r  )r  r  )r  r  r?   r=   r?   r?   r@   r    s    z"AgencyCreateView._get_size_choicesc              
   C   s   ddddddddd	d
g
S zGet specialization choices.)Ztv_advertisingzTV Advertising)Zdigital_marketingzDigital Marketing)Zcreative_serviceszCreative Services)Zmedia_planningzMedia Planning)Zbrand_strategyzBrand Strategy)Zpublic_relationszPublic Relations)Zsocial_mediazSocial Media)Zcontent_creationzContent Creation)Zdata_analyticszData Analytics)Zfull_servicezFull Servicer?   r=   r?   r?   r@   r    s    z,AgencyCreateView._get_specialization_choicesc              
   C   s   ddddddddd	d
g
S zGet timezone choices.)r'   r'   )zAmerica/New_YorkzEastern Time)zAmerica/ChicagozCentral Time)zAmerica/DenverzMountain Time)zAmerica/Los_AngeleszPacific Time)zEurope/LondonzLondon Time)r  z
Paris Time)zEurope/BerlinzBerlin Time)z
Asia/Tokyoz
Tokyo Time)zAustralia/SydneyzSydney Timer?   r=   r?   r?   r@   r    s    z&AgencyCreateView._get_timezone_choicesc              
   C   s   ddddddddd	d
g
S zGet language choices.)r(   ZEnglish)ZesZSpanish)frZFrench)ZdeZGerman)itZItalian)ZptZ
Portuguese)ZzhZChinese)ZjaZJapanese)ZkoZKorean)ZarZArabicr?   r=   r?   r?   r@   r    s    z&AgencyCreateView._get_language_choicesc                 C   s*   ddddddddd	d
dddddddddgS zGet country choices.)r&   zSelect country...)ZUSzUnited States)ZCAZCanada)ZGBzUnited Kingdom)ZDEZGermany)ZFRZFrance)ZESZSpain)ZITZItaly)ZAUZ	Australia)ZJPZJapan)ZCNZChina)INZIndia)ZBRZBrazil)ZMXZMexico)NLZNetherlands)ZSEZSweden)ZNOZNorway)ZDKZDenmark)ZFIZFinlandr?   r=   r?   r?   r@   r  	  s(    z%AgencyCreateView._get_country_choicesr.   rZ  c                 C   s   ddl }d}|||dk	S zValidate email format.r   Nz0^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$rematchr>   r.   r6  patternr?   r?   r@   r  	  s    z AgencyCreateView._is_valid_emailr  rZ  c                 C   sB   z&ddl m} ||}t|j|jgW S  tk
r<   Y dS X dS zValidate URL format.r   )urlparseFNZurllib.parser<  r   ZschemeZnetlocr   r>   r  r<  r   r?   r?   r@   r  "	  s    zAgencyCreateView._is_valid_urlc              
   C   s  z|  |}| ||}|r,| |||W S | ||}d|jkrT| ||jd  | ||d t|d|j	 d t
d|jdW S  tk
r } z(t|dt|  | | W Y S d}~X Y nH tk
r } z(t|d	t|  | | W Y S d}~X Y nX dS r  r  r  r?   r?   r@   r  ,	  s"    


c                 C   s   |j dd |j dd |j dd |j dd |j dd |j dd |j dd |j d	d |j d
d |j dd |j dd |j dd |j d|j dd |j dd |j dd |j dd |j dd dS r  r  r  r?   r?   r@   r  T	  s&    
c           
      C   s  g }|d s| d nt|d dkr2| d |d sF| d n| |d s^| d |d sr| d	 n8ztjj|d d
 W n  tjk
r   | d Y nX |d rt|d dkr| d |d rt|d dkr| d |d r| |d s| d |d r8t|d dkr8| d |d rzHt|d }t	
 j}|dk sr||d kr| d|d  d W n  tk
r   | d Y nX |d rz.t|d }|dk s|dkr| d W n  tk
r   | d Y nX |d  r,t|d  d!kr,| d" |d# rRt|d# d$krR| d% |d& rxt|d& d$krx| d' |d( rt|d( dkr| d) d*|jkr|jd* }| |}|| |d rtjj|d |jd+d, }	|	r| d- |S r  r
  r  r?   r?   r@   r  z	  sv    


















c                 C   sb   g }d}|j |kr|d dddddg}d|jkrH|jdd	  nd
}||kr^|d |S r  r  r  r?   r?   r@   r  	  s    


"
c                 C   s   t jj|d d}|d |j||d dd}ddd	d
ddddddddg}|D ]}|| rL|| ||< qL|d r~t|d |d< |d rt|d |d< |d r|d |d< tjjf |}|S r  r  r  r?   r?   r@   r  	  s>    
         c                 C   s   ||_ |  dS r  r  r  r?   r?   r@   r  &
  s    c                 C   sv   |D ]}t || q|  }|  }|  }|  }|  }	|  }
ddd|||||	|
|t ddd}t	|| j
|S r!  r"  r#  r?   r?   r@   r  1
  s.    c                 C   s   zZt j|j| dd|jj d| d|j |t||jddt|j	|j|dd W n0 t
k
r } ztd	|  W 5 d
}~X Y nX d
S r%  r&  r'  r?   r?   r@   r  [
  s    	
c              	   C   sl   zt jjddddW S  tk
rf   z$t   t jjddddW  Y S    g  Y  Y S X Y nX dS r(  r)  r=   r?   r?   r@   r  w
  s    c                 C   s   ddddddgS r*  r?   r=   r?   r?   r@   r  
  s    c              
   C   s   ddddddddd	d
g
S r+  r?   r=   r?   r?   r@   r  
  s    c              
   C   s   ddddddddd	d
g
S r,  r?   r=   r?   r?   r@   r  
  s    c              
   C   s   ddddddddd	d
g
S r-  r?   r=   r?   r?   r@   r  
  s    c                 C   s*   ddddddddd	d
dddddddddgS r0  r?   r=   r?   r?   r@   r  
  s(    c                 C   s   ddl }d}|||dk	S r4  r5  r8  r?   r?   r@   r  
  s    c                 C   sB   z&ddl m} ||}t|j|jgW S  tk
r<   Y dS X dS r;  r=  r>  r?   r?   r@   r  
  s    N)rB   rC   rD   rE   r  rb  rI  rJ  rX   r  r   r  r   r  r  r  r  r  ri   r  r  r  r  r  r  r  boolr  r  r?   r?   r?   r@   r  >  sH   %(&`2*
(&`2*r  c                   @   s   e Zd ZdZeeedddZeeedddZee	ddd	Z
e	eed
ddZedddZe	edddZdd Zeee	edddZeedddZeedddZeeddd Zd!d" Zd#d$ Zd%d& Zd'd( Zd)d* Zd+d, Zd-S ).AgencyUpdateViewzHUpdate an existing Agency.

    Template: agencies/agency/form.html
    r  c                 C   s   t t|d}|jjs(|j|jkr(td|  }|  }|  }| 	 }| 
 }|  }	|d|j dd||||||	d|j ddd	}
t|d
|
S Nrk   r  Update Agency: Update AgencyFUpdate  - FocusrY   )rS   r  r  r  r  r  r  r  r  r  rP  rR  r  rM  r   rO   rj  rH   rL  r  r  r  r  r  r  r+   r	   r>   rQ   r)   rS   r  r  r  r  r  r  r   r?   r?   r@   rX   
  s.    
zAgencyUpdateView.getc              
   C   sL  t t|d}|jjs(|j|jkr(tdz| |}| |||}|rX| ||||W S | 	|||}d|j
kr| ||j
d  | ||d t|d|j d td|jdW S  tk
 r } z*t|dt|  | || W Y S d	}~X Y nJ tk
rF } z*t|d
t|  | || W Y S d	}~X Y nX d	S )a!  
        Handle agency update with comprehensive validation and error handling.
        
        Args:
            request: HTTP request object
            pk: Agency primary key
            
        Returns:
            HttpResponse: Redirect to agency detail or form with errors
        rk   r  r;   rU  r  z " has been updated successfully!r  r  Nr  )rM  r   rO   rj  rH   rL  r  _validate_form_data_updater  _update_agencyr   r  r  r   r   r+   r
   r)   r  rf   ri   rX   r   )r>   rQ   r)   rS   r  r  Zupdated_agencyr   r?   r?   r@   r  	  s(    

 zAgencyUpdateView.postrY  c                 C   s   |j dd |j dd |j dd |j dd |j dd |j dd |j dd |j d	d |j d
d |j dd |j dd |j dd |j d|j dd |j dd |j dd |j dd |j dd dS r  r  r  r?   r?   r@   r  6  s&    
z#AgencyUpdateView._extract_form_datar  c                 C   s  g }|d s| d nt|d dkr2| d |d sF| d n| |d s^| d |d sr| d	 n8ztjj|d d
 W n  tjk
r   | d Y nX |d rt|d dkr| d |d rt|d dkr| d |d r| |d s| d |d r8t|d dkr8| d |d rzHt|d }t	
 j}|dk sr||d kr| d|d  d W n  tk
r   | d Y nX |d rz.t|d }|dk s|dkr| d W n  tk
r   | d Y nX |d  r,t|d  d!kr,| d" |d# rRt|d# d$krR| d% |d& rxt|d& d$krx| d' |d( rt|d( dkr| d) d*|jkr|jd* }| |}	||	 |d r|d |jkrtjj|d |jd+d,j|jd
 }
|
r| d- |S ).a6  
        Validate all form data for update and return list of errors.
        
        Args:
            form_data: Extracted form data
            request: HTTP request object
            agency: Existing agency object
            
        Returns:
            list: List of validation error messages
        r+   r]   r  r  r.   r  r  r<   r  r  r  r,   r  r-   r  r  r0   r  r/   r  r  r1   r  rr   r   r   r  r3   r  r  r  r4   r   r  r5   r  r  r6   r  r7   r  r;   Fr	  z/You already have another agency with this name.)r~   r}   r  r$   rT   rX   r   r  r   r   rh   r  rs  r   r  r  r+   r   rU   rO   Zexcluder*   r   )r>   r  rQ   rS   r   r  r  r   r   r  r  r?   r?   r@   rH  \  sz    

















z+AgencyUpdateView._validate_form_data_updater  c                 C   sb   g }d}|j |kr|d dddddg}d|jkrH|jdd	  nd
}||kr^|d |S r  r  r  r?   r?   r@   r    s    


"
z$AgencyUpdateView._validate_logo_filer  c                 C   s   t jj|d d}|d |_||_|d |_ddddd	d
ddddddg}|D ]>}|| rjt||||  qLt||tt||t	rdnd qL|d rt
|d |_nd|_|d rt
|d |_nd|_|d |_|  |S )a  
        Update the agency with validated data.
        
        Args:
            form_data: Validated form data
            request: HTTP request object
            agency: Existing agency object
            
        Returns:
            Agency: Updated agency instance
        r<   r  r+   r.   r,   r-   r/   r0   r2   r9   r:   r4   r5   r6   r7   r8   r&   Nr1   r3   r  )r$   rT   rX   r+   rh  r.   setattr
isinstancegetattrri   r   r1   r3   r  rp   )r>   r  rQ   rS   rh  r  r  r?   r?   r@   rI    s<    

         "
zAgencyUpdateView._update_agencyc                 C   s   ||_ |  dS r  r  r  r?   r?   r@   r    s    z$AgencyUpdateView._handle_logo_uploadr   c                 C   s   |D ]}t || q|  }|  }|  }|  }	|  }
|  }|d|j dd||||	|
||d|j ddd}t	|d|S )	aY  
        Render form with validation errors and preserve user input.
        
        Args:
            request: HTTP request object
            errors: List of error messages
            form_data: Form data to preserve
            agency: Existing agency object
            
        Returns:
            HttpResponse: Form with errors
        rB  rC  FrD  rE  rY   )rS   r  r  r  r  r  r  r  r  r  r  rP  rR  r  )
r   rf   r  r  r  r  r  r  r+   r	   )r>   rQ   r   r  rS   rf   r  r  r  r  r  r  r   r?   r?   r@   r    s.    
z)AgencyUpdateView._render_form_with_errorsr$  c                 C   s   zZt j|j| dd|jj d| d|j |t||jddt|j	|j|dd W n0 t
k
r } ztd	|  W 5 d
}~X Y nX d
S r%  r&  r'  r?   r?   r@   r  B  s    	
zAgencyUpdateView._log_activityr3  c                 C   s   ddl }d}|||dk	S r4  r5  r8  r?   r?   r@   r  ]  s    z AgencyUpdateView._is_valid_emailr:  c                 C   sB   z&ddl m} ||}t|j|jgW S  tk
r<   Y dS X dS r;  r=  r>  r?   r?   r@   r  c  s    zAgencyUpdateView._is_valid_urlc              	   C   sl   zt jjddddW S  tk
rf   z$t   t jjddddW  Y S    g  Y  Y S X Y nX dS r(  r)  r=   r?   r?   r@   r  n  s    z"AgencyUpdateView._get_agency_typesc                 C   s   ddddddgS r*  r?   r=   r?   r?   r@   r  y  s    z"AgencyUpdateView._get_size_choicesc              
   C   s   ddddddddd	d
g
S r+  r?   r=   r?   r?   r@   r    s    z,AgencyUpdateView._get_specialization_choicesc              
   C   s   ddddddddd	d
g
S r,  r?   r=   r?   r?   r@   r    s    z&AgencyUpdateView._get_timezone_choicesc              
   C   s   ddddddddd	d
g
S r-  r?   r=   r?   r?   r@   r    s    z&AgencyUpdateView._get_language_choicesc                 C   s*   ddddddddd	d
dddddddddgS r0  r?   r=   r?   r?   r@   r    s(    z%AgencyUpdateView._get_country_choicesN)rB   rC   rD   rE   rI  ri   rJ  rX   r  r   r  r   rH  r  rI  r  r  r  r?  r  r  r  r  r  r  r  r  r?   r?   r?   r@   r@  
  s$   -&a5+r@  c                   @   sd   e Zd ZdZeeedddZdd Zdd Z	d	d
 Z
dd Zdd Zdd ZeeedddZdS )AgencyDeleteViewzNSoft-delete an Agency.

    Template: agencies/agency/confirm_delete.html
    r  c                 C   s   t t|d}|jjs(|j|jkr(td|  }|  }|  }| 	 }| 
 }|  }	|d|j dd||||||	d|j ddd	}
t|d
|
S rA  rF  rG  r?   r?   r@   rX     s.    
zAgencyDeleteView.getc              	   C   sl   zt jjddddW S  tk
rf   z$t   t jjddddW  Y S    g  Y  Y S X Y nX dS r(  r)  r=   r?   r?   r@   r    s    z"AgencyDeleteView._get_agency_typesc                 C   s   ddddddgS r*  r?   r=   r?   r?   r@   r    s    z"AgencyDeleteView._get_size_choicesc              
   C   s   ddddddddd	d
g
S r+  r?   r=   r?   r?   r@   r    s    z,AgencyDeleteView._get_specialization_choicesc              
   C   s   ddddddddd	d
g
S r,  r?   r=   r?   r?   r@   r    s    z&AgencyDeleteView._get_timezone_choicesc              
   C   s   ddddddddd	d
g
S r-  r?   r=   r?   r?   r@   r  "  s    z&AgencyDeleteView._get_language_choicesc                 C   s*   ddddddddd	d
dddddddddgS r0  r?   r=   r?   r?   r@   r  1  s(    z%AgencyDeleteView._get_country_choicesc              
   C   s   t t|d}|jjs(|j|jkr(tdt |_d|_	|
  tj|jdd|j |t||jdddt|jid	 t|d
|j d tdS )Nrk   r  rr   Zdelete_agency_cbvzDeleted (soft) agency (CBV): rM   r&   rb   rN   r  z" deleted successfully.zagencies:agency_list)rM  r   rO   rj  rH   rL  r   rh   r_   rI   rp   r   rV   r+   r   rW   rX   ri   r*   r   r   r
   )r>   rQ   r)   rS   r?   r?   r@   r  I  s"    


zAgencyDeleteView.postN)rB   rC   rD   rE   rI  ri   rJ  rX   r  r  r  r  r  r  r  r?   r?   r?   r@   rM    s   rM  )N)N)N)N)N)N)N)r&   )r&   )_osr   r  Zrequestsr_   Zmultiprocessing.spawnr   Zdjango.viewsr   Zdjango.confr   r"  r   Zdjango.utilsr   Zdjango.contribr   Zdjango.shortcutsr	   r
   Zdjango.core.paginatorr   r   r   Zdjango.contrib.auth.mixinsr   Zdjango.utils.translationr   r   typingr   r   Zdjango.contrib.auth.decoratorsr   r  r   r   r   r   r   r  r   Zapps.common.utilsr   Zapps.channels.modelsr   Zapps.activities.modelsr   Zapps.campaigns.modelsr   r   Zapps.agencies.modelsr   r    r!   r"   r#   r$   r%   Zapps.core.utilsrF   rJ   r`   rm   rq   rs   rv   rw   r   r   r   r   r   r   r   r   r   r-  r0  rF  rH  Zdjango.httprI  rJ  rK  rL  rM  Zdjango.urlsrN  rO  r  r  r  r@  rM  r?   r?   r?   r@   <module>   s    

& & 
	

I
 '"

#
 k b
    l%       -   h