U
    !Êj8J ã                   @   s°  d dl mZ d dlmZ ddlmZmZmZmZm	Z	m
Z
mZ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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!m#Z# d dl$Z$d dl%Z%d dl&Z&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.Z.d dl/m0Z0m1Z1m2Z2 d dl3m4Z4 d dl5m6Z6m7Z7 ddl8m9Z9 d dl:m;Z; d dl!m!Z!m<Z< d dl=Z=d dl>m?Z? d dl@mAZA d dlBZBd dlmZ d dlCZCd dl mZ d dlDZDd dl>mEZE d dlFmGZG d dl3mHZH d d
lmZ d dlmZmZ d dlImJZJ d dlKmLZL d dlMmNZN d dlmZ d dlmZ d dlCZCG dd„ deNƒZOG dd „ d e6ƒZPd!d"„ ZQd#d$„ ZRd d%lmSZS eSƒ ZG d&d'„ d'eNƒZTG d(d)„ d)eNƒZUd d*l!m#Z# d dlmZ G d+d,„ d,eNƒZVG d-d.„ d.eNƒZWG d/d0„ d0eNƒZXG d1d2„ d2eNƒZYG d3d4„ d4eNƒZZG d5d6„ d6eNƒZ[G d7d8„ d8eNƒZ\G d9d:„ d:eNƒZ]G d;d<„ d<eNƒZ^G d=d>„ d>eNƒZ_d dl!m!Z!m<Z< d dl`Z`d dl`Z`d d?l!m!Z!m<Z<m#Z#m"Za d dlKmLZL d dlMmNZN d dlImJZJ dd@lmZm	Z	mZmZ d dAl!m"Z" d dlmZ d dlDZDd dl<Zbg g d dBœaceD d¡ ZedCZf�d7dEdF„ZgdGdH„ ZhdIdJ„ ZiG dKdL„ dLeNƒZjG dMdN„ dNeNƒZkG dOdP„ dPeNƒZld dl!m!Z!m<Zm d dQlnmoZompZp d dlKmLZL d dlMmNZN d dlImJZJ ddRlmZm	Z	 dSdTdUdVgZqdWdX„ ZrdYdZ„ Zsd[d\„ Ztd]d^„ Zud dl`Z`d d?l!m!Z!m<Z<m#Z#m"Za d dlKmLZL d dlMmNZN d dlImJZJ dd@lmZm	Z	mZmZ d_d`dadbdcdddegZvdfdg„ Zwdhdi„ Zxdjdk„ Zydldm„ Zzdndo„ Z{dpdq„ Z|drZ}dsdt„ Z~G dudv„ dveNƒZG dwdx„ dxeNƒZ€G dydz„ dzeNƒZ�d d{l!m<Zm emd|d}ƒZ‚d~Zƒdd€„ Z„d�d‚„ Z…�d8dƒd„„Z†d…d†„ Z‡d‡dˆ„ ZˆG d‰dŠ„ dŠeNƒZ‰G d‹dŒ„ dŒeNƒZŠG d�dŽ„ dŽeNƒZ‹G d�d�„ d�eNƒZŒG d‘d’„ d’eNƒZ�G d“d”„ d”eNƒZŽG d•d–„ d–eNƒZ�dd—lm�Z� d˜d™„ Z‘G dšd›„ d›eNƒZ’G dœd�„ d�eNƒZ“G dždŸ„ dŸeNƒZ”G d d¡„ d¡eNƒZ•G d¢d£„ d£eNƒZ–d dlCZCd d¤l!m!Z!m"Z" d dQlnmoZompZp d d¥l—m˜Z˜ d d¦l3mHZHm™Z™m4Z4 d dlmZ d dlKmLZL d dlMmNZN d dlImJZJ dd§lmZmšZšm›Z›mœZœ d¨Z�d©dª„ Zžd«d¬„ ZŸd­d®„ Z d¯d°„ Z¡d±d²„ Z¢�d9d³d´„Z£G dµd¶„ d¶eNƒZ¤G d·d¸„ d¸eNƒZ¥G d¹dº„ dºeNƒZ¦G d»d¼„ d¼eNƒZ§d½d¾„ Z¨G d¿dÀ„ dÀeNƒZ©G dÁdÂ„ dÂeNƒZªG dÃdÄ„ dÄeNƒZ«d dl3mHZH d dl¬Z¬e¬ ­e®¡Z¯dÅZ°dÆdÇ„ Z±G dÈdÉ„ dÉeNƒZ²G dÊdË„ dËeNƒZ³G dÌdÍ„ dÍeNƒZ´G dÎdÏ„ dÏeNƒZµG dÐdÑ„ dÑeNƒZ¶G dÒdÓ„ dÓeNƒZ·G dÔdÕ„ dÕeNƒZ¸G dÖd×„ d×eNƒZ¹G dØdÙ„ dÙeNƒZºd dl`Z`d d?l!m!Z!m<Z<m#Z#m"Za d dlKmLZL d dlMmNZN d dlImJZJ dd@lmZm	Z	mZmZ d_d`dadbdcdddegZvdÚdg„ ZwdÛdi„ ZxdÜdq„ Z|dÝdÞ„ Z»G dßdà„ dàeNƒZ¼G dádâ„ dâeNƒZ½G dãdä„ däeNƒZ¾d dl+Z+d dl&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Á d dçl—mÂZÂm˜Z˜ d dèl3m™Z™mÃZÃmÄZÄm4Z4 d dél,mÅZÅm-Z- d dlmZ d dlKmLZL d dêlÆmÇZÇmÈZÈ d dl:m;Z; d dlImJZJ d dlMmNZN d dëlÉmÊZÊ d dlmZ ddìlmËZËmÌZÌmÍZÍmÎZÎmÏZÏmÐZÐmZmÑZÑmÒZÒ dZÓdíZÔdîZÕdïZÖdðZ×dñZØdòZÙdódô„ ZÚdõdö„ ZÛddeLjÜfd÷dø„ZÝeLjÞdfdùdú„Zßdûdü„ Zà�d:dýdþ„Zádÿ�d „ Zâ�d�d„ Zã�d�d„ Zä�d�d„ Zå�d�d„ Zæ�d	�d
„ Zç�d�d„ ZèG �d�d„ �deNƒZéG �d�d„ �deNƒZê�d�d„ ZëG �d�d„ �deNƒZì�dZí�d�d„ Zî�d�d„ Zï�d;�d�d„Zð�d�d„ Zñ�d�d„ ZòG �d �d!„ �d!eNƒZóG �d"�d#„ �d#eNƒZô�d$�d%„ ZõG �d&�d'„ �d'eNƒZöG �d(�d)„ �d)eNƒZ÷�d*�d+�d,gZø�d-�d.„ ZùG �d/�d0„ �d0eNƒZú�d1�d2„ Zû�d3�d4„ Zü�d5�d6„ ZýdS (<  é    )Úsettings)Úrenderé   )ÚProfilesÚOtpÚProductÚSettingÚHolidayÚAnnouncementÚLeaveRequestÚPayslipÚEmployeeÚ
AttendanceÚ
DepartmentÚDesignation)ÚObjectDoesNotExist)ÚNotFound)ÚauthenticateÚlogin)ÚRefreshToken)Úmake_password)ÚUser)Útimezone)ÚdateÚdatetimeÚ	timedeltaN)ÚHttpResponse)ÚImageÚImageEnhanceÚImageFilter)ÚQ)ÚRetrieveAPIViewÚListAPIView)ÚUserSerializer)ÚIsAuthenticated)r   Útime)ÚEmailMessage)ÚBASE_DIR)Ú	send_mail)Úget_random_string)ÚSum©ÚResponse©Ústatus)ÚAPIViewc                   @   s   e Zd Zdd„ ZdS )ÚLoginAPIViewc                 C   sH  |j }| d¡}| d¡}|r"|sBttjddœddd dœtjd�S t d	|¡rŽz"tjj|d
�}t	||j
|d�}W qœ tjk
rŠ   d }Y qœX nt	|||d�}|d krÄttjddœddd dœtjd�S t||ƒ t |¡}ztjj|jd�}W n tk
�r   d }Y nX |d k	�r>|jdk�r>ttjddœddd dœtjd�S d}	d}
d}d }d }d}|}|d k	�rü|j}|j}|j}|j�r†|jj}	|jdk�ræz:tjj|jd�}tjj|jd�}|j�rÊ|jj}
|j}W n tk
�râ   Y nX n|j�rü|jj}
|j}ttjddœd d|j
|j|j|j|j t!|ƒt!|j"ƒ|	|
|||||dœdœƒS )NÚusernameÚpasswordÚerror©ÚcodeÚresponsezMissing credentialsz)Username/email and password are required.©r.   r3   ÚmessageÚdatar-   z[^@]+@[^@]+\.[^@]+©Úemail©r1   r2   zAuthentication failedzInvalid username or password©Úuser_idé   zInactive userú/Your account is inactive. Please contact Admin.ú../static/dummy.pngÚloopÚsuccesszLogin success)ÚnameÚidr1   r;   ÚisSuperÚrefreshÚtokenÚprofileÚcompanylogoÚcompanynamer2   ÚphoneÚroleÚ	geostatus)#r9   Úgetr,   r.   ÚHTTP_400_BAD_REQUESTÚreÚmatchr   Úobjectsr   r1   ÚDoesNotExistZHTTP_401_UNAUTHORIZEDr   r   Zfor_userr   rE   r   ÚHTTP_403_FORBIDDENrL   rM   rN   ÚprofilesÚurlr>   Úcreated_by_idrJ   ÚservicenameÚHTTP_200_OKÚ
first_namer;   Úis_superuserÚstrZaccess_token)ÚselfÚrequestr9   Zusername_or_emailr2   Úuser_objÚuserrH   rI   ÚproÚcomrK   rL   rM   rN   Zcreated_companyZcompany_creator_profile© rd   ú+/var/www/html/Manju/school/./myapp/views.pyÚpost”   s°    


üû
üû



üû


òüzLoginAPIView.postN©Ú__name__Ú
__module__Ú__qualname__rf   rd   rd   rd   re   r0   ’   s   r0   c                   @   s&   e Zd ZefZeZdd„ Zdd„ ZdS )ÚUserAPIViewc                 C   s   | j jS ©N)r_   ra   )r^   rd   rd   re   Ú
get_object  s    zUserAPIView.get_objectc                 C   sT   |j }tjj|d d�}tjj|d�}ttjddœd|j|j	|j
j|jjdœdœƒS )	Nr;   r:   ©ra   rC   r4   T)r1   r;   rM   rI   ©r.   r3   r9   )r9   r   rS   rO   r   r,   r.   rZ   r1   r;   rM   rE   rV   rW   )r^   r_   r9   ra   rI   rd   rd   re   rf     s    
üýzUserAPIView.postN)	rh   ri   rj   r$   Úpermission_classesr#   Zserializer_classrm   rf   rd   rd   rd   re   rk   ü   s   rk   c              
   C   s`   d}d|› d�}zt ||tj| gdd� W n0 tk
rZ } ztd|› �ƒ W 5 d }~X Y nX d S )Nú%Your One-Time  (OTP) for Verificationú?Dear User,

    Your One-Time  (OTP) for verification is:

    zâ

    Please enter this code to proceed. This OTP is valid for the next 1 minutes.

    If you did not request this code, please ignore this email.

    Thank you,  
    Pearlcon Technologies LLP
    https://pearlcons.com
    F©Úfail_silentlyúError sending email: ©r(   r   ÚDEFAULT_FROM_EMAILÚ	ExceptionÚprint©r;   ÚotpÚsubjectr8   Úerd   rd   re   Úsend_otp_email  s    üû
r~   c              
   C   s`   d}d|› d�}zt ||tj| gdd� W n0 tk
rZ } ztd|› �ƒ W 5 d }~X Y nX d S )Nrq   rr   zæ

    Please enter this code to proceed. This OTP is valid for the next 1 minutes.

    If you did not request this code, please ignore this email.

    Thank you,  
    Pearlcon Technologies LLP
    https://pearlcons.com
        Frs   ru   rv   rz   rd   rd   re   Úsend_otp_emails2  s    üû
r   )Úget_user_modelc                   @   s   e Zd Zdd„ ZdS )ÚSendotpAPIViewc              
   C   s
  |j }z°| di ¡ dd ¡}td|ƒ tjj|d� ¡ sRttj	ddœddd	œƒW S t
jj|d�}td
dd�}||_t ¡ |_| ¡  tjt||fd� ¡  ttjddœd d|idœƒW S  tk
�r } z.td|ƒ ttjddœdt|ƒd	œƒ W Y ¢S d }~X Y nX d S )NÚparamsr;   úReceived email:r:   zEmail not foundr4   TzEmail not registered©r.   r3   r8   é   Ú
1234567890©ÚlengthÚallowed_chars©ÚtargetÚargsÚSuccessro   zError:úInternal Server Error)r9   rO   ry   r   rS   ÚfilterÚexistsr,   r.   ÚHTTP_404_NOT_FOUNDr   Úcreater)   r{   r   ÚnowÚotp_created_atÚsaveÚ	threadingÚThreadr~   ÚstartrZ   rx   ÚHTTP_500_INTERNAL_SERVER_ERRORr]   )r^   r_   r9   r;   ra   r{   r}   rd   rd   re   rf   S  s8    

ý


ý


ýzSendotpAPIView.postNrg   rd   rd   rd   re   r�   R  s   r�   c                   @   s   e Zd Zdd„ ZdS )ÚSendotpsAPIViewc              
   C   sæ   |j }z˜| dd ¡}td|ƒ tjj|d� ¡ rJttj	ddœdddœƒW S t
d	d
d�}tjj||t ¡ d�}tjt||fd� ¡  ttjddœd d|idœƒW S  tk
rà } z$ttjddœdt|ƒdœƒ W Y ¢S d }~X Y nX d S )Nr;   rƒ   r:   zEmail already registeredr4   Tz;This email is already registered. Please use another email.r„   r…   r†   r‡   )r;   r{   r”   rŠ   r�   ro   rŽ   )r9   rO   ry   r   rS   r�   r�   r,   r.   ÚHTTP_409_CONFLICTr)   r   r’   r   r“   r–   r—   r   r˜   rZ   rx   r™   r]   )r^   r_   r9   r;   r{   ra   r}   rd   rd   re   rf   y  s0    

ý

ý

ýzSendotpsAPIView.postNrg   rd   rd   rd   re   rš   x  s   rš   ©r   c                   @   s   e Zd Zdd„ Zdd„ ZdS )ÚVerifyotpAPIViewc                 C   sÐ   |j  d¡}|j  d¡}z†tjj|d� d¡}|jtdd� }t 	¡ |krbt
ddd	d
œtjd�W S ||jkr„t
dddd
œtjd�W S t
ddd	d
œtjd�W S W n, tjk
rÊ   t
ddd	d
œtjd� Y S X d S )Nr;   r{   r:   r”   é<   )Úsecondsé‘  z&OTP expired. Please request a new one.T)r.   r8   r3   r-   éÈ   zOTP VerifiedFé�  zInvalid OTPé”  zOTP not found)Úquery_paramsrO   r   rS   r�   Úlatestr”   r   r   r“   r,   r.   rZ   r{   rT   )r^   r_   r;   Zotp_enteredZuser_otpZexpiration_timerd   rd   re   rO   œ  sH    ýü
ýüýüýüzVerifyotpAPIView.getc                 C   s˜   |d k	r€zJt jj|d�}|jr:|jjdd� d |_| ¡  ttjddœd ddœƒW S  t	k
r~   ttj
ddœd d	dœƒ Y S X ttjddœd
ddœƒS )Nr=   F)r•   rC   r4   z"Profile image deleted successfullyr„   ÚfailedúProfile not foundzID not providedzUser ID is required)r   rS   rO   rV   Údeleter•   r,   r.   rZ   r   r‘   rP   )r^   r_   rE   rI   rd   rd   re   r¨   Ã  s.    
ý

ý
ýzVerifyotpAPIView.deleteN)rh   ri   rj   rO   r¨   rd   rd   rd   re   r�   ›  s   'r�   c                   @   s*   e Zd ZefZdd„ Zdd„ Zdd„ ZdS )ÚProfileupdateAPIViewc                 K   s¼   |  d¡}|d k	r¸zxtjj |d�}tjj |jd�}|jrN|jjdkrN|jj}nd}|j|j|j	|j
|j||jdœ}ttjddœd |dœƒW S  tk
r¶   ttjd	dœd
ddœƒ Y S X d S )NrE   ©rE   r=   rA   )rD   r;   rL   Úf_nameZl_namerI   rE   r�   r4   ro   ÚFailedTúCompany not foundr„   )rO   r   rS   r   rE   rV   rW   rD   r;   rL   r[   Ú	last_namer,   r.   rZ   r   r‘   )r^   r_   ÚkwargsrE   ra   ÚcompanyÚprr9   rd   rd   re   rO   è  s6    

ø
ý

ýzProfileupdateAPIView.getc              
   C   sÞ   |j }zD| d¡}tjj|jjd�}||_| ¡  tt	j
ddœd ddœƒW S  tk
r’ } z*tt	jddœdd	t|ƒ› �dœƒ W Y ¢S d }~X Y nH tk
rØ } z*tt	jddœdd
t|ƒ› �dœƒ W Y ¢S d }~X Y nX d S )NÚ
prof_photor=   rC   r4   úProfile updated successfullyr„   r¦   TúMissing required field: úAn error occurred: )r9   rO   r   rS   ra   rE   rV   r•   r,   r.   ÚHTTP_201_CREATEDÚKeyErrorrP   r]   rx   r™   )r^   r_   r9   ZphoÚtaker}   rd   rd   re   rf     s.    

ý

ý
ýzProfileupdateAPIView.postc              
   C   s´  |j }�ztjj|d�}tjj|d�}| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d¡r~t	|d ƒ|_
| ¡  | d|j¡|_| d|j¡|_| d|j¡|_| d|j
¡|_
| d¡rÚ|d |_
| d	¡}|rî||_| ¡  ttjd
dœd ddœƒW S  tjk
�r>   ttjddœdddœƒ Y S  tjk
�rl   ttjddœdddœƒ Y S  tk
�r® } z$ttjddœdt|ƒdœƒ W Y ¢S d }~X Y nX d S )Nr=   rª   r[   Zfirst_namesr®   Zemail_idr2   Zphone_nor²   rC   r4   úUser updated successfullyr„   r¦   Tr§   zUser not found)r9   r   rS   rO   r   r1   r[   r®   r;   r   r2   r•   rL   rD   rV   r,   r.   rZ   rT   r‘   rx   r™   r]   )r^   r_   rE   r9   ÚmmÚsdr²   r}   rd   rd   re   Úput6  sh    



þú
	þú	þú	þúzProfileupdateAPIView.putN)rh   ri   rj   r$   rp   rO   rf   r¼   rd   rd   rd   re   r©   ä  s   (&r©   c                   @   s,   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	S )
ÚRegisterAPIViewc                 K   sž  |  d¡}|d k	rÐzŒtjj |d�}tjj |jd�}|jrN|jjdkrN|jj}nd}|j|j|j	|j
|j||j|j|j|j|j|jdœ}ttjddœd |dœƒW S  tk
rÊ   ttjd	dœd
ddœƒ Y S X �nÊ|j  d¡}t|ƒ �z„g }|j  dd¡ ¡ }	|j  dd¡ ¡ }
|j  dd¡ ¡ }|j  dd¡ ¡ }|j  dd¡ ¡ }|dk�rhtjjddd� d¡}ntjjddd� d¡}|	�r�|j|	d�}|�r¢|j|d�}|�r´|j|d�}|
�rÆ|j|
d�}|�rz"t|ƒ}|dk�rì|j|d�}W n tk
�r   Y nX |D ]F}tjj |jd�}|j|j|j	|j|j|j
|j	|jd œ}| |¡ �q
ttjddœd |dœƒW S  tk
�r˜   ttj d	dœd
d!dœƒ Y S X d S )"NrE   rª   rn   rA   )rD   r;   rL   ÚaddressÚpincoderI   Ú	firstnameÚlastnameÚgenderÚdojr2   rE   r�   r4   ro   r¬   Tr­   r„   ÚvalZ
vendornameÚ r¿   r;   rL   r.   Ú2r?   r   )r.   rM   z-user_idr   ©Zname__icontains©Zemail__icontains©Zphone__icontains)Zpincode__icontains)r   r?   r-   )rD   rE   rL   r¿   r;   r¾   rL   r.   úSomething went wrong)!rO   r   rS   r   rE   rV   rW   rD   r;   rL   r¾   r¿   r[   r®   rÂ   rÃ   r2   r,   r.   rZ   r   r‘   ÚGETry   r¤   Ústripr�   Úorder_byÚintÚ
ValueErrorr>   ÚappendrP   )r^   r_   r¯   rE   ra   r°   r±   r9   rÄ   r1   r¿   r;   rL   Ústatus_paramÚ	companiesZ
status_intÚusersZcompany_datard   rd   re   rO   ƒ  s¤    

ï
ý

ý

	ó
ý

ýzRegisterAPIView.getc              
   C   s,  |j }z�| d¡}| d¡}| d¡}| d¡}| d¡}| d¡}t|ƒ}	t|||	d�}
|
 ¡  t||||||
d�}| ¡  ttjd	d
œd ddœƒW S  t	k
rÞ } z*ttj
dd
œddt|ƒ› �dœƒ W Y ¢S d }~X Y nJ tk
�r& } z*ttjdd
œddt|ƒ› �dœƒ W Y ¢S d }~X Y nX d S )NZemployeenamer;   Zmobilenumberr¾   r¿   r2   )r1   r;   r2   )r2   rD   r;   rL   r¾   ra   rC   r4   z New User Registered successfullyr„   r¦   Tr´   rµ   )r9   rO   r   r   r•   r   r,   r.   r¶   r·   rP   r]   rx   r™   )r^   r_   r9   rD   r;   rL   r¾   r¿   r2   Úhashed_passwordÚvanÚprofile_datar}   rd   rd   re   rf   
  sJ    





   ý
ý

ý
ýzRegisterAPIView.postc           
      C   s®  |j  d¡}|j}|j d¡}|dkrltjj|d�}|jdkrFd|_nd|_| ¡  ttj	ddœd d	d
œƒS |dkrºtjj|d�}|jdkr”d|_nd|_| ¡  ttj	ddœd dd
œƒS |�r4tjj|d�}|d |_
|d |_|d |_|d |_|d |_|d |_|d |_| ¡  ttj	ddœd dd
œƒS �zDtjj|d�}tjj|d�}	|d |_|d |_|d |_|d |_|d |_|d |_|d |_|d |_|d |_|d |_|d |_|d  |_|d! |_|d" |_|d# |_ |d$ |_!|d% |_"|d& |_#|d' |_$|d( |_%| ¡  |d |	_&|d) |	_'|d* |	_(|d |	_t)|d( ƒ|	_%|	 ¡  ttj	ddœd d+d
œƒW S  t*k
�r¨   ttj+d,dœd-d.d
œƒ Y S X d S )/NrÄ   ÚctcÚ1r=   r   r?   rC   r4   zWFH updated successfullyr„   rÆ   zInactive updated successfullyÚgrossÚptÚuanÚpanÚaccountÚreimz#Salary details updated successfullyrª   rD   ÚpemailÚshiftÚmarriedstatusrÂ   r;   rL   r¾   ÚcityÚstateÚcountryr¿   Ú
departmentÚdesignationrM   Ú	authorityrÃ   rV   Úempcoder2   rÀ   rÁ   r¹   r¦   TrÊ   ),rË   rO   r9   r   rS   Zwfhr•   r,   r.   r¶   r×   rÙ   rÚ   rÛ   rÜ   rÝ   rÞ   r   rD   rß   rà   rá   rÂ   r;   rL   r¾   râ   rã   rä   r¿   Údepartment_idÚdesignation_idrM   Úauthority_idrÃ   rV   rè   r2   r1   r[   r®   r   r   rP   )
r^   r_   rE   rÄ   r9   r×   ZpoZmeowrº   r»   rd   rd   re   r¼   L  s¢    

ý

ý







ý
























ý

ýzRegisterAPIView.putc                 O   s‚   |  d¡}zFtjj |d�}| ¡  tjj |d�}| ¡  ttjddœd ddœƒW S  tk
r|   ttj	ddœd	d
dœƒ Y S X d S )NrE   r=   rª   rC   r4   zCompany deleted successfullyr„   r¦   TúNo data found)
rO   r   rS   r¨   r   r,   r.   rZ   r   r‘   )r^   rŒ   r¯   Z
company_idr±   r°   rd   rd   re   r¨   «  s"    

ý

ýzRegisterAPIView.deleteN)rh   ri   rj   rO   rf   r¼   r¨   rd   rd   rd   re   r½   ‚  s
    B_r½   c                   @   s   e Zd Zdd„ ZdS )ÚCompanydashboardAPIViewc                 C   sè   z¶ddl m} |jj}tjj|d� ¡ }ddl m} ddlm	} |jj}|ƒ }d}d}d}	d}
d}d}d	}d}d}d
}d}d}|||	|
|||||||||dœ}t
tjddœd |dœƒW S  tk
râ   t
tjddœdddœƒ Y S X d S )Nr   )r“   ©rX   rœ   r…   é   é   é   é	   é   r?   )ÚtotalenquiryÚtotalvendorÚtotalenquirytodaydateÚactivevendorÚinactivevendorÚ	monthdataÚtotalvendorlastmonthÚcurrent_month_enquiryÚlast_month_enquiryÚcurrent_month_auctionÚlast_month_auctionÚcurrent_month_productÚlast_month_productrC   r4   ro   r¦   Trì   r„   )Údjango.utils.timezoner“   ra   rE   r   rS   r�   Úcountr   r   r,   r.   rZ   r   r‘   )r^   r_   r“   Úoprô   r   Zcurrent_daterú   rõ   rö   r÷   rù   rø   rü   rû   rý   rþ   rÿ   r   r9   rd   rd   re   rO   Æ  sZ    ó
ý

ýzCompanydashboardAPIView.getN©rh   ri   rj   rO   rd   rd   rd   re   rí   Ã  s   rí   c                   @   s   e Zd Zddd„ZdS )ÚCheckcompanyAPIViewNc           	      C   sî   |j  d¡}|j  d¡}|j  d¡}|j  d¡p:|j  d¡}td|||ƒ |sZ|sZ|sZ|rÐtƒ }|rr|t|d�O }|r„|t|d�O }|r–|t|d	�O }|r¨|t|d
�O }tj |¡ ¡ }tt	j
ddœd |dœƒS tt	jddœdddœt	jd�S )NrL   r;   r1   Ú	gstnumberÚgstzCheck Params:)rD   )rL   r:   )r  rC   r4   )r.   r3   r�   r¦   Tz!No phone, email, or GST provided.r„   r-   )r¤   rO   ry   r    r   rS   r�   r�   r,   r.   rZ   rP   )	r^   r_   rE   rL   r;   rD   r  Úqueryr�   rd   rd   re   rO     s8    
ý
ýüzCheckcompanyAPIView.get)Nr  rd   rd   rd   re   r    s   r  c                   @   s   e Zd ZdZefZdd„ ZdS )ÚDashboardapiAPIViewa}  
    GET /dashboardapi/?date=YYYY-MM-DD
 
    - Late count: Setting.shift_start + Setting.grace_minutes (NOT hardcoded)
    - Holiday / Weekly-off: Holiday table + Setting.weekly_off
    - Holiday/Weekly-off nu iruntha, "Absent" concept illa (working day illa),
      so absent_list empty-a return aagum, is_holiday/is_weekly_off flag-a paathu
      frontend banner kaatikkum.
    c                 C   sü  |j  d¡}z |r"t |d¡ ¡ nt ¡ }W n tk
rH   t ¡ }Y nX tƒ }t	||ƒ}| |¡}| 
¡ |d k}t|ƒp~|}tjjdd�}	|	 ¡ }
tjj|dd�}| ¡ }|j|d d	� ¡ }g }|�s.|jd
dd�}|	j|d�}|D ]B}t|dd ƒ�r| |jj¡ dd¡nd }| |j|j|dœ¡ qê|
dk�rHt||
 d ƒnd}|dk�rft|| d ƒnd}tdddœd||
|dœd|||dœ|| d¡|d  d¡|d  d¡|d |d  d¡t| d¡�pÞdd „ |d D ƒƒd!œt|ƒ|||d"œ	d#œƒS )$Nr   ú%Y-%m-%dÚ
weekly_offr   r-   ÚPresent)r   r.   Ú
late_after)Zin_time__gtÚemployee_idT©Úflat©Zid__inÚphotoúhttp://úhttps://)rE   rD   Úimager   éd   r¡   rC   r4   zActive Staff)ÚlabelZpresentÚtotalÚpercentz
Late EntryÚshift_startú%I:%M %pÚ	shift_endÚgrace_minutesÚweekly_off_namesc                 S   s   h | ]}t | ’qS rd   ©ÚDAY_KEYS©Ú.0Úird   rd   re   Ú	<setcomp>‰  s     z*DashboardapiAPIView.get.<locals>.<setcomp>)r˜   Úendr  r  r  )	Zn_dataZs_dataZabsent_employeesZselected_daterà   Ú
is_holidayÚholiday_nameÚis_weekly_offÚ
is_off_day©r.   r9   )r¤   rO   r   Ústrptimer   Údate_clsÚtodayrÏ   Úget_attendance_configÚget_holiday_mapÚweekdayÚboolr   rS   r�   r  r   Úvalues_listÚexcludeÚgetattrÚbuild_absolute_urir  rW   ÚreplacerÐ   rE   rD   rÎ   r,   ÚstrftimeÚsorted)r^   r_   Údate_strÚtarget_dateÚcfgÚholiday_mapÚhol_namer(  r)  Zall_empÚtotal_countZpresent_todayÚpresent_countÚ
late_countÚabsent_listZpresent_emp_idsZabsent_empsÚempZ	image_urlZ	p_percentZ	l_percentrd   rd   re   rO   D  sv    ÿþ

(ý
üüÿûáþzDashboardapiAPIView.getN©rh   ri   rj   Ú__doc__r$   rp   rO   rd   rd   rd   re   r	  8  s   	r	  c                   @   s   e Zd Zdd„ ZdS )ÚStudentClassCountAPIViewc              
   C   s’   zPt jj|dd� ¡ }t jj|dd� ¡ }t||dƒ tdddœ||dœd	œƒW S  tk
rŒ } ztd
t|ƒitj	d� W Y ¢S d }~X Y nX d S )Nr   )Ú
student_idÚsession_typer?   Zjsabdbsdsmdbasmdbsandr¡   rC   r4   )Únormal_countÚspecial_countr*  r3   r-   )
r   rS   r�   r  ry   r,   rx   r]   r.   rP   )r^   r_   rE   rH  rI  r}   rd   rd   re   rO   —  s    þþ
zStudentClassCountAPIView.getNr  rd   rd   rd   re   rE  –  s   rE  c                   @   s6   e Zd Zddd„Zdd„ Zdd„ Zdd	„ Zd
d„ ZdS )ÚEmployeeAPIViewNc                 C   s  |d k	� rúz¼t jj|d�}tjj|jd�}|j|j|j|j|j	|j
rL|j
jnd |j
r\|j
jnd|jrl|jjnd |jr||jjnd|j|j|jr¢| |jj¡ dd¡nd |jdœ}ttjddœd |d	œƒW S  t jk
rô   ttjd
dœdddœƒ Y S X �n
zÄt j ¡  d¡}g }t|dƒD ]€\}}tjj|jd�}	| ||j|j|j|j
�rT|j
jnd|j�rf|jjnd|	j|	j|j�rŽ| |jj¡ dd¡nd dœ	¡ �qt|dƒ ttjddœd |d	œƒW S  tk
�r }
 z$ttjd
dœdt|
ƒdœƒ W Y ¢S d }
~
X Y nX d S )Nrª   r=   zN/Ar  r  )rE   rD   ÚmobileÚager¾   ré   Zdepartment_namerê   Zdesignation_namerÃ   r.   Úprofile_picr2   rC   r4   ro   r¦   TzNo employee foundr„   ú-created_atr   )	ÚrowrE   rD   rK  rå   ræ   r.   rN   rM  ZHHHHHHHHHHHHHHHHHHHH) r   rS   rO   r   Úusers_idrE   rD   rK  rL  r¾   rå   ræ   rÃ   r.   r  r5  rW   r6  r2   r,   rZ   rT   r‘   ÚallrÍ   Ú	enumeraterÐ   rN   ry   rx   rP   r]   )r^   r_   rE   rB  Zprofr9   Ú	employeesZemp_listÚindexrb   r}   rd   rd   re   rO   °  sr    
ò
ý

ý ÷

ý

ýzEmployeeAPIView.getc              
   C   sÊ   |j s
dS |j j}tj |¡s"dS zZt|ƒ\}}|s:W dS tj||dd�}|sTW dS | |d ¡ tƒ  t	d|j
› �ƒ W d	S  tk
rÄ } z*t	d
|j
› d|› �ƒ dt|ƒf W Y ¢S d}~X Y nX dS )uç   
        Employee photo-à®µà®¿à®²à¯� face encoding à®Žà®Ÿà¯�à®¤à¯�à®¤à¯� save à®ªà®£à¯�à®£à¯�à®®à¯�.
        à®Žà®¨à¯�à®¤ size photo-à®µà¯�à®®à¯� handle à®ªà®£à¯�à®£à¯�à®®à¯�.
        Returns: (success: bool, message: str)
        )Fõ   Photo à®‡à®²à¯�à®²à¯ˆ)Fu2   Photo file à®•à®¿à®Ÿà¯ˆà®•à¯�à®•à®µà®¿à®²à¯�à®²à¯ˆ)Fu>   Photo-à®²à¯� à®®à¯�à®•à®®à¯� à®¤à¯†à®°à®¿à®¯à®µà®¿à®²à¯�à®²à¯ˆrï   ©Zknown_face_locationsZnum_jitters)Fu$   Face encode à®†à®•à®µà®¿à®²à¯�à®²à¯ˆr   z[Encoding] Saved for: )TzEncoding savedz[Encoding Error] ú: FN)r  ÚpathÚosr�   Úpreprocess_imageÚface_recognitionÚface_encodingsÚsave_encodingÚinvalidate_cachery   rD   rx   r]   )r^   ÚemployeeZ
photo_pathÚ	img_arrayÚface_locationsÚ	encodingsr}   rd   rd   re   Ú_save_face_encodinge  s.    ýz#EmployeeAPIView._save_face_encodingc                 C   s   |j }|j d¡}�z¼| d¡}| d¡}|r<tjj|d�nd }|rRtjj|d�nd }| d¡pbd ¡ }| d¡}	| d¡p„| d	¡}
| d
¡}|s®ttj	ddœdddœƒW S | 
dd¡› d�}t|ƒ}| 
dd¡ ¡ }|}d}tjj|d� ¡ �r
|› |› �}|d7 }qàt||d�}| ¡  td|||
|||d�}| ¡  tjj|| d¡| d¡|||| d¡||j|jj�rx|jnd d�
}d}|�r´|  |¡\}}|�s´td|j› d|› �ƒ ttjddœd d||dœƒW S  tk
�r } z*ttj	ddœdd t|ƒ› �dœƒ W Y ¢S d }~X Y nX d S )!NrM  rå   ræ   rª   rD   rÅ   r;   rK  rL   r¾   r¦   r4   TzName is requiredr„   ú z@123r   )r1   r<   é   )rM   r2   rD   rL   r¾   ra   rV   rL  rÃ   )
rD   rK  rL  r¾   rå   ræ   rÃ   r  rP  Ú
created_byrU  z[Warning] Encoding failed for rW  rC   zEmployee created successfully)r.   r3   r8   Úencoding_statusZlogin_usernameúError: )r9   ÚFILESrO   r   rS   r   rÌ   r,   r.   rP   r6  r   Úlowerr   r�   r�   r•   r   r   r’   rE   ra   Úis_authenticatedrc  ry   rD   r¶   rx   r]   )r^   r_   r9   rM  Zdept_idZdesig_idZdeptZdesigrD   r;   rL   r¾   Úraw_passwordrÔ   Zbase_usernamer1   ÚcounterrÕ   rÖ   r_  rg  Úokr}   rd   rd   re   rf   Š  s†    




ý

ù	ö
û

ýzEmployeeAPIView.postc              
   C   sš  |j }|j d¡}�ztjj|d�}d|krBtjj| d¡d�|_d|kr`tjj| d¡d�|_| d¡r|| d|j	¡ 
¡ n|j	}||j	k}||_	| d|j¡|_| d|j¡|_| d|j¡|_| d	|j¡|_| d
|j¡|_|rì||_| ¡  d}|j}	|	�rÎz’tjj|	d�}
tjj|
d�}| d¡}||_	| d|j¡|_| d|j¡|_|�r^||_|�rj||
_|�r€t|ƒ|
_||_|
 ¡  | ¡  d}W n6 tjk
�r²   d}Y n tjk
�rÌ   d}Y nX d}|�sè|j�r|j�s|  |¡\}}|�std|j	› d|› �ƒ tdddœd||dœƒW S  tjk
�rV   tdddœddœƒ Y S  tk
�r” } z tdddœt |ƒdœƒ W Y ¢S d }~X Y nX d S )NrM  rª   rå   ræ   rD   rK  rL  r¾   rÃ   r.   zProfile link illarn   r2   r³   zUser record not foundzProfile record not foundu!   Photo à®®à®¾à®±à®µà®¿à®²à¯�à®²à¯ˆz%[Warning] Encoding update failed for rW  r¡   rC   r4   zEmployee updated successfully)r.   r8   rg  Úprofile_statusr£   r¦   úEmployee not found©r.   r8   r¢   )!r9   ri  rO   r   rS   r   rå   r   ræ   rD   rÌ   rK  rL  r¾   rÃ   r.   r  r•   rP  r   r   rL   rV   r1   r   r2   rT   Úface_encoding_datarc  ry   r,   rx   r]   )r^   r_   rE   r9   rM  rB  Únew_nameZname_changedro  r>   Zvan_userZprofile_objrl  rg  rn  r}   rd   rd   re   r¼   Þ  sŒ    "

 ÿ ÿ

ü
þþzEmployeeAPIView.putc                 C   s\   z,t jj|d�}| ¡  tdddœddœƒW S  t jk
rV   tdddœd	dœƒ Y S X d S )
Nrª   r¡   rC   r4   zEmployee deletedrq  r£   r¦   z	Not found)r   rS   rO   r¨   r,   rT   )r^   r_   rE   rB  rd   rd   re   r¨   I  s    þ
zEmployeeAPIView.delete)N)rh   ri   rj   rO   rc  rf   r¼   r¨   rd   rd   rd   re   rJ  ­  s   
 6%TkrJ  c                   @   s   e Zd Zdd„ ZdS )ÚFetchdesignationAPIViewc                 C   sH   t jj|d�}g }|D ]}| |j|jdœ¡ qttjddœd |dœƒS )N)ré   )rD   rE   rC   r4   ro   )	r   rS   r�   rÐ   rD   rE   r,   r.   rZ   )r^   r_   rE   r°   r9   r#  rd   rd   re   rO   t  s    þ

ýzFetchdesignationAPIView.getNr  rd   rd   rd   re   rt  s  s   rt  c                   @   s   e Zd Zdd„ ZdS )ÚStudentStatusAPIViewc                 C   st   zHt jj|d�}|jdkr"d|_nd|_| ¡  tdddœ|jddœƒW S  t jk
rn   td	d
idd� Y S X d S )Nrª   r   r?   r¡   rC   r4   úStatus updated successfully©r.   Ú
new_statusr8   r3   zStudent not foundr£   r-   )r   rS   rO   r.   r•   r,   rT   )r^   r_   rE   Ústudentrd   rd   re   Úpatch‰  s    
ý
zStudentStatusAPIView.patchN©rh   ri   rj   rz  rd   rd   rd   re   ru  ˆ  s   ru  )r   r%   r   r   )r   r	   r   r   ©r   )rb  ÚidsÚlast_reloadé,  Fc              	   C   sº   t  ¡ }t�¤ | s0|td  tk r0W 5 Q R £ d S tjjdd�jdd�}g g  }}|D ]*}| ¡ }|d k	rT| 	|¡ | 	|j
¡ qT|td< |td< |td< tdt|ƒ› d	�ƒ W 5 Q R X d S )
Nr~  T)Zface_encoding_data__isnullrÅ   )rr  rb  r}  z[Cache] z encodings loaded.)Útime_moduler%   Ú_cache_lockÚ_encoding_cacheÚ	CACHE_TTLr   rS   r3  Úget_encodingrÐ   rE   ry   Úlen)Úforcer“   rS  rb  r}  rB  Úencrd   rd   re   Úload_encoding_cache  s&    ÿþ

rˆ  c                	   C   s   t � dtd< W 5 Q R X d S )Nr   r~  )r�  r‚  rd   rd   rd   re   r^  .  s    r^  c                 C   s¶  t | tƒrt | ¡ d¡}n$|  d¡ t t |  ¡ ¡¡ d¡}|j	\}}t
d|› d|› �ƒ t||ƒ}|dk r¸d| }| t|| ƒt|| ƒftj¡}|j	\}}t
d|› d|› �ƒ t||ƒ}|dk�rd| }| t|| ƒt|| ƒftj¡}|j	\}}t
d	|› d|› �ƒ t |¡ d
¡}t |¡ d¡}t |¡ d¡}t |¡}tj|ddd�}t
dt|ƒ› d�ƒ |�r€||fS tj|ddd�}t
dt|ƒ› d�ƒ |�r²||fS t t |¡ d¡¡}	tj|	ddd�}t
dt|ƒ› d�ƒ |�rú|	|fS |dk�rtd| | ƒnd}
| d|
ftj¡}t |¡}tj|ddd�}t
dt|ƒ› d�ƒ |�rf||fS | tj¡}t |¡}tj|ddd�}t
dt|ƒ› d�ƒ |�r®||fS |g fS )u  
    source: uploaded file object à®…à®²à¯�à®²à®¤à¯� file path string
 
    5 different attempts-à®²à¯� face detect à®ªà®£à¯�à®£à¯�à®®à¯�:
      1. Normal HOG
      2. HOG + upsample (small photos)
      3. Extra brightness (dark photos)
      4. 800px width resize (portrait photos)
      5. Horizontally flipped (selfie mirror issue)
 
    Returns: (img_array, face_locations)
    ZRGBr   z[DEBUG] Original size: Úxr¡   r  z[DEBUG] Upscaled to: i°  z[DEBUG] Downscaled to: g333333ó?gÍÌÌÌÌÌô?g      ø?Zhogr   )ÚmodelZnumber_of_times_to_upsamplez[DEBUG] Attempt 1 (HOG): z facesr?   z$[DEBUG] Attempt 2 (HOG upsample=2): gÍÌÌÌÌÌü?z"[DEBUG] Attempt 3 (extra bright): i   z![DEBUG] Attempt 4 (800w resize): z[DEBUG] Attempt 5 (flipped): )Ú
isinstancer]   r   ÚopenÚconvertÚseekÚioÚBytesIOÚreadÚsizery   ÚminÚresizerÎ   ZLANCZOSÚmaxr   Z
BrightnessZenhanceZContrastZ	SharpnessÚnpÚarrayr[  ra  r…  Ú	transposeZFLIP_LEFT_RIGHT)ÚsourceZpil_imgÚwÚhÚshortÚscaleÚlongr`  ÚlocsZ
bright_arrZnew_hZresizedZ
resize_arrZflippedZflip_arrrd   rd   re   rZ  7  sn    



 ÿ


 ÿ



rZ  c                   @   s   e Zd Zdd„ Zdd„ ZdS )ÚAttendanceAPIViewc           	      C   sê   z¢|j  dt ¡  ¡ ¡}|j  d¡}tjj|d� d¡}|rH|j|d�}g }t	|dƒD ]2\}}| 
||j|jj|jj|j|j|jdœ¡ qVttjdd	œd |d
œƒW S  tk
rä } z$ttjdd	œdt|ƒdœƒ W Y ¢S d }~X Y nX d S )Nr   rG  r|  rN  )rG  r   )rO  rE   Z	studentIdÚstudentNamer.   rG  r   rC   r4   ro   r¦   Tr„   )r¤   rO   r   r-  Ú	isoformatr   rS   r�   rÍ   rR  rÐ   rE   ry  r¡  r.   rG  r,   rZ   rx   rP   r]   )	r^   r_   Z
query_daterG  ZattendancesZattendance_listrT  Úattr}   rd   rd   re   rO   •  s8    ù
	
ý

ýzAttendanceAPIView.getc              
   C   sò  |j  d¡}|s tddidd�S �z€t|ƒ\}}|sFtddidd�W S tj||dd�}|sltdd	idd�W S |d
 }tƒ  td }td }|s tddidd�W S t ||¡}	t	t
 |	¡ƒ}
t|	|
 ƒ}td|d›d�ƒ |dkròtddidd�W S ||
 }tjj|d�}t ¡  ¡ }t ¡  ¡ }|j d¡}tjj|j|d||dœd�\}}|�sr||_| ¡  d|j› �}d}nd|j› �}d}td||j|t|dƒdœd œƒW S  tk
�rì } z*td!|› �ƒ td"t|ƒid#d� W Y ¢S d }~X Y nX d S )$Nr  r8   zImage requiredr¢   r-   u†   à®®à¯�à®•à®®à¯� à®šà®°à®¿à®¯à®¾à®• à®¤à¯†à®°à®¿à®¯à®µà®¿à®²à¯�à®²à¯ˆ! à®¨à¯‡à®°à®Ÿà®¿à®¯à®¾à®• camera-à®� à®ªà®¾à®°à¯�à®™à¯�à®•à®³à¯�.r   rV  u¡   à®®à¯�à®•à®®à¯� à®¤à¯†à®°à®¿à®•à®¿à®±à®¤à¯� à®†à®©à®¾à®²à¯� encode à®†à®•à®µà®¿à®²à¯�à®²à¯ˆ. à®®à¯€à®£à¯�à®Ÿà¯�à®®à¯� à®®à¯�à®¯à®±à¯�à®šà®¿à®•à¯�à®•à®µà¯�à®®à¯�.r   rb  r}  uq   à®ªà®¤à®¿à®µà¯� à®šà¯†à®¯à¯�à®¯à®ªà¯�à®ªà®Ÿà¯�à®Ÿ à®®à¯�à®•à®™à¯�à®•à®³à¯� à®Žà®¤à¯�à®µà¯�à®®à¯� à®‡à®²à¯�à®²à¯ˆ!z[DEBUG] Best match distance: z.4fz (threshold: 0.50)ç      à?ub   à®¯à®¾à®°à¯� à®Žà®©à¯�à®±à¯� à®…à®Ÿà¯ˆà®¯à®¾à®³à®®à¯� à®•à®¾à®£ à®®à¯�à®Ÿà®¿à®¯à®µà®¿à®²à¯�à®²à¯ˆ!r    rª   Zlocation_namer  )r.   Úin_timeÚlocation)r  r   Údefaultsu@   à®µà¯†à®³à®¿à®¯à¯‡à®±à¯�à®®à¯� à®¨à¯‡à®°à®®à¯� à®ªà®¤à®¿à®µà¯�: Úoutu!   à®µà®°à¯�à®•à¯ˆ à®ªà®¤à®¿à®µà¯�: ÚinrC   re  )rD   ÚactionZdistance)r.   r8   r9   z[ERROR] Attendance post: r3   iô  )ri  rO   r,   rZ  r[  r\  rˆ  r‚  Zface_distancerÎ   r–  ÚargminÚfloatry   r   rS   r   r“   r   r%   r9   r   Úget_or_createrE   Úout_timer•   rD   Úroundrx   r]   )r^   r_   Úuploaded_filer`  ra  Ztarget_encodingsZ
target_encZknown_encodingsZ	known_idsZface_distancesZbest_idxZbest_distanceÚemp_idZ
found_userr-  Znow_timer¦  r£  ÚcreatedÚmsgrª  r}   rd   rd   re   rf   ´  s”     ÿþý ÿþ ÿþ ÿþ
ý
ýý

zAttendanceAPIView.postN©rh   ri   rj   rO   rf   rd   rd   rd   re   r   “  s   r   c                   @   s4   e Zd ZefZd
dd„Zdd„ Zdd„ Zdd	„ ZdS )ÚDesignationAPIViewNc              	   C   s6  |d k	rvz>t jj|d�}|j|j|j|jdœ}ttj	ddœd |dœƒW S  t
k
rr   ttjddœddd	œƒ Y S X n¼zŒd
}g }t j ¡ D ]^}|d7 }ztjj|jd�}|j}W n tjk
rÊ   d}Y nX | ||j|j|j|dœ¡ qŠttj	ddœd |dœƒW S  t
k
�r0   ttjddœddd	œƒ Y S X d S )Nrª   )rE   rD   Údescriptionrå   rC   r4   ro   r¦   Trì   r„   r   r   rÅ   )rO  rE   rD   r¶  rå   )r   rS   rO   rE   rD   r¶  ré   r,   r.   rZ   r   r‘   rQ  r   rT   rÐ   )r^   r_   rE   ræ   r9   rT  Zdesignationsrå   rd   rd   re   rO     s^    ü
ý

ý

û

ý

ýzDesignationAPIView.getc              
   C   sž   |j }zNtjj|d |d tjj|d d�|jd�}| ¡  tt	j
ddœd dd	œƒW S  tk
r˜ } z&tt	jd
dœdd|› �d	œƒ W Y ¢S d }~X Y nX d S )NrD   r¶  rå   rª   )rD   r¶  rå   rf  rC   r4   z Designation created successfullyr„   r¦   Tr´   )r9   r   rS   r’   r   rO   ra   r•   r,   r.   r¶   r·   rP   )r^   r_   r9   rå   r}   rd   rd   re   rf   E  s(    ü
ý

ýzDesignationAPIView.postc                 C   s�   |j }zXtjj|d�}|d |_|d |_tjj|d d�|_| ¡  t	t
jddœd ddœƒW S  tk
rŠ   t	t
jd	dœd
ddœƒ Y S X d S )Nrª   rD   r¶  rå   rC   r4   z Designation updated successfullyr„   r¦   Trì   )r9   r   rS   rO   rD   r¶  r   rå   r•   r,   r.   rZ   r   r‘   )r^   r_   rE   r9   ræ   rd   rd   re   r¼   ]  s$    


ý

ýzDesignationAPIView.putc                 C   s„   |d k	rhz0t jj|d�}| ¡  ttjddœd ddœƒW S  tk
rd   ttjddœd ddœƒ Y S X nttj	ddœd ddœƒS d S )	Nrª   rC   r4   z Designation deleted successfullyr„   r¦   rì   rÊ   )
r   rS   rO   r¨   r,   r.   rZ   r   r‘   rP   )r^   r_   rE   ræ   rd   rd   re   r¨   t  s(    
ý

ý
ýzDesignationAPIView.delete)N©	rh   ri   rj   r$   rp   rO   rf   r¼   r¨   rd   rd   rd   re   rµ  
  s
   
8rµ  c                   @   s4   e Zd ZefZd
dd„Zdd„ Zdd„ Zdd	„ ZdS )ÚDepartmentAPIViewNc                 C   sú   |d k	rrz:t jj|d�}|j|j|jdœ}ttjddœd |dœƒW S  t	k
rn   ttj
ddœddd	œƒ Y S X n„zTd
}g }t j ¡ D ]&}|d7 }| ||j|j|jdœ¡ q†ttjddœd |dœƒW S  t	k
� rô   ttj
ddœddd	œƒ Y S X d S )Nrª   ©rE   rD   r¶  rC   r4   ro   r¦   Trì   r„   r   r   )rO  rE   rD   r¶  )r   rS   rO   rE   rD   r¶  r,   r.   rZ   r   r‘   rQ  rÐ   ©r^   r_   rE   r°   r9   rT  rÒ   rd   rd   re   rO   �  sP    ý
ý

ýü

ý

ýzDepartmentAPIView.getc              
   C   sŽ   |j }z>tjj|d |d |jd�}| ¡  ttjddœd ddœƒW S  t	k
rˆ } z&ttj
ddœd	d
|› �dœƒ W Y ¢S d }~X Y nX d S )NrD   r¶  )rD   r¶  rf  rC   r4   zDepartment created successfullyr„   r¦   Tr´   )r9   r   rS   r’   ra   r•   r,   r.   r¶   r·   rP   )r^   r_   r9   r°   r}   rd   rd   re   rf   À  s&    ý
ý

ýzDepartmentAPIView.postc              
   C   sÀ   |j }zDtjj|d�}|d |_|d |_| ¡  ttj	ddœd ddœƒW S  t
k
rv   ttjddœd	d
dœƒ Y S  tk
rº } z(t|ƒ ttjddœd	ddœƒ W Y ¢S d }~X Y nX d S )Nrª   rD   r¶  rC   r4   úDepartment updated successfullyr„   r¦   Trì   rÊ   )r9   r   rS   rO   rD   r¶  r•   r,   r.   rZ   r   r‘   rx   ry   rP   ©r^   r_   rE   r9   r°   r}   rd   rd   re   r¼   ×  s0    


ý

ý
ýzDepartmentAPIView.putc                 C   sj   |d k	rfz0t jj|d�}| ¡  ttjddœd ddœƒW S  tk
rd   ttjddœd ddœƒ Y S X d S ©Nrª   rC   r4   zDepartment deleted successfullyr„   r¦   rì   ©	r   rS   rO   r¨   r,   r.   rZ   r   r‘   ©r^   r_   rE   r°   rd   rd   re   r¨   ó  s    
ý

ýzDepartmentAPIView.delete)Nr·  rd   rd   rd   re   r¸  Œ  s
   
1r¸  )ÚDecimalÚInvalidOperation)r   r	   r  ú%I:%M%pú%H:%M:%Sú%H:%Mc              	   C   s€   | dkrdS t | tƒr| S t| ƒ ¡  ¡  dd¡}tD ]4}zt ||¡ 	¡ W   S  t
k
rh   Y q6Y q6X q6t
d| › d�ƒ‚dS )zl
    '09:30 AM', '9:30AM', '09:30', '09:30:00' -> datetime.time
    Invalid na ValueError raise pannum.
    ©NrÅ   NÚ.rÅ   úInvalid time 'ú'. Use hh:mm AM/PM format.)r‹  Údt_timer]   rÌ   Úupperr6  ÚTIME_FORMATSr   r+  r%   rÏ   ©ÚvalueÚrawÚfmtrd   rd   re   Ú
parse_time	  s    
rÐ  c              	   C   s6   z
t | ƒW S  ttfk
r0   t|› d�ƒ‚Y nX d S ©Nz must be a number.)rÎ   Ú	TypeErrorrÏ   ©rÍ  Úfieldrd   rd   re   Ú	parse_int(	  s    
rÕ  c              
   C   s<   zt t| ƒƒW S  tttfk
r6   t|› d�ƒ‚Y nX d S rÑ  )rÀ  r]   rÁ  rÒ  rÏ   rÓ  rd   rd   re   Úparse_decimal/	  s    rÖ  c                 C   s"   t | tƒr| S t| ƒ ¡  ¡ dkS )N)rØ   ÚtrueÚyesÚon)r‹  r1  r]   rÌ   rj  ©rÍ  rd   rd   re   Ú
parse_bool6	  s    
rÛ  ÚMonÚTueÚWedÚThuÚFriÚSatÚSunc                 C   s(   t dt| ƒƒ} | d d›d| d d›�S ©Nr   rž   Ú02dú:©r•  rÎ   ©Ztotal_minutesrd   rd   re   Úfmt_hhmmR	  s    rè  c               	      s®   t jjdd�\} }| jp tddƒ}| jp0tddƒ}t| jp<dƒ}dd„ | jpNd	 	d
¡D ƒ‰ ‡ fdd„t
tƒD ƒ}t t ¡ |¡t|d�  ¡ }| |||||ˆ t| jp¦dƒdœS )uè   
    Setting table (pk=1) -la irundhu shift timing, grace period,
    weekly off days edukkum. Monthly + Today rendu API-um idhe
    function-a use pannanum â€” settings maathi na rendu idathulayum
    automatic-a update aagum.
    r   ©Úpkrò   é   é   r   c                 S   s(   h | ] }|  ¡ r|  ¡ d d…  ¡ ’qS ©Nre  ©rÌ   Útitle©r"  Úprd   rd   re   r$  e	  s   þú(get_attendance_config.<locals>.<setcomp>rÅ   ú,c                    s   h | ]\}}|ˆ kr|’qS rd   rd   ©r"  r#  Únm©Z	off_namesrd   re   r$  j	  s      ©Úminutesró   )Úsettingr  r  r  r  r  r  Úhalf_day_hours)r   rS   r­  r  r%   r  rÎ   r  r  ÚsplitrR  r   r   Úcombiner,  r-  r   r¬  rú  ©rù  Ú_r  r  Zgracer  r  rd   rö  re   r.  W	  s&    þÿør.  c                 C   s    t jj| |gd�}dd„ |D ƒS )uL   Holiday table -la irundhu {date_obj: name} â€” date range kku eduthu tharum.©Údate__rangec                 S   s   i | ]}|j |j“qS rd   ©r   rD   ©r"  r›  rd   rd   re   Ú
<dictcomp>€	  s      z#get_holiday_map.<locals>.<dictcomp>)r	   rS   r�   )Ú
start_dateÚend_dateÚqsrd   rd   re   r/  }	  s    r/  c                 C   s   t | dd ƒpt | ddƒpdS )NrD   r¡  rÅ   õ   â€”)r4  ©rB  rd   rd   re   Úemp_display_nameƒ	  s    r	  c                 C   s"   t | dd ƒp t | dd ƒp t| jƒS )NrK  r±  )r4  r]   rE   r  rd   rd   re   Úemp_display_code‡	  s    r
  c                 C   s   t | o| |d kƒS ©Nr  ©r1  ©r¥  r;  rd   rd   re   Úis_late‹	  s    r  i€p  c                 C   sZ   |d j sdS | r|sdS t ¡ }t ||¡t || ¡ }| ¡ }|tkrNdS t|t ƒS )zÛ
    Total worked time (out_time - in_time) 8 hours-a thaandi irundha,
    andha extra seconds mattum OT-a return pannum.
    in_time/out_time illama irundha, or out_time < in_time (data issue)
    irundha, OT = 0.
    rù  r   )Úovertime_enabledr,  r-  r   rü  Útotal_secondsÚSTANDARD_WORK_SECONDSrÎ   )r¥  r®  r;  ÚdÚworkedZ
worked_secrd   rd   re   Ú
ot_seconds”	  s    
r  c                   @   s(   e Zd ZdZdd„ Zdd„ Zdd„ ZdS )	ÚSettingAPIViewu=   Single settings row (pk=1) â€” GET fetch, PUT partial update.c                 C   s   t jjdd�\}}|S )Nr   ré  )r   rS   r­  )r^   rù  rþ  rd   rd   re   rm   ¯	  s    zSettingAPIView.get_objectc                 C   s”   |   ¡ }|jr|j d¡nd |jr.|j d¡nd dd„ |jp>d d¡D ƒ|j|jd k	r`t|jƒnd|j	|j
|j|j|jdœ
}ttjdd	œd |d
œƒS )Nr  c                 S   s   g | ]}|r|‘qS rd   rd   ©r"  r  rd   rd   re   Ú
<listcomp>¸	  s      z&SettingAPIView.get.<locals>.<listcomp>rÅ   ró  r   )
r  r  r  r  rú  r  Úgeofence_enabledÚface_sensitivityÚcompany_nameÚ	time_zonerC   r4   ro   )rm   r  r7  r  r  rû  r  rú  r¬  r  r  r  r  r  r,   r.   rZ   )r^   r_   rù  r9   rd   rd   re   rO   ³	  s"    ö
ýzSettingAPIView.getc              
   C   sÄ  |   ¡ }|j}dd„ }�z6d|kr2|| d¡ƒ|_d|krJ|| d¡ƒ|_d|krz| d¡}t|tƒrpd |¡n|pvd|_d|kr’t	| d¡ƒ|_
d	|krªt| d	¡ƒ|_d
|krÂt| d
¡ƒ|_d|krÚt| d¡ƒ|_d|krî| d¡|_d|k�r| d¡�pd ¡ |_d|k�r.| d¡�p&d ¡ |_|jj�r>|jnd |_| ¡  W nN ttfk
�rœ } z*ttjddœdt|ƒdœtjd� W Y ¢S d }~X Y nX ttjddœd d|  |¡jd dœƒS )Nc              	   S   sr   | dkrd S t | ƒ ¡  ¡  dd¡}dD ]4}zt ||¡ ¡ W   S  tk
rZ   Y q(Y q(X q(td| › d�ƒ‚d S )NrÅ  rÆ  rÅ   )r  rÂ  rÃ  rÄ  rÇ  rÈ  )r]   rÌ   rÊ  r6  r   r+  r%   rÏ   rÌ  rd   rd   re   rÐ  Ë	  s    z&SettingAPIView.put.<locals>.parse_timer  r  r  ró  rÅ   r  rú  r  r  r  r  r  r¦   r4   Tr„   r-   rC   zSettings updated successfullyr9   r7   )rm   r9   rO   r  r  r‹  ÚlistÚjoinr  rÎ   r  r¬  rú  r1  r  r  r  rÌ   r  r  ra   rk  Ú
updated_byr•   rÏ   rÒ  r,   r.   rP   r]   rZ   )r^   r_   rù  r9   rÐ  Zwor}   rd   rd   re   r¼   Ç	  sR    



ýü
üzSettingAPIView.putN)rh   ri   rj   rD  rm   rO   r¼   rd   rd   rd   re   r  ¬	  s   r  c                   @   s,   e Zd ZdZd	dd„Zdd„ Zd
dd„ZdS )ÚHolidayAPIViewu%   Holiday CRUD â€” List / Add / Delete.Nc                 C   s¬   |d k	rzzt jj|d�}W n4 t jk
rN   ttjddœdddœtjd� Y S X ttjddœd |j|j	t
|jƒd	œd
œƒS t j ¡  d¡}ttjddœd dd„ |D ƒd
œƒS )Nrª   r¦   r4   TúHoliday not foundr„   r-   rC   ©rE   rD   r   ro   r   c                 S   s"   g | ]}|j |jt|jƒd œ‘qS )r!  )rE   rD   r]   r   r  rd   rd   re   r  
  s     z&HolidayAPIView.get.<locals>.<listcomp>)r	   rS   rO   rT   r,   r.   r‘   rZ   rE   rD   r]   r   rQ  rÍ   )r^   r_   rE   r›  Úholidaysrd   rd   re   rO   
  s,    
ýü
ý
ýzHolidayAPIView.getc                 C   sä   |j  d¡pd ¡ }|j  d¡p"d ¡ }|r0|sNttjddœdddœtjd	�S zt |d
¡ W n2 tk
r�   ttjddœdddœtjd	� Y S X t	j
j|||jjrª|jnd d�}ttjddœd d|j|jt|jƒdœdœtjd	�S )NrD   rÅ   r   r¦   r4   TzName and date are required.r„   r-   r
  z"Date must be in YYYY-MM-DD format.)rD   r   rf  rC   zHoliday added successfullyr!  r7   )r9   rO   rÌ   r,   r.   rP   r   r+  rÏ   r	   rS   r’   ra   rk  r¶   rE   rD   r]   r   )r^   r_   rD   Zdate_valÚholidayrd   rd   re   rf   
  sB    
ýü
ýüý
üûzHolidayAPIView.postc                 C   sŽ   |d kr&t tjddœdddœtjd�S ztjj|d�}W n4 tjk
rl   t tjddœdddœtjd� Y S X | ¡  t tj	d	dœd d
dœƒS )Nr¦   r4   TzHoliday id required in URL.r„   r-   rª   r   rC   zHoliday deleted)
r,   r.   rP   r	   rS   rO   rT   r‘   r¨   rZ   )r^   r_   rE   r#  rd   rd   re   r¨   ;
  s0    
ýü
ýü
ýzHolidayAPIView.delete)N)N)rh   ri   rj   rD  rO   rf   r¨   rd   rd   rd   re   r  
  s   
 r  c                   @   s   e Zd Zdd„ ZdS )ÚEmployeeMiniListAPIViewc                 C   s:   t jjdd� d¡}dd„ |D ƒ}ttjddœd |dœƒS )	Nr   r-   rD   c                 S   s"   g | ]}|j t|ƒt|ƒd œ‘qS )©rE   rD   r5   )rE   r	  r
  ©r"  r}   rd   rd   re   r  Z
  s   ÿz/EmployeeMiniListAPIView.get.<locals>.<listcomp>rC   r4   ro   )r   rS   r�   rÍ   r,   r.   rZ   )r^   r_   rS  r9   rd   rd   re   rO   X
  s    þ
ýzEmployeeMiniListAPIView.getNr  rd   rd   rd   re   r$  W
  s   r$  )r%   rì  é-   r…   c              	   C   s†   | sdS t | tƒrpzBdd„ |  ¡  d¡dd… D ƒ}t|ƒdk rL| d¡ q4t|Ž W S  ttfk
rn   Y dS X t	| dƒr‚|  
¡ S | S )zGtime / datetime / "HH:MM[:SS]" string -> time object (mudiyala na None)Nc                 S   s   g | ]}t t|ƒƒ‘qS rd   )rÎ   r¬  ©r"  r‰  rd   rd   re   r    s     z_to_time.<locals>.<listcomp>rå  re  r   r%   )r‹  r]   rÌ   rû  r…  rÐ   rÉ  rÏ   rÒ  Úhasattrr%   )rÍ  Úpartsrd   rd   re   Ú_to_timeþ
  s    
 

r+  c                 C   s   | j d | jd  | j S )Né  rž   )ÚhourÚminuteÚsecond©Útrd   rd   re   Ú_seconds  s    r2  c                 C   s&   t |ƒ}|sdS tdt|ƒttƒ ƒS )z,OT = out_time - 6:45 PM. out_time illa na 0.r   )r+  r•  r2  ÚOT_START)r¥  r®  r;  Úout_trd   rd   re   Úot_seconds_static  s    r5  c                 C   s4   t | ƒt |ƒ }}|r|sdS tdt|ƒt|ƒ ƒS )z<Total login -> logout neram (seconds). Edhaavadhu illa na 0.r   )r+  r•  r2  )r¥  r®  Úin_tr4  rd   rd   re   Úworked_seconds  s    r7  c                 C   s&   t | ƒrt |ƒsdS t| |ƒtd k S )zBIn & Out rendum irundhu, total velai neram 6 hrs ku kammi na True.Fr,  )r+  r7  ÚHALF_DAY_MIN_HOURS)r¥  r®  rd   rd   re   Úis_half_day#  s    r9  c                   @   s   e Zd ZdZdd„ ZdS )ÚMonthattendanceAPIViewaÎ  
    Status per day: P / HD / A / H (Holiday table) / W (Setting.weekly_off) / '--' (future)
    HD    = In -> Out 6 hrs ku kammi (0.5 day)
    A     = Absent, illa check-in irundhu check-out illa (past date) -> no_checkout = True
    Late  = in_time > shift_start + grace_minutes (Setting table)
    3 Late = 0.5 day cut from Present (effective_present)
    OT    = out_time - 6:45 PM (static)
    Optional filter: ?employee_id=<id>  (illa na ellame varum)
    c           "         sð  |j  d¡}|s"tdditjd�S zt |d d¡ ¡ ‰W n& tk
r`   tdditjd� Y S X ˆj	dkrŽˆj
ˆjd	 d	d	d
�td	d� }nˆj
ˆj	d	 d	d�td	d� }‡fdd„t|ˆ jd	 ƒD ƒ}tƒ ‰ tˆ|ƒ‰|j  d¡pò|j  d¡}tjjd	d�}|�r|dk�r|j|d�}tjjˆ|gd�}	t ¡ }
g }|D �]‰‡fdd„|	D ƒ}d } } }}d}i }|D �]R}| d¡}d}d}| ¡ }|ˆk}|ˆ d k}|�r´d}nú|�rÀd}nî||
k�rÐd}nÞ||k�r¢|| }|jdk�r”|j�s||
k �rd}|d	7 }d}n€|j�r8t|j|jƒ�r8d }|d	7 }nd!}|d	7 }t|jˆ ƒ�rZ|d	7 }|j�rpt|j|jƒnd}|dk�r ||7 }t|d" ƒ}nd}|d	7 }nd}|d	7 }|||ˆ |¡d#œ||< �qt|d$ }t|d% d&ƒ}tt d||d%  | ƒd&ƒ}t!|d' ƒ} t!|d' d" ƒ}!| "ˆj#t$ˆƒt%ˆƒ|| |||| d(›d)|!d(›�||||d*œ¡ �q@t‡ ‡fd+d„|D ƒ|ˆ d,  d-¡ˆ d.  d-¡ˆ d/ ˆ d0  d-¡t&ˆ  d1¡�pºd2d3„ ˆ d D ƒƒd4t'd5t'› d6�d7œd8d„ t&ˆ (¡ ƒD ƒd9œtj)d�S ):NrÄ   r3   ú!val is required. Use ?val=YYYY-MMr-   ú-01r
  úInvalid val format. Use YYYY-MMé   r   ©ÚyearÚmonthÚday©Údays©rA  rB  c                    s   g | ]}ˆ t |d � ‘qS ©rC  rœ   r!  ©Ú	first_dayrd   re   r  U  s    z.MonthattendanceAPIView.get.<locals>.<listcomp>r  rF  rQ  rª   rÿ  c                    s    i | ]}|j ˆ jkr|j|“qS rd   )r  rE   r   ©r"  Úrr  rd   re   r  f  s       z.MonthattendanceAPIView.get.<locals>.<dictcomp>r   ú00:00Fr  ÚHÚWú--r  ÚATÚHDÚPrž   ©r.   ÚotÚno_checkoutr'  re  r¤  r?   r,  rä  rå  )rE   rD   r5   Útotal_presentÚ	half_daysÚeffective_presentÚtotal_absentÚtotal_otr@  Úhalf_day_cutsÚlate_deductionÚ
attendancec                    sJ   g | ]B}|  d ¡|j|  d¡|  d¡| ¡ ˆ d k|ˆkˆ |¡dœ‘qS ©r
  z%dz%ar  )r   Zday_numÚdisplayÚday_namer(  r&  r'  ©r7  rB  r0  rO   r  ©r;  r<  rd   re   r  ¸  s   
øùr  r  r  r  r  r  c                 S   s   h | ]}t | ’qS rd   r  r!  rd   rd   re   r$  Ê  s     z-MonthattendanceAPIView.get.<locals>.<setcomp>z3 Late = 0.5 day deductionzBelow z hrs = Half day)r  r  r  r  r  Z	late_rulerú  Zhalf_day_rulec                 S   s    g | ]\}}|  d ¡|dœ‘qS ©r
  r  ©r7  ©r"  r  Únrd   rd   re   r  Ï  s   ÿ)rD  ÚreportÚconfigr"  )*rË   rO   r,   r.   rP   r   r+  r   rÏ   rA  r6  r@  r   ÚrangerD  r.  r/  r   rS   r�   r   r,  r-  r7  r0  r®  r9  r¥  r  r5  rè  r¯  r•  rÎ   rÐ   rE   r	  r
  r8  r8  ÚitemsrZ   )"r^   r_   rŒ   r¯   rÄ   Úlast_dayÚdates_in_monthÚ	emp_paramrS  Zall_attendancer-  Zfinal_reportÚemp_recordsÚtotal_pÚtotal_hdÚtotal_ar@  Útotal_ot_secÚattendance_maprB  Úday_strÚ
ot_displayrT  Úwdr&  r(  Ústatus_codeÚrecÚsecrZ  r[  rW  Ú
total_ot_hÚ
total_ot_mrd   )r;  rB  rH  r<  re   rO   @  sà    þþ
"
ÿ








üô
ö 
ø

þèäzMonthattendanceAPIView.getN©rh   ri   rj   rD  rO   rd   rd   rd   re   r:  5  s   
r:  c                   @   s   e Zd ZdZdd„ ZdS )ÚTodayAttendanceAPIViewu‹  
    Settings + Holiday table wise, particular date-oda present/absent.
 
    âœ… Past date la check-in irundhu check-out illa na -> ABSENT list la varum
       (no_checkout = True, in_time kaattum). Admin out time update / delete pannalaam.
    âœ… Innaiku (today) check-out illa na innum velai la irukkaanga -> PRESENT.
    âœ… In -> Out 6 hrs ku kammi na PRESENT list la "half_day": True
    c                 C   sÞ  |j  d¡}z |r"t |d¡ ¡ nt ¡ }W n& tk
rR   tddit	j
d� Y S X t ¡ }tƒ }t||ƒ}| |¡}| ¡ |d k}|rŽdn
|r–dnd}	|j  d	¡}
tjjd
d�}|
rÌ|
dkrÌ|j|
d�}tjj||d� d¡}g }g }|D �]0}|j}t|j|ƒ}t|jƒ}|j|jt|ƒt|ƒt|dd ƒ�r:|jjnd |j�rP|j d¡nd|�rd|j d¡nd|�rpdnd||jddddddœ}|�s¬||k �r¬d|d< |  |¡ qî|�rât!|j|jƒ}t"|d ƒ|d< t#|j|jƒ|d< |�röt$|j|jƒnd}t"|d ƒ|d< |d |d< |  |¡ qîdd „ |D ƒ}d!d „ |j%|d"�D ƒ}t&|| d#d$„ d%�}t| '¡ |	t|ƒ||t(|ƒt(|ƒt(|ƒt)d&d'„ |D ƒƒt&|d(d$„ d%�||d)  d¡|d*  d¡|d+ |d,  d¡t*d-œd.œt	j+d�S )/Nr   r
  r3   úInvalid date. Use YYYY-MM-DDr-   r  r#  Úworkingr  r   rQ  rª   )r   Zemployee__inr_  r  r  rN  ÚLatezOn TimeFrK  r   )Úattendance_idrE   rD   r5   r  r¥  r®  Zentry_statusÚlater¦  rT  Úhalf_dayÚworked_timeÚot_timeÚ
ot_minutesTrT  rž   rƒ  r‚  r„  r…  c                 S   s   g | ]
}|j ‘qS rd   ©r  rI  rd   rd   re   r  |  s     z.TodayAttendanceAPIView.get.<locals>.<listcomp>c              
   S   s<   g | ]4}d |j t|ƒt|ƒt|dd ƒr.|jjnd ddœ‘qS )Nr  F)r€  rE   rD   r5   r  rT  )rE   r	  r
  r4  r  rW   r&  rd   rd   re   r  }  s   	ùúr  c                 S   s   | d  | d fS )NrT  rD   rd   ©r‰  rd   rd   re   Ú<lambda>Œ  ó    z,TodayAttendanceAPIView.get.<locals>.<lambda>©Úkeyc                 s   s   | ]}|d  rdV  qdS )r‚  r   Nrd   rð  rd   rd   re   Ú	<genexpr>˜  s      z-TodayAttendanceAPIView.get.<locals>.<genexpr>c                 S   s   | d S )NrD   rd   r‡  rd   rd   re   rˆ  ™  r‰  r  r  r  r  ©r  r  r  r  rú  )r   Úday_typer&  r'  r(  r?  Zabsent_countZno_checkout_countZhalf_day_countÚpresent_listrA  rg  ),r¤   rO   r   r+  r   r,  r-  rÏ   r,   r.   rP   r.  r/  r0  r   rS   r�   r   Úselect_relatedr_  r  r¥  r1  r®  rE   r	  r
  r4  r  rW   r7  r¦  rÐ   r7  rè  r9  r5  r3  r8  r¢  r…  Úsumr8  rZ   )r^   r_   r9  r:  r-  r;  r<  r=  r(  rŽ  rl  rS  Úrecordsr�  Zno_checkout_listrw  rB  r�  Zhas_outÚitemr  rx  Zrecorded_idsZplain_absentrA  rd   rd   re   rO   4  s´    ÿþþ

 ÿþ

ñ
	
÷þûôízTodayAttendanceAPIView.getNr{  rd   rd   rd   re   r|  *  s   	r|  c                   @   s   e Zd Zdd„ ZdS )ÚUpdateAttendanceOutTimeAPIViewc           	   
   C   sh  t |j d¡pdƒ ¡ }|s.tdditjd�S d }dD ]8}zt ||¡ 	¡ }W  qpW q6 t
k
rl   Y q6Y q6X q6|d krŠtdditjd�S ztj d¡j|d	�}W n( tjk
rÊ   tdd
itjd� Y S X t|jƒ}|d k	�r
||k�r
tdd| d¡› d�itjd�S ||_| ¡  t|j|jƒ}td|j|j|j ¡ |j d¡t|j|jƒt|d ƒdœtjd�S )Nr®  rÅ   r3   z)out_time is required. Use HH:MM (24-hour)r-   )rÄ  rÃ  z%Invalid out_time. Use HH:MM (24-hour)r_  rª   úAttendance record not foundz Out time must be after in time (r  ú)zOut time updatedrž   )r8   r€  r  r   r®  r‚  r„  )r]   r9   rO   rÌ   r,   r.   rP   r   r+  r%   rÏ   r   rS   r�  rT   r‘   r+  r¥  r7  r®  r•   r5  rE   r  r   r¢  r9  rè  rZ   )	r^   r_   r€  Zout_strÚparsedrÏ  rw  r6  rx  rd   rd   re   rz  ²  sZ    þ
þþ
þ

ùøz$UpdateAttendanceOutTimeAPIView.patchNr{  rd   rd   rd   re   r”  °  s   r”  c                   @   s   e Zd Zdd„ ZdS )ÚDeleteAttendanceAPIViewc                 C   sV   zt jj|d�}W n( t jk
r:   tdditjd� Y S X | ¡  tdditjd�S )Nrª   r3   r•  r-   r8   zAttendance deleted)	r   rS   rO   rT   r,   r.   r‘   r¨   rZ   )r^   r_   r€  rw  rd   rd   re   r¨   í  s    þþzDeleteAttendanceAPIView.deleteN)rh   ri   rj   r¨   rd   rd   rd   re   r˜  ë  s   r˜  c                   @   s   e Zd ZdZdd„ ZdS )ÚEmployeeDashboardAPIViewz²
    GET /employee-dashboard/?employee_id=<id>
 
    employee_id kudukkalana, login panna user-oda user_data-la
    irundhu employee_id anuppanum (frontend already anuppum).
    c                 C   s|  |j  d¡}|s"tdditjd�S ztjj|d�}W n( tjk
r\   tdditjd� Y S X t	ƒ }t
 ¡ }|jdd�}|jd	kr¤|j|jd ddd
�tdd� }n|j|jd dd�tdd� }t||ƒ}tjj|d� d¡ ¡ }	tjj|j|d� ¡ }
||k}| ¡ |d k}|�rd}n:|�r*d}n.|
�rT|
jdk�rTt|
j|ƒ�rNdnd}nd}tjj|j||gd�}dd„ |D ƒ}d } }}|}|t||ƒk�r| ¡ |d k}||k}|�s|�s| |¡}|�rü|jdk�rü|d7 }t|j|ƒ�r|d7 }n|d7 }|tdd�7 }�qŒ|d }t|d dƒ}ttd|| ƒdƒ}ttjddœd |jt|ƒt|ƒt |dd ƒ�rt|j!j"nd d œ| #¡ ||
�rœ|
j�rœ|
j $d!¡nd"|
�r¸|
j%�r¸|
j% $d!¡nd"d#œ|d$  $d!¡|d%  $d!¡|d& |d'  $d!¡t&d(d)„ |d D ƒƒt&| d*¡�pd+d,„ |d D ƒƒd-œd.d/„ t&| '¡ ƒD ƒ|	�rL|	j( #¡ |	j)d0œnd d1œ| $d2¡||||||d3œd4œd5œtjd�S )6Nr  r3   úemployee_id is requiredr-   rª   rp  r   )rB  r>  r?  rC  rE  )Ú	date__gter   ©r  r   r  r	   z
Weekly Offr  r  úNot Checked In©r  r   c                 S   s   i | ]}|j |“qS rd   r|  rI  rd   rd   re   r  9  s      z0EmployeeDashboardAPIView.get.<locals>.<dictcomp>r   re  r¤  r?   rC   r4   r  )rE   rD   r5   r  r  rN  )r   r.   r¥  r®  r  r  r  r  c                 s   s   | ]}t | V  qd S rl   r  r!  rd   rd   re   rŒ  d  s     z/EmployeeDashboardAPIView.get.<locals>.<genexpr>r  c                 S   s   h | ]}t | ’qS rd   r  r!  rd   rd   re   r$  i  s     z/EmployeeDashboardAPIView.get.<locals>.<setcomp>)r˜   r%  r  r  r  Zweekly_off_daysc                 S   s   g | ]\}}|  ¡ |d œ‘qS )r  )r¢  )r"  Úd2re  rd   rd   re   r  n  s   ÿz0EmployeeDashboardAPIView.get.<locals>.<listcomp>r  )Ú
this_monthÚnextú%B %Y)Úmonth_labelrU  rW  rX  r@  rZ  r[  )r_  r-  rà   r"  Zmonth_summaryro   )*r¤   rO   r,   r.   rP   r   rS   rT   r‘   r.  r,  r-  r6  rA  r@  r   r/  r	   r�   rÍ   Úfirstr   rE   r0  r  r¥  r“  r¯  r•  rZ   r	  r
  r4  r  rW   r¢  r7  r®  r8  ri  r   rD   )r^   r_   r±  rB  r;  r-  Úmonth_startÚ	month_endZmonth_holidaysÚupcomingZ	today_recZis_holiday_todayZis_weekly_off_todayZtoday_statusZmonth_recordsZrec_by_datern  rp  r@  r  Zis_offZis_holrw  rZ  r[  rW  rd   rd   re   rO   
  sº    þþ
"
 ÿ


üüÿ÷
þÿùùÚý3ÍzEmployeeDashboardAPIView.getNr{  rd   rd   rd   re   r™    s   r™  c                   @   s   e Zd ZdZdd„ ZdS )ÚEmployeeAttendanceAPIViewu`  
    GET /employee-attendance/?employee_id=<id>&date=YYYY-MM-DD
 
    date illama kudutha, today edukkum.
    Status: Present / Late / Half Day / H / W / Absent / Not Checked In / --
    âœ… Past date + check-in irundhu check-out illa -> Absent (no_checkout = True)
    âœ… In -> Out 6 hrs ku kammi -> Half Day
    OT = out_time - 6:45 PM (static)
    c                 C   sª  |j  d¡}|s"tdditjd�S ztjj|d�}W n( tjk
r\   tdditjd� Y S X |j  d¡}z |r€t	 
|d¡ ¡ nt ¡ }W n& tk
r°   tdd	itjd� Y S X t ¡ }tƒ }t||ƒ}| |¡}	| ¡ |d
 k}
tjj|j|d� ¡ }d}d}d}d}d}|	�rd}nÌ|
�r&d}nÀ|�r¶|jdk�r¶|j�sT||k �rTd}d}n`t|j|ƒ}|j�ršt|j|jƒ}tt|j|jƒd ƒ}t|j|jƒ}|�r¦d}n|�r°dnd}n0|�rÂd}n$||k�rÒd}n||k �râd}nd}ttjddœd |jt|ƒt|ƒdœ|  ¡ |||||�r0|j�r0|j !d¡nd|�rL|j�rL|j !d¡nd|t|d ƒ|	dœ	t"|	ƒ|
|d  !d¡|d  !d¡|d |d   !d¡t#d!œd"œd#œtjd�S )$Nr  r3   rš  r-   rª   rp  r   r
  r}  r  rœ  Fr   rN  rL  rM  r  ÚAbsentTrž   zHalf Dayr  r�  rC   r4   r%  r  )	r.   r�  r‚  rT  r¥  r®  rƒ  r„  r'  r  r  r  r  r�  )r_  r   Úrecordr&  r(  rg  ro   )$r¤   rO   r,   r.   rP   r   rS   rT   r‘   r   r+  r   r,  r-  rÏ   r.  r/  r0  r   r�   rE   r¤  r®  r  r¥  r5  rè  r7  r9  rZ   r	  r
  r¢  r7  r1  r8  )r^   r_   r±  rB  r9  r:  r-  r;  r<  r=  r(  rw  r�  rx  rT  r‚  rƒ  Zrecord_statusrd   rd   re   rO   ™  s°    þþÿþþ




ý
÷ûìýázEmployeeAttendanceAPIView.getNr{  rd   rd   rd   re   r¨  Ž  s   
r¨  c                   @   s   e Zd ZdZdd„ ZdS )Ú EmployeeMonthlyAttendanceAPIViewzÓ
    GET /employee-monthly-attendance/?employee_id=<id>&val=YYYY-MM
 
    Same day-status rules as MonthattendanceAPIView, but scoped to
    ONE employee and returns a single "row" object instead of a list.
    c                    sô  |j  d¡}|j d¡}|s.tdditjd�S |sDtdditjd�S ztjj|d�}W n( tjk
r~   tdditj	d� Y S X zt
 |d	 d
¡ ¡ ‰W n& tk
r¾   tdditjd� Y S X ˆjdkrìˆjˆjd ddd�tdd� }nˆjˆjd dd�tdd� }‡fdd„t|ˆ jd ƒD ƒ}tƒ ‰ tˆ|ƒ‰dd„ tjj|jˆ|gd�D ƒ}t ¡ }d }	 }
 }}d}i }|D �]R}| d
¡}d}d}| ¡ }|ˆk}|ˆ d k}|�r¾d}nú|�rÊd}nî||k�rÚd}nÞ||k�r¬|| }|jdk�rž|j�s||k �rd}|d7 }d}n€|j�rBt|j|jƒ�rBd }|
d7 }
nd!}|	d7 }	t |jˆ ƒ�rd|d7 }|j�rzt!|j|jƒnd}|dk�rª||7 }t"|d" ƒ}nd}|d7 }nd}|d7 }|||ˆ |¡d#œ||< �q~|d$ }t#|d% d&ƒ}t#t$d|	|
d%  | ƒd&ƒ}t%|d' ƒ}t%|d' d" ƒ}ttj&d(d)œd |jt'|ƒt(|ƒd*œ‡ ‡fd+d„|D ƒ|	|
 |
|||d,›d-|d,›�||||d.œ	ˆ d/  d0¡ˆ d1  d0¡ˆ d2 ˆ d3  d0¡t)ˆ  d4¡�pÆd5d6„ ˆ d D ƒƒt*d7œd8d„ t)ˆ +¡ ƒD ƒd9œd:œtj&d�S );Nr  rÄ   r3   rš  r-   r;  rª   rp  r<  r
  r=  r>  r   r?  rC  rE  c                    s   g | ]}ˆ t |d � ‘qS rF  rœ   r!  rG  rd   re   r  Ê  s    z8EmployeeMonthlyAttendanceAPIView.get.<locals>.<listcomp>c                 S   s   i | ]}|j |“qS rd   r|  rI  rd   rd   re   r  Ñ  s   ÿ z8EmployeeMonthlyAttendanceAPIView.get.<locals>.<dictcomp>rž  r   rK  Fr  rL  rM  rN  r  rO  TrP  rQ  rž   rR  re  r¤  r?   r,  rC   r4   r%  c                    sJ   g | ]B}|  d ¡|j|  d¡|  d¡| ¡ ˆ d k|ˆkˆ |¡dœ‘qS r]  r`  r  ra  rd   re   r     s   
øùrä  rå  )	rU  rV  rW  rX  rY  r@  rZ  r[  r\  r  r  r  r  r  r  c                 S   s   h | ]}t | ’qS rd   r  r!  rd   rd   re   r$  =  s     z7EmployeeMonthlyAttendanceAPIView.get.<locals>.<setcomp>)r  r  r  r  r  rú  c                 S   s    g | ]\}}|  d ¡|dœ‘qS rb  rc  rd  rd   rd   re   r  A  s   ÿ)r_  rD  rO  rg  Zholidays_this_monthro   ),r¤   rO   rË   r,   r.   rP   r   rS   rT   r‘   r   r+  r   rÏ   rA  r6  r@  r   rh  rD  r.  r/  r   r�   rE   r,  r-  r7  r0  r®  r9  r¥  r  r5  rè  r¯  r•  rÎ   rZ   r	  r
  r8  r8  ri  )r^   r_   r±  rÄ   rB  rj  rk  rm  r-  rn  ro  rp  r@  rq  rr  rB  rs  rt  rT  ru  r&  r(  rv  rw  rx  rZ  r[  rW  ry  rz  rd   )r;  rH  r<  re   rO   ¦  sô    þþþþ
"
ÿ
þ






ü
ý
ö÷ÿø

þÙý/Ñz$EmployeeMonthlyAttendanceAPIView.getNr{  rd   rd   rd   re   r«  ž  s   r«  )ÚLeaveRequestsc                 C   sj   | j | jt| jƒt| jƒ| j| j ¡ | j ¡ | j	| j
| j| j| jrN| j d¡nd | jrb| j d¡nd dœS )Nz%Y-%m-%d %I:%M %p)rE   r  Úemployee_nameZemployee_codeÚ
leave_typer  r  Ú
days_countr¶  r.   Ú
admin_noteÚ
applied_atÚreviewed_at)rE   r  r	  r_  r
  r®  r  r¢  r  r¯  r¶  r.   r°  r±  r7  r²  )Úlvrd   rd   re   Ú
leave_jsonN  s    ór´  c                   @   s    e Zd ZdZdd„ Zdd„ ZdS )ÚEmployeeLeaveAPIViewz°
    GET  /employee-leave/?employee_id=<id>              -> list own leave requests
    POST /employee-leave/  {employee_id, leave_type, start_date, end_date, description}
    c                 C   sX   |j  d¡}|s"tdditjd�S tjj|d� d¡}ttj	ddœd d	d
„ |D ƒdœƒS )Nr  r3   rš  r-   r†  r_  rC   r4   c                 S   s   g | ]}t |ƒ‘qS rd   ©r´  ©r"  r³  rd   rd   re   r  p  s     z,EmployeeLeaveAPIView.get.<locals>.<listcomp>ro   )
r¤   rO   r,   r.   rP   r¬  rS   r�   r�  rZ   )r^   r_   r±  Úleavesrd   rd   re   rO   g  s    
ýzEmployeeLeaveAPIView.getc              	   C   s<  |j }| d¡}|s&tdditjd�S ztjj|d�}W n( tjk
r`   tdditjd� Y S X | dd¡}| d	¡}| d
¡}| d¡pŽd 	¡ }z$t
 |d¡ ¡ }	t
 |d¡ ¡ }
W n* ttfk
râ   tdditjd� Y S X |
|	k �r tdditjd�S tjj|||	|
|dd�}ttjddœd dt|ƒdœtjd�S )Nr  r3   rš  r-   rª   rp  r®  ÚCasualr  r  r¶  rÅ   r
  z1start_date/end_date required in YYYY-MM-DD formatú$End date cannot be before start dateÚPending)r_  r®  r  r  r¶  r.   rC   r4   zLeave request submittedr7   )r9   rO   r,   r.   rP   r   rS   rT   r‘   rÌ   r   r+  r   rÒ  rÏ   r¬  r’   r¶   r´  )r^   r_   r9   r±  rB  r®  Ú	start_strÚend_strr¶  r  r  r³  rd   rd   re   rf   s  sL    


þ
ú
üûzEmployeeLeaveAPIView.postN)rh   ri   rj   rD  rO   rf   rd   rd   rd   re   rµ  a  s   rµ  c                   @   s0   e Zd ZdZdd„ Zdd„ Zdd„ Zdd	„ Zd
S )ÚEmployeeLeaveDetailAPIViewzÈ
    GET    /employee-leave/<id>/
    PUT    /employee-leave/<id>/   -- edit, only allowed while status="Pending"
    DELETE /employee-leave/<id>/   -- cancel, only allowed while status="Pending"
    c                 C   s4   zt j d¡j|d�W S  t jk
r.   Y d S X d S )Nr_  rª   )r¬  rS   r�  rO   rT   ©r^   rE   rd   rd   re   rm   §  s    z%EmployeeLeaveDetailAPIView.get_objectc                 C   s<   |   |¡}|s tdditjd�S ttjddœd t|ƒdœƒS )Nr3   úLeave request not foundr-   rC   r4   ro   )rm   r,   r.   r‘   rZ   r´  ©r^   r_   rE   r³  rd   rd   re   rO   ­  s    

ýzEmployeeLeaveDetailAPIView.getc                 C   s(  |   |¡}|s tdditjd�S |jdkrFtdd|j› d�itjd�S |j}z@d|krlt |d d¡ ¡ |_	d	|krŠt |d	 d¡ ¡ |_
W n& tk
r²   tdd
itjd� Y S X |j
|j	k rÒtdditjd�S d|krä|d |_d|k�r| d¡púd ¡ |_| ¡  ttjddœd dt|ƒdœƒS )Nr3   rÀ  r-   r»  u&   Cannot edit â€” this leave is already rÆ  r  r
  r  úDates must be YYYY-MM-DDrº  r®  r¶  rÅ   rC   r4   zLeave request updatedr7   )rm   r,   r.   r‘   rP   r9   r   r+  r   r  r  rÏ   r®  rO   rÌ   r¶  r•   rZ   r´  )r^   r_   rE   r³  r9   rd   rd   re   r¼   ·  s:    

þ


üzEmployeeLeaveDetailAPIView.putc                 C   sf   |   |¡}|s tdditjd�S |jdkrFtdd|j› d�itjd�S | ¡  ttjddœd d	d
œƒS )Nr3   rÀ  r-   r»  u(   Cannot cancel â€” this leave is already rÆ  rC   r4   zLeave request cancelledr„   )rm   r,   r.   r‘   rP   r¨   rZ   rÁ  rd   rd   re   r¨   Ú  s    

þ
ýz!EmployeeLeaveDetailAPIView.deleteN)rh   ri   rj   rD  rm   rO   r¼   r¨   rd   rd   rd   re   r¾     s
   
#r¾  c                   @   s   e Zd ZdZdd„ ZdS )ÚAdminLeaveListAPIViewz³
    GET /admin-leave/?employee_id=&status=&val=YYYY-MM
 
    employee_id="all" or omitted -> every employee
    status omitted -> every status
    val omitted -> every month
    c              	   C   sô   t j d¡ ¡ }|j d¡}|r4|dkr4|j|d�}|j d¡}|rX|dkrX|j|d�}|j d¡}|r¤z&tt| 	d¡ƒ\}}|j||d	�}W n t
k
r¢   Y nX ttjd
dœd dd„ |D ƒ|jdd� ¡ |jdd� ¡ |jdd� ¡ dœdœƒS )Nr_  r  rQ  r†  r.   r-   rÄ   ú-)Zstart_date__yearZstart_date__monthrC   r4   c                 S   s   g | ]}t |ƒ‘qS rd   r¶  r·  rd   rd   re   r    s     z-AdminLeaveListAPIView.get.<locals>.<listcomp>r»  ÚApprovedÚRejected)ÚpendingZapprovedÚrejected©r.   r3   r9   Úsummary)r¬  rS   r�  rQ  r¤   rO   r�   ÚmaprÎ   rû  rÏ   r,   r.   rZ   r  )r^   r_   r  r±  Ústatus_filterrÄ   r@  rA  rd   rd   re   rO   õ  s.    
ýüzAdminLeaveListAPIView.getNr{  rd   rd   rd   re   rÃ  ì  s   rÃ  c                   @   s   e Zd ZdZdd„ ZdS )ÚAdminLeaveActionAPIViewzX
    PUT /admin-leave/<id>/action/   {status: "Approved" | "Rejected", admin_note?}
    c                 C   sÒ   zt j d¡j|d�}W n( t jk
r@   tdditjd� Y S X |j d¡}|dkrhtdditj	d�S ||_|j d	¡p|d
 
¡ p„d |_|jjr–|jnd |_t ¡ |_| ¡  ttjddœd d|› �t|ƒdœƒS )Nr_  rª   r3   rÀ  r-   r.   )rÅ  rÆ  r»  z-status must be Approved, Rejected, or Pendingr°  rÅ   rC   r4   zLeave marked as r7   )r¬  rS   r�  rO   rT   r,   r.   r‘   r9   rP   rÌ   r°  ra   rk  Úreviewed_byr   r“   r²  r•   rZ   r´  )r^   r_   rE   r³  rx  rd   rd   re   r¼     s*    þ

üzAdminLeaveActionAPIView.putN)rh   ri   rj   rD  r¼   rd   rd   rd   re   rÍ    s   rÍ  c                   @   s   e Zd ZdZdd„ ZdS )ÚTodayUpcomingLeaveAPIViewuÃ   
    GET /leave-today-upcoming/?employee_id=
 
    Used by the admin "View Employee" screen â€” shows who's on
    Approved leave today, and Approved leaves starting in the
    next 30 days.
    c                 C   sž   |j  d¡}t ¡ }tjjdd� d¡}|r@|dkr@|j|d�}|j||d�}|j||tdd	� d
� 	d¡}t
tjddœd dd„ |D ƒdd„ |D ƒdœdœƒS )Nr  rÅ  r-   r_  rQ  r†  )Ústart_date__lteZend_date__gterë  rC  )Zstart_date__gtrÐ  r  rC   r4   c                 S   s   g | ]}t |ƒ‘qS rd   r¶  r·  rd   rd   re   r  P  s     z1TodayUpcomingLeaveAPIView.get.<locals>.<listcomp>c                 S   s   g | ]}t |ƒ‘qS rd   r¶  r·  rd   rd   re   r  Q  s     )r-  r§  ro   )r¤   rO   r,  r-  r¬  rS   r�   r�  r   rÍ   r,   r.   rZ   )r^   r_   r±  r-  r  Ztoday_leavesZupcoming_leavesrd   rd   re   rO   ?  s&     ÿþ
þýzTodayUpcomingLeaveAPIView.getNr{  rd   rd   rd   re   rÏ  6  s   rÏ  )r   r   )Útransaction)r*   ÚCountr    )r   Ú	FeeClientÚFeeÚ
FeePaymentTc                 C   s>   t  ¡ }t  | ¡r.t  | ¡ ¡ t  |¡ ¡ kS |  ¡ | ¡ kS rl   )r   r“   Úis_awareÚ	localtimer   )Údtr“   rd   rd   re   Ú	_is_today€  s    
rÙ  c                 C   s,   |rt | jƒt |ƒkrdS to(t| jƒ  S )zGPayment-ah collect pannina employee mattum (same day-na) edit pannalam.F)r]   Úcollected_by_idÚEMPLOYEE_EDIT_SAME_DAY_ONLYrÙ  Ú
created_at)Úpaymentr  rd   rd   re   Ú_can_edit_payment‡  s    rÞ  c                 C   s,   |rt | jƒt |ƒkrdS to(t| jƒ  S )zoFee record-ah create pannina employee mattum (same day-na) service /
    due date / fee amount ellam maathalam.F)r]   rX   rÛ  rÙ  rÜ  )Úfeer  rd   rd   re   Ú_can_edit_feeŽ  s    rà  c                 C   s   | j | j| j| j| j| jdœS )N©rE   Úclient_coderD   rK  Ú
gst_numberr.   rá  )Úcrd   rd   re   Úclient_json™  s    úrå  c              
   C   sP   | j | jt| jƒ| j d¡| j| j| j| j	r4| j	j nd | j	rD| j	j
nddœdœS )Nr
  r  )rE   rD   )rE   Úfee_idÚamountÚpayment_dateÚpayment_modeÚreference_noÚnoteÚcollected_by)rE   ræ  r]   rç  rè  r7  ré  rê  rë  rì  rD   )rñ  rd   rd   re   Úpayment_json¤  s    
þørí  c                 C   sˆ   | j t| jƒ| jdkr| jn| jp$dt| jƒ| j| j 	d¡| j
rL| j
 	d¡nd t| jƒt| jƒ| jdœ
}|r„dd„ | j ¡ D ƒ|d< |S )NÚOtherr
  )
rE   ÚclientÚserviceÚ
fee_amountÚbilling_frequencyÚdue_dateÚnext_due_dateÚpaid_amountÚbalanceÚpayment_statusc                 S   s   g | ]}t |ƒ‘qS rd   )rí  rð  rd   rd   re   r  Â  s     zfee_json.<locals>.<listcomp>Úpayments)rE   rå  rï  rð  Úservice_otherr]   rñ  rò  ró  r7  rô  rõ  rö  r÷  rø  rQ  )ÚfÚwith_paymentsr9   rd   rd   re   Úfee_json´  s    
örü  c                   @   s   e Zd Zdd„ Zdd„ ZdS )ÚFeeClientListAPIViewc                 C   sj   |j  dd¡ ¡ }tjjdd�}|rH| t|d�t|d�B t|d�B ¡}ttj	dd	œd d
d„ |D ƒdœƒS )NÚsearchrÅ   r   r-   rÇ   ©Zclient_code__icontains)Zmobile__icontainsrC   r4   c                 S   s   g | ]}t |ƒ‘qS rd   )rå  ©r"  rä  rd   rd   re   r  Ù  s     z,FeeClientListAPIView.get.<locals>.<listcomp>ro   )
r¤   rO   rÌ   rÓ  rS   r�   r    r,   r.   rZ   )r^   r_   rþ  Úclientsrd   rd   re   rO   Ë  s    ÿþÿ
ýzFeeClientListAPIView.getc                 C   sX  |j }| d¡pd ¡ }| d¡p$d ¡ }|s@tdditjd�S t|ƒdk r^tdditjd�S |r€t d	|¡s€tdd
itjd�S t	j
j|dd� ¡ }|rÂttjddœd d|j› d�dt|ƒdœƒS |�rt	j
j|dd� ¡ }|�rttjddœd d|j› d�dt|ƒdœƒS t	j
j||�pd | d¡| d¡d�}ttjddœd ddt|ƒdœtjd�S )NrD   rÅ   rK  r3   zClient name is requiredr-   r?   zClient name is too shortz\d{10}z'Mobile number must be exactly 10 digitsr   )Úname__iexactr.   rC   r4   zA client named "z" already exists.T)r.   r3   r8   Zalready_existsr9   )rK  r.   z2A client with this mobile number already exists ("z").r¾   rã  )rD   rK  r¾   rã  zClient addedF)r9   rO   rÌ   r,   r.   rP   r…  rQ   Ú	fullmatchrÓ  rS   r�   r¤  rZ   rD   rå  r’   r¶   )r^   r_   r9   rD   rK  Zexisting_by_nameÚexistingrä  rd   rd   re   rf   Ü  s\    þ
û
ûü
ûúzFeeClientListAPIView.postNr´  rd   rd   rd   re   rý  Ê  s   rý  c                   @   s   e Zd Zdd„ ZdS )ÚFeeClientDetailAPIViewc                 C   sÂ   zt jj|d�}W n( t jk
r:   tdditjd� Y S X tjj|d�j	t
dƒd�d p\d	}tjj|d
� dd¡ ¡ }ttjddœd t|ƒt|ƒ|r¢|j d¡nd |r²t|jƒnd dœ–dœƒS )Nrª   r3   úClient not foundr-   ©Ú	client_idrö  r0  r1  r   ©Úfee__client_idú-payment_daterN  rC   r4   ú%d-%m-%Y)Úpending_balanceÚlast_payment_dateÚlast_payment_amountro   )rÓ  rS   rO   rT   r,   r.   r‘   rÔ  r�   Ú	aggregater*   rÕ  rÍ   r¤  rZ   rå  r]   rè  r7  rç  )r^   r_   rE   rï  r  Úlast_paymentrd   rd   re   rO     s&    " ÿÿ
üýzFeeClientDetailAPIView.getNr  rd   rd   rd   re   r    s   r  c                   @   s   e Zd Zdd„ ZdS )ÚFeeDetailAPIViewc                 C   sh   zt j d¡ d¡j|d�}W n( t jk
rF   tdditjd� Y S X ttj	ddœd t
|d	d
�dœƒS )Nrï  rø  rª   r3   úFee record not foundr-   rC   r4   T©rû  ro   )rÔ  rS   r�  Úprefetch_relatedrO   rT   r,   r.   r‘   rZ   rü  )r^   r_   rE   rß  rd   rd   re   rO   :  s    

ýzFeeDetailAPIView.getNr  rd   rd   rd   re   r  9  s   r  c                   @   s   e Zd Zdd„ ZdS )ÚAdminFeesListAPIViewc           
      C   s®  t j d¡ d¡}|j d¡}|j d¡}|j d¡}|j d¡}|j d¡}|r„z|jt |d¡ 	¡ d	�}W n t
k
r‚   Y nX |rºz|jt |d¡ 	¡ d
�}W n t
k
r¸   Y nX |rÒ|dkrÒ|j|d�}|rê|dkrê|j|d�}|�r
|dk�r
|j|d� ¡ }| d¡}|jtdƒd�d �p,d}|jtdƒd�d �pFd}	ttjddœd dd„ |D ƒt|ƒt|	ƒt||	 ƒ|jdd� ¡ |jdd� ¡ |jdd� ¡ dœdœƒS )Nrï  rø  ÚfromÚtor  r.   rð  r
  )Zdue_date__gte)Zdue_date__lterQ  )r÷  )rð  )Zpayments__collected_by_idú	-due_daterñ  r0  r1  r   rõ  rC   r4   c                 S   s   g | ]}t |ƒ‘qS rd   ©rü  ©r"  rú  rd   rd   re   r  m  s     z,AdminFeesListAPIView.get.<locals>.<listcomp>r»  ÚPartialÚPaid)Útotal_billedÚtotal_collectedÚtotal_pendingÚpending_countZpartial_countZ
paid_countrÉ  )rÔ  rS   r�  r  r¤   rO   r�   r   r+  r   rÏ   ÚdistinctrÍ   r  r*   r,   r.   rZ   r]   r  )
r^   r_   r  Úfrom_strÚto_strr  rÌ  Zservice_filterr  r  rd   rd   re   rO   K  sJ    


úüzAdminFeesListAPIView.getNr  rd   rd   rd   re   r  J  s   r  c                 C   sp   |j  d¡}|j  d¡}|j  d¡}|r<|dkr<| j|d�} |rT|dkrT| j|d�} |rl|dkrl| j|d�} | S )u‡   employee_id / service / payment_mode â€” AdminFeesSummary & EmployeeCollectionReport
    rendayum idhu 3 filters-ah share pannikuranga.r  rð  ré  rQ  ©rÚ  ©Úfee__service©ré  )r¤   rO   r�   )Z
payment_qsr_   r  rð  ré  rd   rd   re   Ú_apply_common_filtersy  s    r)  c                   @   s   e Zd Zdd„ ZdS )ÚAdminFeesSummaryAPIViewc                 C   s°  t  ¡ }tj ddd¡}t||ƒ}t|j|d�jt	dƒd�d pBdƒt|j|j
|jd	�jt	dƒd�d pjdƒt|j|j
d
�jt	dƒd�d pŽdƒt|j|d�jt	dƒd�d p°dƒdœ}|}|j d¡}|j d¡}|�rz|jt |d¡  ¡ d�}W n tk
�r   Y nX |�rHz|jt |d¡  ¡ d�}W n tk
�rF   Y nX | d¡jt	dƒd� d¡}dd„ |D ƒ}	|jt	dƒd�d �pŠd}
ttjddœd |t|
ƒ|	dœdœƒS )Nrß  Úfee__clientrì  ©rè  rç  r0  r1  r   ©Úpayment_date__yearZpayment_date__month)r.  ©Zpayment_date__lte)r-  r   Ú	this_yearZ
till_todayr  r  r
  ©Zpayment_date__gter'  )r  ú-totalc                 S   s"   g | ]}|d  t |d ƒdœ‘qS )r'  r  )rð  r  ©r]   ©r"  rO  rd   rd   re   r  À  s   ÿz/AdminFeesSummaryAPIView.get.<locals>.<listcomp>rC   r4   )ÚcountsÚall_services_totalÚ
by_servicero   )r   r-  rÕ  rS   r�  r)  r]   r�   r  r*   r@  rA  r¤   rO   r   r+  rÏ   ÚvaluesÚannotaterÍ   r,   r.   rZ   )r^   r_   r-  Úbase_qsr5  Zrange_qsr#  r$  Zby_service_rowsr7  r6  rd   rd   re   rO   •  sn    
ÿ ÿþþý ÿÿô
ÿþÿþ
ýýzAdminFeesSummaryAPIView.getNr  rd   rd   rd   re   r*  ”  s   r*  c                   @   s   e Zd ZdZdd„ ZdS )ÚEmployeeFeesAPIViewuÑ  
    GET /employee-fees/?employee_id=&from=&to=

    âœ… Date-wise filter â€” "from"/"to" kudukkaama vittal, DEFAULT-a "TODAY" oru
    naaà®³à¯� data mattume varum (munnadi "whole month" default-a irundhuchu,
    ippo employee login pà®£à¯�à®£à¯�à®®à¯�à®ªà¯‹à®¤à¯‡ "today's collection" first-a à®¤à¯†à®°à®¿à®¯à¯�à®®à¯�).
    "from"/"to" kudutha, andha range-oda data varum. Old "month=YYYY-MM"
    param-um still support pà®£à¯�à®£à¯�rom (backward-compatible).
    c              	      s8  |j  d¡‰ ˆ s"tdditjd�S |j  d¡}|j  d¡}|j  d¡}tjjˆ d� d	d
¡}|sf|�rZ|r z t	 
|d¡ ¡ }|j|d�}W n tk
rž   Y nX |rÚz t	 
|d¡ ¡ }|j|d�}W n tk
rØ   Y nX |�r|�r||k�r|t ¡  d¡k�rdnt	 
|d¡ d¡}n<|�rT|�rTt	 
|d¡ d¡› dt	 
|d¡ d¡› �}nd}n‚|�rÄz8tt| d¡ƒ\}	}
|j|	|
d�}t|	|
dƒ d¡}W n( tk
�rÀ   tdditjd� Y S X nt ¡ }|j|d�}d}| d¡}|jtdƒd�d �pþd}ttjddœd |t|ƒ| ¡ ‡ fd d!„|D ƒd"œd#œƒS )$Nr  r3   rš  r-   r  r  rA  r%  rß  r+  r
  r1  r/  ÚTodayz%d %b %Yz%d %bu    â€“ zSelected rangerÄ  r-  r   r¢  zmonth must be YYYY-MMr,  r  rç  r0  r1  r   rC   r4   c              
      sJ   g | ]B}t |ƒ|jj|jjj|jjj|jjt|ˆ ƒp>t|jˆ ƒd œ–‘qS ))r  râ  Úclient_namerð  Zcan_edit)	rí  rß  r  rï  râ  rD   rð  rÞ  rà  rð  ©r±  rd   re   r    s   	ùúz+EmployeeFeesAPIView.get.<locals>.<listcomp>)r£  r  Úpayment_countrø  ro   )r¤   rO   r,   r.   rP   rÕ  rS   r�   r�  r   r+  r   rÏ   r-  r7  rË  rÎ   rû  rÍ   r  r*   rZ   r]   r  )r^   r_   r#  r$  Z	month_strrø  Z	from_dateZto_dateZrange_labelr@  rA  r-  r  rd   r>  re   rO   ß  sl     ÿ
þ(ÿ


	÷üýzEmployeeFeesAPIView.getNr{  rd   rd   rd   re   r;  Ô  s   
r;  c                   @   s   e Zd ZdZdd„ ZdS )ÚEmployeeCollectionReportAPIViewu³  
    GET /employee-collection-report/?employee_id=&from=&to=&service=&payment_mode=&client_id=

    â”€â”€ employee_id="all" (illa kudukkaama vittal) â”€â”€
      "mode": "all" â€” ella employees-oda totals-um oru list-a varum (idha vachu
      "All Employees" filter-la, andha date range-oda ella employees collection-um
      oru table-a paakalam).

    â”€â”€ employee_id=<id> â”€â”€
      "mode": "employee" â€” andha à®’à®°à¯� employee-oda full report (Total Clients,
      Total Collections, payment history table) â€” munnadi maari thaan.

      client_id kà¯‚da kudutha, adhoda mà¯‡là¯‡ oru "client_summary" block-um varum:
      andha client-ku last payment eppo, evlo, à®‡à®ªà¯�à®ªà¯‹à®¤à¯� pending balance evlo nu.
      (client_summary â€” andha client-oda ella employees payments-um vachu
      calculate aagum, ellai ippove filter panna employee mattum illa â€”
      "last paid when/how much" nu client-oda real status idhà¯�.)
    c              
   C   sØ  |j  d¡}|j  d¡}|j  d¡}|j  d¡}|j  d¡}|j  d¡}|rV|dk�r˜tj dd	d
¡}|rœz|jt |d¡ ¡ d�}W n t	k
rš   Y nX |rÒz|jt |d¡ ¡ d�}W n t	k
rÐ   Y nX |rê|dkrê|j|d�}|�r|dk�r|j|d�}|�r"|dk�r"|j|d�}| 
dd¡jtdƒtdƒtddd�d� d¡}	|jtdƒd�d �phd}
ttjddœd dt|
ƒdd „ |	D ƒd!œd"œƒS ztjj|d#�}W n* tjk
�rÔ   td$d%itjd&� Y S X tjj|d'� dd	¡}|�r&z|jt |d¡ ¡ d�}W n t	k
�r$   Y nX |�r`z|jt |d¡ ¡ d�}W n t	k
�r^   Y nX |�r||dk�r||j|d�}|�r˜|dk�r˜|j|d�}|�r´|dk�r´|j|d�}| d(¡}|jtdƒd�d �pÖd}
| 
d¡ ¡  ¡ }d }|�r¢|dk�r¢zŠtjj|d#�}tjj|d)�jtd*ƒd�d �p0d}tjj|d� d+d,¡ ¡ }|j|jt|ƒ|�rl|j d-¡nd |�r~t|j ƒnd d.œ}W n tjk
�r    Y nX ttjddœd d/|j|t|
ƒ|d0d „ |D ƒd1œd"œƒS )2Nr  r  r  rð  ré  r  rQ  rß  r+  rì  r
  r1  r/  r&  r(  r	  rÚ  Úcollected_by__namerç  rE   r
  T)r"  )r  r?  r  r2  r0  r1  r   rC   r4   c                 S   s8   g | ]0}|d  |d pdt |d ƒ|d |d dœ‘qS )rÚ  rA  r  r  r?  r  )r  r­  Útotal_collectionsr?  Útotal_clientsr3  r4  rd   rd   re   r  x  s   ú

ûz7EmployeeCollectionReportAPIView.get.<locals>.<listcomp>)ÚmoderB  rS  ro   rª   r3   rp  r-   r%  rè  r  rö  r  rN  r  )râ  rD   r  r  r  r_  c                 S   s6   g | ].}|j  d ¡|jjj|jjt|jƒ|jdœ‘qS )r  )r   rï  rð  rç  ré  )	rè  r7  rß  rï  rD   rð  r]   rç  ré  rð  rd   rd   re   r  Ã  s   ú
û)rD  r­  rC  rB  Úclient_summaryrø  )!r¤   rO   rÕ  rS   r�  r�   r   r+  r   rÏ   r8  r9  r*   rÒ  rÍ   r  r,   r.   rZ   r]   r   rT   r‘   r"  r  rÓ  rÔ  r¤  râ  rD   rè  r7  rç  )r^   r_   r±  r#  r$  rð  ré  r  r  ÚrowsrB  r_  rC  rE  rï  r  r  rd   rd   re   rO   J  sÆ    
üúÿ	
øýý
"ÿ ÿÿû

øúýz#EmployeeCollectionReportAPIView.getNr{  rd   rd   rd   re   r@  6  s   r@  ZPtsImh5xd6D9V8yaSQoifOPlrj41c2TELqFwp7BkHCKeNAXgJYWWpKkENHqSL35VRrnJ6XlF8xBIgZfC4c                 C   sþ  �z¼t | jjpdƒ ¡ }|s,t d¡ W dS | dd¡ dd¡ dd¡}| d¡r^|dd	… }t|ƒd
ksr| 	¡ sˆt d|› �¡ W dS t
jj| d�jtdƒd�d p¨d}| j| }| jdkrÊ| jrÊ| jn| j}d| jj› d|jd›d|› d|d›d|j› d|j d¡› d�}d}tdddœ}	d|dd|d d!œ}
tj||	|
d"d#�}t d$|j¡ |jd%k�r | ¡ }| d&¡d'k�rŠt d(|› �¡ W d'S t d)|› �¡ W dS t d*|j› d+|j› �¡ W dS  tk
�rø } zt d)|› �¡ W Y ¢dS d	}~X Y nX d	S ),z9Payment save aana apparam client-ku Fast2SMS SMS anuppum.rÅ   zClient mobile number missingFz+91rd  rÄ  Ú0r   Né
   zInvalid client mobile number: )rß  rç  r0  r1  r   rî  zHi zW,

Manju Associates
Payment Received Successfully

We have received your payment of Rs.z,.0fz for z.
Balance: Rs.z
Collected by: z
Date: r  z;

Thank you for choosing Manju Associates.
Have a nice day!z#https://www.fast2sms.com/dev/bulkV2zapplication/json)ÚauthorizationÚacceptzcontent-typeÚqÚenglishrØ   )Úrouter8   ÚlanguageZflashÚnumbersZsms_detailsé   )ÚheadersÚjsonÚtimeoutzFast2SMS Response: %sr¡   ÚreturnTz!Payment SMS sent successfully to zFast2SMS SMS failed: zFast2SMS HTTP Error rW  ) r]   rï  rK  rÌ   Úloggerr3   r6  Ú
startswithr…  ÚisdigitrÕ  rS   r�   r  r*   rñ  rð  rù  rD   rç  rè  r7  ÚFAST2SMS_API_KEYÚrequestsrf   ÚinfoÚtextrv  rR  rO   rx   Ú	exception)rß  rÝ  r_  rL   Ú
total_paidrö  rð  ÚbodyrW   rQ  r9   r6   Úresultr}   rd   rd   re   Úsend_payment_smsà  sŽ    

ÿýüû
ÿÿý
<ÿýúüþÿÿÿÿr`  c                   @   s   e Zd Zdd„ ZdS )ÚFeePaymentCreateAPIViewc              
   C   s  |j }| d¡}|s&tdditjd�S ztjj|d�}W n( tjk
r`   tdditjd� Y S X | d¡}|s‚tdditjd�S zt	t
|ƒƒ}|d	krœt‚W n* ttfk
rÈ   tdd
itjd� Y S X | d¡}|�rztjj|d�}W n* tjk
�r   tdditjd� Y S X �n6| d¡}| d¡}	|�r<|	�sNtdditjd�S ztjj|d�}
W n* tjk
�rŠ   tdditjd� Y S X zt |	d¡ ¡ }W n( tk
�rÈ   tdditjd� Y S X | d|¡}zt	t
|ƒƒ}|d	k�ròt‚W n, ttfk
�r    tdditjd� Y S X tjj|
| dd¡| d¡|| dd¡||d�}| d¡}z"|�rtt |d¡ ¡ nt ¡ }W n( tk
�r¦   tdditjd� Y S X tjj||||| dd¡| d¡| d ¡d!�}| ¡  t|||ƒ ttjd"d#œd d$t|d%d&�d'œtjd�S )(Nr  r3   rš  r-   rª   rp  rç  zamount is requiredr   z&amount must be a valid positive numberræ  r  r  ró  z7client_id and due_date are required to create a new feer  r
  zdue_date must be YYYY-MM-DDrñ  z*fee_amount must be a valid positive numberrð  z
GST Filingrù  rò  ÚMonthly)rï  rð  rù  rñ  rò  ró  rf  rè  zpayment_date must be YYYY-MM-DDré  ÚCashrê  rë  )rß  rì  rç  rè  ré  rê  rë  rC   r4   zPayment recordedTr  r7   )r9   rO   r,   r.   rP   r   rS   rT   r‘   rÀ  r]   rÁ  rÒ  rÔ  rÓ  r   r+  r   rÏ   r’   r-  rÕ  Úrefresh_from_dbr`  r¶   rü  )r^   r_   r9   r  r_  rç  ræ  rß  r  Zdue_date_strZ
fee_clientró  Zfee_amount_rawrñ  Zpayment_date_strrè  rÝ  rd   rd   re   rf   �  s¨    




þ
þ

ù

ÿþ
ù	

üûzFeePaymentCreateAPIView.postNrg   rd   rd   rd   re   ra  œ  s   ra  c                   @   s   e Zd Zdd„ ZdS )ÚClientHistoryAPIViewc              
      sd  |j  d¡}|s"tdditjd�S ztjj|d�}W n, tjtfk
r`   tdditj	d� Y S X t
jj|d� d¡ d	¡}|jtd
ƒtdƒtdƒd�}tjj|d� dd¡ dd¡}| ¡ }dd„ ‰ ttjddœd t|ƒt|d pædƒt|d pôdƒt|d �pdƒdœ|�r:|j d¡t|jƒ|j�r2|jjnddœnd dd„ |D ƒ‡ fd d„|D ƒd!œd"œƒS )#Nr  r3   zclient_id is requiredr-   rª   r  r  rï  r  rñ  rõ  rö  )rß  ÚpaidrÇ  r	  rß  rì  r  rN  c                 S   s   | j dkr| j S | jpdS )Nrî  )rð  rù  )rú  rd   rd   re   Úsvc  s    z%ClientHistoryAPIView.get.<locals>.svcrC   r4   r   rf  rÇ  )Z	total_feer]  r   r  r  )r   rç  rì  c                 S   s   g | ]}t |ƒ‘qS rd   r  r  rd   rd   re   r  )  s     z,ClientHistoryAPIView.get.<locals>.<listcomp>c              
      sH   g | ]@}|j |j|j d ¡t|jƒ|jˆ |jƒ|jr<|jj	nddœ‘qS )r  r  )rE   ræ  r   rç  ré  rð  rì  )
rE   ræ  rè  r7  r]   rç  ré  rß  rì  rD   rð  ©rg  rd   re   r  *  s   
ø
ù)rï  Útotalsr  Úfeesrø  ro   )r¤   rO   r,   r.   rP   rÓ  rS   rT   rÏ   r‘   rÔ  r�   r�  rÍ   r  r*   rÕ  r¤  rZ   rå  r]   rè  r7  rç  rì  rD   )r^   r_   r  rï  rj  ri  rø  Úlastrd   rh  re   rO     sP     ÿ þÿ
ý	ü
ý

öóýzClientHistoryAPIView.getNr  rd   rd   rd   re   re    s   re  c                   @   s4   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	d
„ ZdS )ÚFeePaymentDetailAPIViewc                 C   s8   zt j ddd¡j|d�W S  t jk
r2   Y d S X d S )Nrß  r+  rì  rª   )rÕ  rS   r�  rO   rT   r¿  rd   rd   re   rm   D  s    z"FeePaymentDetailAPIView.get_objectc                 C   sx   |j }t|ƒ|jt|jƒ|j|jt|jƒ|j	|j
 d¡|jrH|j d¡nd t|jƒt|jƒ|jdœt||ƒt||ƒdœS )Nr
  )rE   rï  rð  rù  rñ  rò  ró  rô  rõ  rö  r÷  )rÝ  rß  Zcan_edit_paymentZcan_edit_fee)rß  rí  rE   rå  rï  rð  rù  r]   rñ  rò  ró  r7  rô  rõ  rö  r÷  rÞ  rà  )r^   rñ  r  rß  rd   rd   re   Ú_detailJ  s"    
õðzFeePaymentDetailAPIView._detailc                 C   sL   |   |¡}|s tdditjd�S |j d¡}ttjddœd |  ||¡dœƒS )Nr3   úPayment not foundr-   r  rC   r4   ro   )rm   r,   r.   r‘   r¤   rO   rZ   rm  ©r^   r_   rE   rñ  r  rd   rd   re   rO   _  s    


ýzFeePaymentDetailAPIView.getc              	      sœ  |   |¡}|s tdditjd�S |j‰ ˆ  d¡}|sFtdditjd�S |j}t||ƒ}t	||ƒ}t
rhdnd}|sŽ|sŽtdd|› d	�itjd�S d
}	d}
|sÊt‡ fdd„|	D ƒƒrÊtdd|› d	�itjd�S |sþt‡ fdd„|
D ƒƒrþtdd|› d	�itjd�S dd„ }dd„ }dd„ }|j}|j}|j}tt|jƒƒ}�zR|�r²dˆ k�rV|ˆ d ƒ}ˆ  d¡�rn|ˆ d ƒ}ˆ  d¡�r²dd„ tj d¡jD ƒ}ˆ d |k�rª|dƒW S ˆ d }|�r€dˆ k�rÎ|ˆ d ƒ}ˆ  d¡�r
dd„ tj d¡jD ƒ}ˆ d |k�r
|d ƒW S ˆ  d!¡�rFd"d„ tj d!¡jD ƒ}ˆ d! |k�rF|d#ƒW S ˆ  d$¡�r^|ˆ d$ ƒnd }ˆ  d%¡�rz|ˆ d% ƒnd }nd  }}W n> ttfk
�r¬   |d&ƒ Y S  tk
�rÈ   |d'ƒ Y S X |jj|jd(�jtdƒd)�d* �pòtd+ƒ}|| |k�r|d,|| › d-|› d.�ƒS t  !¡ ��D |�rðt"|�o>||j#kƒ}t"ˆ  d!¡�o\ˆ d! |j$kƒ}||_ˆ  d¡�r|ˆ d |_%d/ˆ k�r¢ˆ  d/¡�p”d &¡ �pžd |_'ˆ  d!¡�r¸ˆ d! |_$|�rÄ||_#|�rÒ||_(n|�sÞ|�rè| )¡ |_(| *¡  |�r^||_||_||_d0ˆ k�r.ˆ  d0¡�p d &¡ �p*d |_+d1ˆ k�rTˆ  d1¡�pFd &¡ �pPd |_,| *¡  n| -¡  W 5 Q R X |   |¡}ttj.d2d3œd d4|  /||¡d5œƒS )6Nr3   rn  r-   r  rš  z (same day only)rÅ   z5Only the employee who entered this record can edit itrÆ  )rç  rè  ré  rê  rë  )rð  rù  rò  rñ  ró  rô  c                 3   s   | ]}|ˆ kV  qd S rl   rd   ©r"  Úk©r9   rd   re   rŒ  €  s     z.FeePaymentDetailAPIView.put.<locals>.<genexpr>zYou can't edit this paymentc                 3   s   | ]}|ˆ kV  qd S rl   rd   rp  rr  rd   re   rŒ  ‚  s     zOYou can't edit the fee details (service / due date / fee amount) of this recordc                 S   s   t d| itjd�S )Nr3   r-   )r,   r.   rP   )r³  rd   rd   re   Úbadˆ  s    z(FeePaymentDetailAPIView.put.<locals>.badc                 S   s   t  | d¡ ¡ S )Nr
  )r   r+  r   rÚ  rd   rd   re   Ú
parse_date‹  s    z/FeePaymentDetailAPIView.put.<locals>.parse_datec                 S   s   t t| ƒƒ}|dkrt‚|S )Nr   )rÀ  r]   rÁ  )rÍ  Úvrd   rd   re   Úparse_moneyŽ  s    z0FeePaymentDetailAPIView.put.<locals>.parse_moneyrç  rè  ré  c                 S   s   h | ]}|d  ’qS ©r   rd   r   rd   rd   re   r$     s     z.FeePaymentDetailAPIView.put.<locals>.<setcomp>zInvalid payment moderñ  rð  c                 S   s   h | ]}|d  ’qS rw  rd   r   rd   rd   re   r$  ¨  s     zInvalid servicerò  c                 S   s   h | ]}|d  ’qS rw  rd   r   rd   rd   re   r$  ¬  s     zInvalid billing frequencyró  rô  z&Amount must be a valid positive numberrÂ  rª   r0  r1  rG  u   Total collected (â‚¹u"   ) would exceed the fee amount (â‚¹ú).rù  rê  rë  rC   r4   zRecord updatedr7   )0rm   r,   r.   r‘   r9   rO   rP   rß  rÞ  rà  rÛ  rU   Úanyrç  rè  ré  rÀ  r]   rñ  rÕ  Ú_metaÚ	get_fieldÚchoicesrÔ  rÁ  rÒ  rÏ   rø  r3  rE   r  r*   rÑ  Úatomicr1  ró  rò  rð  rÌ   rù  rô  Úcompute_next_due_dater•   rê  rë  ÚrecalcrZ   rm  )r^   r_   rE   rñ  r  rß  Zcan_payZcan_feeZruleZpay_keysZfee_keysrs  rt  rv  Z
new_amountZnew_pay_dateZnew_modeZnew_fee_amountÚvalidZnew_dueZnew_next_dueÚothersZdue_changedZfreq_changedrd   rr  re   r¼   j  sÎ    



þþ




*ÿÿ









üzFeePaymentDetailAPIView.putc                 C   st   |   |¡}|s tdditjd�S |j d¡p6|j d¡}t||ƒsTtdditjd�S | 	¡  ttj
ddœd dd	œƒS )
Nr3   rn  r-   r  z9Only the employee who entered this payment can cancel it.rC   r4   zPayment removedr„   )rm   r,   r.   r‘   r¤   rO   r9   rÞ  rU   r¨   rZ   ro  rd   rd   re   r¨   æ  s    

þ
ýzFeePaymentDetailAPIView.deleteN)rh   ri   rj   rm   rm  rO   r¼   r¨   rd   rd   rd   re   rl  C  s
   |rl  c                   @   s   e Zd ZdZdd„ ZdS )ÚEmployeeStatusAPIViewuÃ   
    Active / Inactive toggle mattum. geostatus-à®� à®‡à®¤à¯�à®² à®¤à¯Šà®Ÿà®¾à®¤à¯� â€”
    à®…à®¤à¯� à®¤à®©à®¿ concept, à®¤à®©à®¿ button, à®¤à®©à®¿ API (à®•à¯€à®´ EmployeeGeoStatusAPIView).
    c                 C   sv   zt jj|d�}W n. t jk
r@   tdddœddœdd� Y S X |jdkrPd	nd|_| ¡  td
ddœ|jddœƒS )Nr=   r£   r¦   r4   rp  ©r.   r3   r-   r   r?   r¡   rC   rv  rw  )r   rS   rO   rT   r,   r.   r•   ©r^   r_   rE   r_  rd   rd   re   rz  ü  s     þýýzEmployeeStatusAPIView.patchN©rh   ri   rj   rD  rz  rd   rd   rd   re   r‚  ö  s   r‚  c                   @   s   e Zd ZdZdd„ ZdS )ÚEmployeeGeoStatusAPIViewu“  
    âœ… à®ªà¯�à®¤à¯� API â€” "Anywhere Attendance" / WFH toggle.
    geostatus = 1 -> office geofence-à®� bypass à®ªà®£à¯�à®£à®¿ à®Žà®™à¯�à®•à®¿à®°à¯�à®¨à¯�à®¤à¯�à®®à¯� attendance mark à®ªà®£à¯�à®£à®²à®¾à®®à¯�
    geostatus = 2 (à®…à®²à¯�à®²à®¤à¯� default) -> office radius-à®•à¯�à®•à¯�à®³à¯� à®¤à®¾à®©à¯� attendance mark à®ªà®£à¯�à®£ à®®à¯�à®Ÿà®¿à®¯à¯�à®®à¯�
 
    PATCH /employee-geostatus/<id>/
    c                 C   sŽ   zt jj|d�}W n. t jk
r@   tdddœddœdd� Y S X t|dƒ |jd	krZd
nd	|_| ¡  tdddœ|j|jd	kr„dnddœƒS )Nr=   r£   r¦   r4   rp  rƒ  r-   ZRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRr   r?   r¡   rC   zAnywhere attendance enabledu9   Anywhere attendance disabled â€” office location required)r.   Znew_geostatusr8   )r   rS   rO   rT   r,   ry   rN   r•   r„  rd   rd   re   rz    s&    þý
ÿúzEmployeeGeoStatusAPIView.patchNr…  rd   rd   rd   re   r†    s   r†  c                   @   s4   e Zd ZefZd
dd„Zdd„ Zdd„ Zdd	„ ZdS )Ú
AnnAPIViewNc                 C   sú   |d k	rrz:t jj|d�}|j|j|jdœ}ttjddœd |dœƒW S  t	k
rn   ttj
ddœddd	œƒ Y S X n„zTd
}g }t j ¡ D ]&}|d7 }| ||j|j|jdœ¡ q†ttjddœd |dœƒW S  t	k
� rô   ttj
ddœddd	œƒ Y S X d S )Nrª   )rE   r   r¶  rC   r4   ro   r¦   Trì   r„   r   r   )rO  rE   r   r¶  )r
   rS   rO   rE   r   r¶  r,   r.   rZ   r   r‘   rQ  rÐ   rº  rd   rd   re   rO   ¶  sP    ý
ý

ýü

ý

ýzAnnAPIView.getc              
   C   sž   |j }zN|d }|d }tjj|d |d |jd�}| ¡  ttjddœd ddœƒW S  t	k
r˜ } z&ttj
ddœd	d
|› �dœƒ W Y ¢S d }~X Y nX d S )Nr   r¶  )r   r¶  rf  rC   r4   z!Announcement created successfullyr„   r¦   Tr´   )r9   r
   rS   r’   ra   r•   r,   r.   r¶   r·   rP   )r^   r_   r9   r   r¶  r°   r}   rd   rd   re   rf   ç  s*    ý
ý

ýzAnnAPIView.postc              
   C   sÐ   |j }zT|d }|d }tjj|d�}|d |_|d |_| ¡  ttj	ddœd ddœƒW S  t
k
r†   ttjddœd	d
dœƒ Y S  tk
rÊ } z(t|ƒ ttjddœd	ddœƒ W Y ¢S d }~X Y nX d S )Nr   r¶  rª   rC   r4   z!Announcement updated successfullyr„   r¦   Trì   rÊ   )r9   r
   rS   rO   r   r¶  r•   r,   r.   rZ   r   r‘   rx   ry   rP   )r^   r_   rE   r9   r   r¶  r°   r}   rd   rd   re   r¼     s4    


ý

ý
ýzAnnAPIView.putc                 C   sj   |d k	rfz0t jj|d�}| ¡  ttjddœd ddœƒW S  tk
rd   ttjddœd ddœƒ Y S X d S r½  )	r
   rS   rO   r¨   r,   r.   rZ   r   r‘   r¿  rd   rd   re   r¨   %  s    
ý

ýzAnnAPIView.delete)Nr·  rd   rd   rd   re   r‡  ³  s
   
1$r‡  c                   @   s4   e Zd ZefZd
dd„Zdd„ Zdd„ Zdd	„ ZdS )ÚLeaveAPIViewNc           	      C   s*  |d k	r~zFt jj|d�}|j|j|j|j|j|jdœ}t	tj
ddœd |dœƒW S  tk
rz   t	tjddœddd	œƒ Y S X n¨zxd
}g }t jj|jd�D ]D}|d7 }|j}| d¡}| ||j|j|j|j||j|jdœ¡ q˜t	tj
ddœd |dœƒW S  tk
�r$   t	tjddœddd	œƒ Y S X d S )Nrª   )rE   rD   r¶  Ú	totaldaysÚ
leavedatesr.   rC   r4   ro   r¦   Trì   r„   r   rî   r   ú%Y-%m-%d %H:%M:%S)rO  rE   ÚtypeÚreasonÚtdr   r.   Úwhy)r   rS   rO   rE   rŒ  r�  Ú
total_daysÚleave_datesr.   r,   rZ   r   r‘   r�   ra   rÜ  r7  rÐ   r�  )	r^   r_   rE   r°   r9   rT  rÒ   Útfr9  rd   rd   re   rO   =  sb    ú	
ý

ý
ø

ý

ýzLeaveAPIView.getc              
   C   s  |j }zÆ|d }|d }t|d |d |d |d |jd�}| ¡  tjj|jd�}tjj|jd�}|j}d}	d}
d	|j	› d
|› d|› d|	› d�	}|j}t
|
|tj|gd�}| ¡  ttjddœd ddœƒW S  tk
�r } z&ttjddœdd|› �dœƒ W Y ¢S d }~X Y nX d S )NrD   Útotaldayr¶  Ú	leavedate)rŒ  r�  r�  r‘  rf  r=   z+https://pearlpackagingindia.com/manageleaveúLeave requestz
            Hi am z,,

            This is my leave request for z.

            Total days: z[

            

            You can log in using the following link and check:
            z)

            

            
            ©r|   r^  Ú
from_emailr  rC   r4   z"Leave request created successfullyr„   r¦   Tr´   )r9   r   ra   r•   r   rS   rO   rë   r;   rD   r&   r   ÚEMAIL_HOST_USERÚsendr,   r.   r¶   r·   rP   )r^   r_   r9   ZcasualÚmanZleave_requestÚjkZmeesiÚroÚ	login_urlr|   r^  Úwer;   r}   rd   rd   re   rf   z  sZ    ûÿýû
öü	
ý

ýzLeaveAPIView.postc              
   C   sÔ   |j }zXtjj|d�}|d |_|d |_|d |_|d |_| ¡  t	t
jddœd dd	œƒW S  tk
rŠ   t	t
jd
dœddd	œƒ Y S  tk
rÎ } z(t|ƒ t	t
jd
dœddd	œƒ W Y ¢S d }~X Y nX d S )Nrª   rD   r¶  r”  r“  rC   r4   r»  r„   r¦   Trì   rÊ   )r9   r   rS   rO   rŒ  r�  r‘  r�  r•   r,   r.   rZ   r   r‘   rx   ry   rP   r¼  rd   rd   re   r¼   ¾  s4    




ý

ý
ýzLeaveAPIView.putc                 C   sj   |d k	rfz0t jj|d�}| ¡  ttjddœd ddœƒW S  tk
rd   ttjddœd ddœƒ Y S X d S r½  r¾  r¿  rd   rd   re   r¨   Ý  s    
ý

ýzLeaveAPIView.delete)Nr·  rd   rd   rd   re   rˆ  8  s
   
=Drˆ  c                   @   s$   e Zd ZefZddd„Zdd„ ZdS )ÚManageleaveAPIViewNc                 C   s’  |d k	r„zJt jj|d�}|j|j|jt|jƒ|j|j	dœ}t
tjddœd |dœƒW S  tk
r~   t
tjddœddd	œƒ Y S X �n
zÚd
}g }tjj|jd�}|D ]¢}t jj|jd�D ]Œ}|d7 }|j}	|	 d¡}
z(|j}tjj|d�}|jd |j }W n  ttjfk
�r   d}Y nX | ||j|j|j|j|
|j|dœ¡ q¶q¢t
tjddœd |dœƒW S  tk
�rŒ   t
tjddœddd	œƒ Y S X d S )Nrª   )rE   rD   r¶  r‰  rŠ  r�  rC   r4   ro   r¦   Trì   r„   r   )rë   )rf  r   r‹  rd  ÚUnknown)rO  rE   rŒ  r�  rŽ  r   r.   r1   )r   rS   rO   rE   rŒ  r�  rÎ   r�  r‘  r�  r,   r.   rZ   r   r‘   r   r�   ra   r>   rÜ  r7  rX   r   r[   r®   rÏ   rT   rÐ   )r^   r_   rE   r°   r9   rT  rÒ   ZerpÚmr’  r9  r>   rÄ   r1   rd   rd   re   rO   ó  sr    ú	
ý

ý

ø
ý

ýzManageleaveAPIView.getc              
   C   sî  |j }�zfz |d d k	r$t|d ƒnd}W n ttfk
rF   d}Y nX | d¡}| dd¡}| dd¡}|dkrxd}n|dkr†d	}nd
}zÆtjj|d�}	||	_| dd¡|	_| dd¡|	_	||	_
||	_| dd¡|	_|	 ¡  |dk�rNz:tjj|	jd�}
|
jd k�r d|
_t|
jƒ|
_|
 ¡  W n* tjk
�rL   td|	j› d�ƒ Y nX W nB tjk
�r’   td|› d�ƒ ttjddœdddœƒ Y W S X z|tjj|jd�}tjj|	jd�}
|j}d}d}d|› d|› d|› d|› d�	}|
j}t|d ƒ t||tj|gd!�}| ¡  W nD tjk
�rT   td|	j› d�ƒ ttjddœdd"dœƒ Y W S X ttjd#dœd d$dœƒW S  tk
�rœ   ttjddœdddœƒ Y S  tk
�rè } z.td%|› �ƒ ttjddœdd&dœƒ W Y ¢S d }~X Y nX d S )'Nr“  ç        r.   rD   rÅ   rÆ   rÅ  Ú3rÆ  r»  rª   r¶  r”  r�  r=   r   zProfile for user ID z does not exist.zLeaveRequest with ID r¦   r4   Trì   r„   z,https://pearlpackagingindia.com/leaverequestr•  z$
                Your leave request z is z.
                Total days: zU

                You can log in using the following link and check:
                z
                zSending email to recipientr–  z(Profile not found for email notificationrC   zRequest updated successfullyzError occurred: rÊ   ) r9   r¬  rÏ   rÒ  rO   r   rS   rŒ  r�  r‘  r�  r.   r�  r•   r   rX   Ztotal_leaverÎ   rT   ry   r,   r‘   ra   r;   r&   r   r˜  r™  rZ   r   rx   rP   )r^   r_   rE   r9   ZrtoÚstaÚmlÚnamesrž  r°   r±   r›  rœ  r�  r|   r^  Zrecipient_emailr;   r}   rd   rd   re   r¼   ?  s²     




ýÿÿþû
ü
ý
ý

ý
ýzManageleaveAPIView.put)N)rh   ri   rj   r$   rp   rO   r¼   rd   rd   rd   re   rŸ  ð  s   
LrŸ  c                   @   s   e Zd Zdd„ ZdS )Ú	FpAPIViewc           	   
   C   s®   |j }z^| di ¡}| d¡}| d¡}t|ƒ}tjj|d�}||_| ¡  ttj	ddœd ddœƒW S  t
k
r¨ } z&ttjd	dœd
d|› �dœƒ W Y ¢S d }~X Y nX d S )Nr‚   r;   r2   r:   rC   r4   zPassword reset successfullyr„   r¦   Tr´   )r9   rO   r   r   rS   r2   r•   r,   r.   rZ   r·   rP   )	r^   r_   r9   r‚   r;   r2   rÔ   rš  r}   rd   rd   re   rf   ý  s(    


ý

ýzFpAPIView.postNrg   rd   rd   rd   re   r§  ù  s   r§  c                 C   s(   t dt| ƒƒ} | d d›d| d d›�S rã  ræ  rç  rd   rd   re   rè  ,  s    c                     s    t jjdd�\} }| jp tddƒ}| jp0tddƒ}t| jp<dƒ}dd„ | jpNd	 	d
¡D ƒ‰ ‡ fdd„t
tƒD ƒ}t t ¡ |¡t|d�  ¡ }| |||||dœS )Nr   ré  rò   rë  rì  r   c                 S   s(   h | ] }|  ¡ r|  ¡ d d…  ¡ ’qS rí  rî  rð  rd   rd   re   r$  7  s   þrò  rÅ   ró  c                    s   h | ]\}}|ˆ kr|’qS rd   rd   rô  rö  rd   re   r$  <  s      r÷  )rù  r  r  r  r  r  )r   rS   r­  r  r%   r  rÎ   r  r  rû  rR  r   r   rü  r,  r-  r   rý  rd   rö  re   r.  1  s"    þÿúc                 C   s   t | o| |d kƒS r  r  r  rd   rd   re   r  L  s    c                 C   sH   | r| |d krdS t  ¡ }t || ¡t ||d ¡ }t| ¡ d ƒS )Nr  r   rž   )r,  r-  r   rü  rÎ   r  )r®  r;  r  Údiffrd   rd   re   r…  P  s
    r…  c                   @   s   e Zd Zddd„Zdd„ ZdS )ÚSalaryAPIViewNc                 C   s‚  |d k	rtz:t jj|d�}|j|j|jdœ}ttjddœd |dœƒW S  t	k
rn   ttj
ddœddd	œƒ Y S X �n
�z´t ¡ }t|j d
|j¡ƒ}t|j d|j¡ƒ}t ||¡d }ddlm}	 |	||dƒ}
|	|||ƒ}tdddƒ}d}d}g }tj ¡ D �]}|d7 }tjj|j|
|d�}|jdd� ¡ }d}|jdd�D ]"}|j�r@|j|k�r@|d7 }�q@|d d }td|| ƒ}| ||j|j|jt|jƒt|j ƒt|j!ƒt|j"ƒt|j#ƒt|j$ƒ|||||t|j%ƒt|j&ƒt|j'ƒt|j(ƒt|j)ƒt|j*ƒ||dœ¡ t+|ƒ � qþttjddœd |dœƒW S  t,k
�r| } z2t+d|› �ƒ ttj-ddœdt.|ƒd	œƒ W Y ¢S d }~X Y nX d S )Nrª   r¹  rC   r4   ro   r¦   Trì   r„   rA  r@  r   r   r|  rò   re  )r  r›  Z	date__lter  r-   r¤  r¢  )rO  rE   rD   rÜ   r×   ÚgrossSalaryÚbasicÚhraÚ
conveyanceÚotherAllowanceZ	totalDaysZworkingDaysZpresentDaysZ	lateCountZlateDeductionÚfixedPTÚpfLimitÚadvancerS  ÚreimbursementÚ	incentiverA  r@  rh  )/r   rS   rO   rE   rD   r¶  r,   r.   rZ   r   r‘   r   r“   rÎ   r¤   rA  r@  ÚcalendarÚ
monthranger   r%   r   rQ  r   r�   r  r¥  r•  rÐ   rÜ   r¬  r×   rª  r«  r¬  r­  r®  r¯  r°  r±  rS  r²  r³  ry   rx   rP   r]   )r^   r_   rE   r°   r9   r“   rA  r@  r�  r   r¥  r¦  Z	LATE_TIMEZLATES_PER_DAY_CUTrT  rÒ   Zattendance_qsZpresent_daysr@  r£  Zlate_deduction_daysZworking_daysr}   rd   rd   re   rO   Z  s¤    ý
ý

ýýé
ý

ýzSalaryAPIView.getc              
   C   s”  |j }�z
tjj|d�}| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j	¡|_	| d|j
¡|_
| d	|j¡|_| d
|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| ¡  ttjddœd d|j› d�dœƒW S  tjk
�rB   ttjddœdddœƒ Y S  tk
�rŽ } z.td|› �ƒ ttjddœdddœƒ W Y ¢S d }~X Y nX d S )Nrª   rÜ   r×   rª  r«  r¬  r­  r®  r¯  r°  r±  rS  r²  r³  rC   r4   z	Employee z updated successfullyr„   r¦   Trp  rh  z"Something went wrong during update)r9   r   rS   rO   rÜ   r×   rª  r«  r¬  r­  r®  r¯  r°  r±  rS  r²  r³  r•   r,   r.   rZ   rD   rT   r‘   rx   ry   rP   )r^   r_   rE   r9   r_  r}   rd   rd   re   r¼   Ë  sF    
ý

ý
ýzSalaryAPIView.put)N)rh   ri   rj   rO   r¼   rd   rd   rd   re   r©  X  s   
qr©  c                   @   s   e Zd Zddd„Zdd„ ZdS )ÚPayslipAPIViewNc              "   C   s¦  |d k	rìz²t jj|d�}|j|j|j|j|j|j|j	|j
|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j|j |j!|j"|j#dœ!}t$t%j&ddœd |dœƒW S  t j'k
rè   t$t%j(ddœddd	œƒ Y S X n¶zbd
}g }t j )¡ D ]4}|d7 }| *||j|j|j"|j#dœ¡ t+|ƒ �q t$t%j&ddœd |dœƒW S  t,k
�r  } z2t+d|› �ƒ t$t%j-ddœdt.|ƒd	œƒ W Y ¢S d }~X Y nX d S )Nrª   )!rE   ÚempnameÚempidÚemppanr×   ÚgrosssalaryÚperdaysalaryÚbasicsalaryr¬  r­  Úotherallowancer‰  ÚworkingdaysÚbaiscnewÚhranewÚconveyancenewÚotherallowancenewÚgrosspayÚvariablepfgrossÚpflessÚesilessÚlessptÚpfÚesiÚbankrÛ   r±  ÚnetpayrS  r²  r³  ÚtopayrA  rC   r4   ro   r¦   TzPayslip not foundr„   r   r   )rO  rE   rD   rÌ  rA  rh  )/r   rS   rO   rE   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±  rË  rS  r²  r³  rÌ  rA  r,   r.   rZ   rT   r‘   rQ  rÐ   ry   rx   rP   r]   )r^   r_   rE   r°   r9   rT  rÒ   r}   rd   rd   re   rO     s’    ß#
ý

ýû
ý

ýzPayslipAPIView.getc              %   C   sÄ  �zj|j  dg ¡}|s0ttjddœdddœƒW S g }g }ddd	d
dddddddddœ}|D �]Ö}| d¡}| d¡}| t|ƒt|ƒ¡}	ztjj|d�}
W n tj	k
r´   Y qZY nX t
jj|
|	d� ¡ }|�rà| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d |j¡|_| d!|j¡|_| d"|j¡|_| d#|j¡|_| d$|j¡|_| d%|j¡|_| d&|j¡|_| d'|j¡|_| d(|j¡|_| d)|j¡|_| d*|j¡|_| d+|j ¡|_ | d,|j!¡|_!| d-|j"¡|_"| d.|j#¡|_#| d/|j$¡|_$| d0|j%¡|_%| d1|j&¡|_&| d2|j'¡|_'| d3|j(¡|_(| d4|j)¡|_)| d5|j*¡|_*| d6|j+¡|_+|	|_,d7|_| -¡  | .|¡ qZt
jj/|
| dd8¡| dd8¡| dd8¡| dd9¡| dd9¡| dd9¡| dd9¡| dd9¡| d d9¡| d!d9¡| d"d9¡| d#d9¡| d$d9¡| d%d9¡| d&d9¡| d'd9¡| d(d9¡| d)d9¡| d*d9¡| d+d9¡| d,d9¡| d-d9¡| d.d9¡| d/d8¡| d0d8¡| d1d9¡| d2d9¡| d3d9¡| d4d9¡| d5d9¡| d6d9¡|	d7d:�" | .|¡ qZttj0d;dœd t1|ƒ› d<t1|ƒ› d=�t1|ƒt1|ƒd>œƒW S  t2k
�r¾ } z2t3d?|› �ƒ ttjddœdt|ƒdœƒ W Y ¢S d }~X Y nX d S )@NZpayslipsr¦   r4   Tu,   Payslip data Ã Â®â€¡Ã Â®Â²Ã Â¯Â�Ã Â®Â²Ã Â¯Ë†r„   ÚJanuaryÚFebruaryÚMarchÚAprilÚMayÚJuneÚJulyÚAugustÚ	SeptemberÚOctoberÚNovemberÚDecember)r   r?   re  ró   rï   r…   rð   rñ   rò   rH  é   r>  rA  r_  rª   )r_  rA  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±  rË  rS  r²  r³  rÌ  r   rÅ   rG  )"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Û   r±  rË  rS  r²  r³  rÌ  rA  r.   rC   z
 created, z updated)r.   r3   r8   r²  ÚupdatedzPayslip Error: )4r9   rO   r,   r.   rP   rÎ   r]   r   rS   rT   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É  rÊ  rÛ   r±  rË  rS  r²  r³  rÌ  rA  r•   rÐ   r’   rZ   r…  rx   ry   )r^   r_   Zpayslips_dataZcreated_listZupdated_listZMONTH_NAMESrñ  Z	month_valr±  Ú
month_nameZemployee_instancer  r}   rd   rd   re   rf   \  sô    
ý
        ü



þ































Ý%
û

ýzPayslipAPIView.post)Nr´  rd   rd   rd   re   r¶    s   
Xr¶  c                   @   s   e Zd Zdd„ ZdS )Ú ProductactivestatusupdateAPIViewc              
   C   sš   zPt jj|d�}|jdkr*d|_| ¡  nd|_| ¡  ttjddœd ddœƒW S  tk
r” } z&ttjddœd	d
|› �dœƒ W Y ¢S d }~X Y nX d S )Nrª   r   r?   rC   r4   zQuote accepted successfullyr„   r¦   Tr´   )	r   rS   rO   r.   r•   r,   r¶   r·   rP   )r^   r_   rE   Zvenr}   rd   rd   re   r¼   æ  s$    


ý

ýz$ProductactivestatusupdateAPIView.putN)rh   ri   rj   r¼   rd   rd   rd   re   rÜ  ä  s   rÜ  )ÚValidationError)Ú	Paginator)ÚIntegrityErrorrÑ  )rÒ  ÚPrefetchÚProtectedErrorr    )ÚFileResponser   )Ú
FormParserÚMultiPartParser)Ú
TokenError)	ÚDOC_TYPE_CHOICESÚSTATUS_ACTIVEÚSTATUS_INACTIVEÚClientÚClientDocumentÚClientServicer   ÚRenewalHistoryÚServicere  rH  é2   iˆ  rï   rë  c                   C   s   t jrt ¡ S t ¡ S )z=Today's date. Works whether settings.USE_TZ is True or False.)r   ÚUSE_TZr   Ú	localdater   r-  rd   rd   rd   re   Ú
today_date-  s    rñ  c                   C   s   t jrt ¡ S t ¡ S )zFCurrent date and time. Works whether settings.USE_TZ is True or False.)r   rï  r   r×  r   r“   rd   rd   rd   re   Ú	now_local2  s    rò  c                 K   s4   |ddœd | dœ}|r||d< |  |¡ t||d�S )NrC   r4   ro   r8   r-   )Úupdater,   )r9   r8   r5   Úextrar^  rd   rd   re   rC   7  s
    
rC   c                 C   s*   |ddœd| dœ}|r||d< t ||d�S )Nr¦   r4   Tr„   Úerrorsr-   r+   )r8   r5   rõ  r^  rd   rd   re   r¦   ?  s    r¦   c                 C   s(   | j r
tS tjj| jd�jddd� ¡ S )Nr=   rM   Tr  )r\   Ú
ADMIN_ROLEr   rS   r�   rE   r2  r¤  rn   rd   rd   re   Úget_roleF  s    r÷  c                 C   s0   |r
t fnt tf}t| jƒ|kr,tdtjƒS dS )zKReturns an error Response if this user may not use the API, otherwise None.z&You do not have permission to do this.N)rö  ÚEMPLOYEE_ROLEr÷  ra   r¦   r.   rU   )r_   Ú
admin_onlyÚallowedrd   rd   re   Ú
check_roleL  s    rû  c              	   C   s¼   zt t| j dd¡ƒdƒ}W n ttfk
r8   d}Y nX zt| j dt¡ƒ}W n ttfk
rl   t}Y nX tt |dƒtƒ}t	||ƒ}| 
|¡}|j|j||j| ¡ | ¡ dœ}|j|fS )z>?page=2&page_size=10  ->  (rows of that page, pagination info)Úpager   Ú	page_size)r  rü  rý  Ztotal_pagesÚhas_nextÚhas_previous)r•  rÎ   r¤   rO   rÒ  rÏ   Ú	PAGE_SIZEr“  ÚMAX_PAGE_SIZErÞ  Úget_pager  ÚnumberÚ	num_pagesrþ  rÿ  Úobject_list)r_   Úquerysetrü  r’  Ú	paginatorÚpage_objrZ  rd   rd   re   ÚpaginateT  s&    



úr	  c                 C   s.   t | dƒrdd„ | j ¡ D ƒS dd | j¡iS )z4Django ValidationError -> {"field": "first message"}Úmessage_dictc                 S   s6   i | ].\}}||r"|d  dkr"dn|r.|d  nd“qS )r   zThis field cannot be blank.zThis field is required.zInvalid valuerd   )r"  rq  ru  rd   rd   re   r  p  s   ÿ zerror_dict.<locals>.<dictcomp>Ú__all__z; )r)  r
  ri  r  Úmessages)Úexcrd   rd   re   Ú
error_dictm  s
    
ÿr  c                 C   s   t t|  ¡ ƒƒS rl   )r¡  Úiterr8  ©rõ  rd   rd   re   Úfirst_erroru  s    r  c                 C   s   | dkS )N)Tr   rØ   r×  ÚTruerØ  ÚYesrd   rÚ  rd   rd   re   Úto_booly  s    r  c                 C   s   | r|   d¡S dS )Nr  rÅ   rc  ©r  rd   rd   re   Úfmt_date}  s    r  c                 C   s   | rd| dd … › �S dS )Nz
XXXX XXXX éüÿÿÿrÅ   rd   ©ru  rd   rd   re   Úmask_aadhaar�  s    r  c                 C   s.   | r*dt t| ƒd dƒ › | dd … › �S dS )NÚXró   r   r  rÅ   )r•  r…  r  rd   rd   re   Úmask_account…  s    r  c                   @   s   e Zd ZdZefZdd„ ZdS )Ú	MeAPIViewzGGET /api/v1/me/  -> who owns this token + role (checked on the server).c              
   C   sz   |j }tjj|jd� ¡ }|d k	r8|jdkr8tdtjƒS t	|j|j
|j|j|j|rX|jnd |rd|jnd |rp|jnddœƒS )Nr=   r?   r@   )rE   rD   r1   r;   rF   rL   rM   rN   )ra   r   rS   r�   rE   r¤  r.   r¦   rU   rC   r1   r[   r;   r\   rL   rM   rN   )r^   r_   ra   rI   rd   rd   re   rO   Ž  s    øzMeAPIView.getNrC  rd   rd   rd   re   r  Š  s   r  c                   @   s   e Zd ZdZefZdd„ ZdS )ÚLogoutAPIViewzJPOST /api/v1/logout/  {"refresh": "..."}  -> blacklists the refresh token.c                 C   s:   zt |j d¡ƒ ¡  W n tk
r,   Y nX ttjd�S )NrG   r-   )r   r9   rO   Z	blacklistrå  r,   r.   ZHTTP_205_RESET_CONTENT)r^   r_   rd   rd   re   rf   £  s
    zLogoutAPIView.postN©rh   ri   rj   rD  r$   rp   rf   rd   rd   rd   re   r  Ÿ  s   r  c                 C   s$   | j | j| jt| dd ƒt| jƒdœS )NÚclients_count)rE   rD   r.   r  rÜ  )rE   rD   r.   r4  r  rÜ  )Úsrd   rd   re   Úservice_to_dict¬  s    
ûr!  c                   @   s@   e Zd ZdZefZddd„Zdd„ Zdd„ Zd	d
„ Z	dd„ Z
dS )ÚServiceAPIViewaÇ  
    GET    /api/v1/services/              list, 10 per page   (?page=&search=&status=)
    GET    /api/v1/services/?val=options  all services for dropdowns
    GET    /api/v1/services/?val=summary  counts for dashboard
    GET    /api/v1/services/<id>/         one service
    POST   /api/v1/services/              create   (admin)
    PUT    /api/v1/services/<id>/         update   (admin)
    DELETE /api/v1/services/<id>/         delete   (admin)
    Nc                 C   sh  t |ƒ}|r|S |d k	rfztjjtdƒd�j|d�}W n" tjk
rX   tdtj	ƒ Y S X t
t|ƒƒS |j dd¡}|dkr¤tj d¡ d	dd
¡}t
dd„ |D ƒƒS |dkrÜtj ¡ }tjjtd� ¡ }t
|||| dœƒS tjjtdƒd� d¡}	|j dd¡ ¡ }
|j d
d¡ ¡ }|
�r*|	j|
d�}	|dk�rD|	jt|ƒd�}	t||	ƒ\}}t
dd„ |D ƒ|d�S )NÚclient_services©r  rª   úService not foundrÄ   rÅ   ÚoptionsrD   rE   r.   c                 S   s(   g | ] }|d  |d |d t kdœ‘qS )rE   rD   r.   )rÍ  r  Úinactive)rè  rI  rd   rd   re   r  Ñ  s     z&ServiceAPIView.get.<locals>.<listcomp>rÊ  r-   )r  Úactiver'  rþ  rÇ   ©rØ   rÆ   c                 S   s   g | ]}t |ƒ‘qS rd   )r!  ©r"  r   rd   rd   re   r  à  s     ©Ú
pagination)rû  rí  rS   r9  rÒ  rO   rT   r¦   r.   r‘   rC   r!  r¤   rÍ   r8  r  r�   rç  rÌ   rÎ   r	  )r^   r_   rE   Údeniedr   rÄ   rF  r  r(  Úservicesrþ  rÑ   rZ  rd   rd   re   rO   Â  s4    

zServiceAPIView.getc              
   C   sB  |j }d|kr|d |_d|kr*|d |_z|jp4d ¡ |_| ¡  W n> tk
r„ } z t|ƒ}tt|ƒ|d� W Y ¢S d }~X Y nX t	j
j|jd�j|jd� ¡ r¸d}t|d|id�S |rÄ|j|_|j|_z| ¡  W n" tk
� rú   tdtjƒ Y S X t	j
jtdƒd	�j|jd�}tt|ƒ|�r*d
nd|�r8tjntjd�S )NrD   r.   rÅ   r  )r  ré  z(A service with this name already exists.r#  r$  zService created successfullyzService updated successfully©r8   r5   )r9   rD   r.   rÌ   Úclean_fieldsrÝ  r  r¦   r  rí  rS   r�   r3  rê  r�   ra   rf  r  r•   rß  r›   r9  rÒ  rO   rC   r!  r¶   rZ   )r^   r_   rð  Úcreatingr9   r}   rõ  r³  rd   rd   re   Ú_saveâ  s6    

&ýzServiceAPIView._savec                 C   s&   t |dd�}|r|S | j|tƒ dd�S )NT©rù  ©r1  )rû  r2  rí  ©r^   r_   r-  rd   rd   re   rf     s    zServiceAPIView.postc                 C   sZ   t |dd�}|r|S ztjj|d�}W n" tjk
rH   tdtjƒ Y S X | j||dd�S )NTr3  rª   r%  Fr4  )	rû  rí  rS   rO   rT   r¦   r.   r‘   r2  )r^   r_   rE   r-  rð  rd   rd   re   r¼   	  s    zServiceAPIView.putc                 C   sv   t |dd�}|r|S ztjj|d� ¡  W n@ tjk
rL   tdtjƒ Y S  t	k
rj   tdtj
ƒ Y S X tdd�S )NTr3  rª   r%  zOThis service is used by clients and can't be deleted. Mark it Inactive instead.zService deleted successfully©r8   )rû  rí  rS   rO   r¨   rT   r¦   r.   r‘   rá  r›   rC   ©r^   r_   rE   r-  rd   rd   re   r¨     s    zServiceAPIView.delete)N©rh   ri   rj   rD  r$   rp   rO   r2  rf   r¼   r¨   rd   rd   rd   re   r"  ¶  s   	
 !
r"  )rD   Úbusiness_namer¾   râ   r¿   rL   r;   rÜ   ÚaadhaarÚgstinÚ	bank_nameÚaccount_holderÚaccount_numberÚifscr.   Únotesc              	   C   s,   | j | j|  ¡ | j| j| j| jt| jƒdœS )N)rE   Údoc_typeZdoc_type_labelÚoriginal_nameÚcontent_typer’  ÚremarksZuploaded_at)	rE   rA  Úget_doc_type_displayrB  rC  r’  rD  r  rÜ  r  rd   rd   re   Údocument_to_dict(  s    ørF  c                   C   s   t j tdtj d¡d�d¡S )zEClients with services + documents loaded in 2 extra queries (no N+1).r#  rð  )r  Ú	documents)ré  rS   r  rà  rë  r�  rd   rd   rd   re   Úclient_queryset5  s    þrH  c                 C   sÎ   t | j ¡ dd„ d�}| j| j| j| j| j| j| j	| j
| j| j| j|rL| jnt| jƒ| j| j|rf| jnt| jƒ| jdd„ |D ƒ| jt| jƒt| j ¡ ƒ|r®dd„ | j ¡ D ƒng | j| jt| jƒt| jƒdœS )zXList + exports use masked Aadhaar / account number. full=True is only for the edit form.c                 S   s   | j j ¡ S rl   ©rð  rD   rj  )Úcsrd   rd   re   rˆ  ?  r‰  z client_to_dict.<locals>.<lambda>rŠ  c                 S   s6   g | ].}|j |jj|jr"|j ¡ nd t|jƒdœ‘qS )N)rE   rD   Úrenewal_dateÚrenewal_label)Ú
service_idrð  rD   rK  r¢  r  ©r"  rJ  rd   rd   re   r  Q  s   ûüz"client_to_dict.<locals>.<listcomp>c                 S   s   g | ]}t |ƒ‘qS rd   )rF  r  rd   rd   re   r  ]  s     )rE   râ  rD   r9  r¾   râ   r¿   rL   r;   rÜ   r;  r:  r<  r=  r>  r?  r.  Úfile_deliveredÚfile_delivered_onZdocuments_countrG  r.   r@  rÜ  Ú
updated_at)r8  r#  rQ  rE   râ  rD   r9  r¾   râ   r¿   rL   r;   rÜ   r;  r:  r  r<  r=  r>  r  r?  rO  r  rP  r…  rG  r.   r@  rÜ  rQ  )rä  ÚfullÚlinksrd   rd   re   Úclient_to_dict=  s:    ù	ßrT  c                 C   sø   t ƒ  d¡}| j}| dd¡ ¡ }| dd¡ ¡ }| dd¡ ¡ }| dd¡ ¡ }|dkrj|jt|ƒd�}|d	kr‚|j|d
kd�}| ¡ rš|jt|ƒd�}|rô| t|d�t|d�B t|d�B t|d�B t|d�B t|d�B t|d�B t|d�B ¡}|S )Nú-idrþ  rÅ   r.   rð  rO  r)  r-   )rG  rØ   rØ   )rO  )Zclient_services__service_idrÇ   )Zbusiness_name__icontainsrÿ  rÉ   rÈ   )Zpan__icontains)Zgstin__icontains)Zcity__icontains)	rH  rÍ   r¤   rO   rÌ   r�   rÎ   rW  r    )r_   r  rñ  rþ  rÑ   rð  Ú	deliveredrd   rd   re   Úfiltered_clientse  s6    ÿÿÿþþÿrW  c              
   C   sH  | dkrg S t | tƒs"tddiƒ‚g tƒ  }}| D �]}t |tƒsNtddiƒ‚zt| d¡ƒ}W n$ ttfk
r„   tddiƒ‚Y nX ||krštddiƒ‚| 	|¡ d}| d¡}|dk�r4z t
 t|ƒdd	… d
¡ ¡ }W n  tk
rü   tddiƒ‚Y nX tdddƒ|  k�r&tdddƒk�s4n tddiƒ‚| ||f¡ q2|S )zX[{"service_id": 3, "renewal_date": "2026-10-10"}, ...]  ->  [(3, date(2026,10,10)), ...]rÅ  r.  zServices must be a list.zInvalid service selected.rM  z#The same service is selected twice.NrK  rH  r
  z"Renewal date must be a valid date.éÐ  r   é4  r>  é   zRenewal date is out of range.)r‹  r  rÝ  ÚsetÚdictrÎ   rO   rÒ  rÏ   Úaddr   r+  r]   r   rÐ   )rÎ  rF  ÚseenrO  rM  ÚrenewalZraw_daterd   rd   re   Úparse_service_rows|  s4    





 *r`  c                   @   s@   e Zd ZdZefZddd„Zdd„ Zdd„ Zd	d
„ Z	dd„ Z
dS )ÚClientAPIViewaz  
    GET    /api/v1/clients/              list, 10 per page  (?page=&search=&status=1|2&service=&file_delivered=0|1)
    GET    /api/v1/clients/?val=summary  dashboard numbers + latest clients
    GET    /api/v1/clients/?val=excel    download Excel  (same filters)
    GET    /api/v1/clients/?val=pdf      download PDF    (same filters)
    GET    /api/v1/clients/<id>/         full details
    POST   /api/v1/clients/              create   (admin + employee)
    PUT    /api/v1/clients/<id>/         update   (admin + employee)  - also used to toggle file_delivered
    DELETE /api/v1/clients/<id>/         delete   (admin only)
    Nc                 C   sž  t |ƒ}|r|S |d k	r^ztƒ j|d�}W n" tjk
rL   tdtjƒ Y S X tt	|dd�ƒS |j
 dd¡}|dkrÚtj ¡ }tjjtd� ¡ }tjjtd	d
� ¡ }tƒ  d¡d d… }	t|||| |dd„ |	D ƒdœƒS |dk�rvtt|ƒd t… ƒ}
z0|dk�rt|
ƒ}d}d}nt|
ƒ}d\}}W n" tk
�rJ   tdtjƒ Y S X t||d�}dtƒ d›d|› d�|d< |S t|t|ƒƒ\}}tdd„ |D ƒ|d�S )Nrª   r  T©rR  rÄ   rÅ   rÊ  r-   F)r.   rO  rU  rï   c                 S   s   g | ]}t |ƒ‘qS rd   ©rT  r   rd   rd   re   r  ½  s     z%ClientAPIView.get.<locals>.<listcomp>)r  r(  r'  Zfile_pendingr¥   )ÚexcelÚpdfrd  zAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetZxlsx)úapplication/pdfre  z6Install on the server:  pip install openpyxl reportlab)rC  zattachment; filename="clients-r
  rÆ  ú"zContent-Dispositionc                 S   s   g | ]}t |ƒ‘qS rd   rc  r   rd   rd   re   r  Ñ  s     r+  )rû  rH  rO   ré  rT   r¦   r.   r‘   rC   rT  r¤   rS   r  r�   rç  rÍ   r  rW  ÚEXPORT_LIMITÚbuild_clients_excelÚbuild_clients_pdfÚImportErrorZHTTP_501_NOT_IMPLEMENTEDr   rñ  r	  )r^   r_   rE   r-  rä  rÄ   r  r(  rÇ  r¥   r  ÚcontentrC  Úextr6   rF  rZ  rd   rd   re   rO   ¨  sL    
   þ

zClientAPIView.getc              
      s¦  |j }tD ],}||kr
t|||| d k	r0|| ndƒ q
d|krnt|d pLdƒ ¡  ¡ }|rd||_n
|rnd |_d|kr¤t|d ƒ}|r”|js”t	ƒ |_
|sžd |_
||_z&| ¡  d|krÄt| d¡ƒnd }W n@ tk
�r
 }	 z t|	ƒ}
tt|
ƒ|
d� W Y ¢S d }	~	X Y nX i }
|j�s d|
d< |j�s0d|
d	< |j�rvtjj|jd
�j|jd� ¡ }|�rvd|j› d|j› d�|
d< dD ]^\}}t||ƒ}|�rztjjf ||iŽj|jd� ¡ }|�rz|› d|j› d|j› d�|
|< �qzi ‰|d k	�rhdd„ tjjdd„ |D ƒd�D ƒ‰tˆƒt|ƒk�r&d|
d< nB|�r2tƒ nt|jjddd�ƒ‰ t ‡ ‡fdd„|D ƒƒ�rhd|
d< |
�r~tt|
ƒ|
d�S zÆt! "¡ �´ |�r˜|j#|_$|j#|_%| &¡  |d k	�r8dd„ |j '¡ D ƒ}|D ]T\}}| (|d ¡}|d k�rüt)jj*|||d � n |j+|k�rÊ||_+|j&d!gd"� �qÊ| ,¡ D ]}| -¡  �q(W 5 Q R X W n" t.k
�rf   td#t/j0ƒ Y S X t1ƒ j|jd�}t2t3|dd$�|�rŽd%nd&|�rœt/j4nt/j5d'�S )(NrÅ   râ  rO  r.  r  zClient name is required.rD   zMobile number is required.rL   )râ  ré  z
Client ID z is already used by rÆ  ))rÜ   ÚPAN)r:  ÚAadhaarz already belongs to client z (rx  c                 S   s   i | ]}|j |“qS rd   rª   r*  rd   rd   re   r    s      z'ClientAPIView._save.<locals>.<dictcomp>c                 S   s   g | ]\}}|‘qS rd   rd   ©r"  Úsidrþ  rd   rd   re   r    s     z'ClientAPIView._save.<locals>.<listcomp>r  z+One or more selected services do not exist.rM  Tr  c                 3   s(   | ] \}}ˆ| j tko|ˆ kV  qd S rl   )r.   rè  rp  ©ÚalreadyÚfoundrd   re   rŒ  
  s     z&ClientAPIView._save.<locals>.<genexpr>z*Inactive services can't be newly assigned.c                 S   s   i | ]}|j |“qS rd   ©rM  rN  rd   rd   re   r    s      )rï  rM  rK  rK  ©Úupdate_fieldszMAnother client already uses one of these details (Client ID / PAN / Aadhaar).rb  zClient created successfullyzClient updated successfullyr/  )6r9   ÚCLIENT_TEXT_FIELDSÚsetattrr]   rÌ   rÊ  râ  r  rO  rñ  rP  Úvalidate_fieldsr`  rO   rÝ  r  r¦   r  rD   rL   ré  rS   r�   r3  rê  r¤  r4  rí  r…  r[  r#  r2  ry  rÑ  r}  ra   rf  r  r•   rQ  Úpoprë  r’   rK  r8  r¨   rß  r.   r›   rH  rC   rT  r¶   rZ   )r^   r_   rï  r1  r9   rÔ  ÚtypedrV  Zservice_rowsr}   rõ  Úclashr  rÍ  Úotherr  rM  r_  ÚlinkÚleftoverrd   rr  re   r2  Ô  s’    "
&
 "
"
 



ýzClientAPIView._savec                 C   s"   t |ƒ}|r|S | j|tƒ dd�S )NTr4  )rû  r2  ré  r5  rd   rd   re   rf   ,  s    zClientAPIView.postc                 C   sV   t |ƒ}|r|S ztjj|d�}W n" tjk
rD   tdtjƒ Y S X | j||dd�S )Nrª   r  Fr4  )	rû  ré  rS   rO   rT   r¦   r.   r‘   r2  )r^   r_   rE   r-  rï  rd   rd   re   r¼   2  s    zClientAPIView.putc                 C   sX   t |dd�}|r|S ztjj|d� ¡  W n" tjk
rL   tdtjƒ Y S X t	dd�S )NTr3  rª   r  zClient deleted successfullyr6  )
rû  ré  rS   rO   r¨   rT   r¦   r.   r‘   rC   r7  rd   rd   re   r¨   <  s    zClientAPIView.delete)Nr8  rd   rd   rd   re   ra  ›  s   

,X
ra  c                   @   s   e Zd ZdZefZdd„ ZdS )ÚRenewalAPIViewzò
    GET /api/v1/renewals/?when=tomorrow|today|week|overdue&search=&page=
    Default = tomorrow: clients whose renewal date is one day away (shown every day).
    Only ACTIVE clients are listed.  `counts` gives the number for every tab.
    c                    s4  t |ƒ}|r|S tƒ ‰tˆtdd� d�tˆd�tˆˆtdd� d�tˆd�dœ}|j dd	¡}||krld	}tj d
d¡j	dt
d�‰ ˆ  	|| ¡ dd¡}|j dd¡ ¡ }|rè| 	t|d�t|d�B t|d�B t|d�B t|d�B ¡}t||ƒ\}}‡fdd„|D ƒ}	‡ fdd„| ¡ D ƒ}
t|	||
|ˆ ¡ d�S )Nr   rC  )rK  rð   )Zrenewal_date__gtZrenewal_date__lte)Zrenewal_date__lt)Útomorrowr-  ÚweekZoverdueÚwhenr‚  rï  rð  F)Zrenewal_date__isnullZclient__statusrK  Zclient__namerþ  rÅ   )Zclient__name__icontains)Zclient__client_code__icontains)Zclient__phone__icontains)Z client__business_name__icontains)Zservice__name__icontainsc                    sR   g | ]J}|j |j|jj|jj|jj|jj|jj|j 	¡ t
|jƒ|jˆ  jd œ
‘qS ))
rE   r  râ  r=  r9  rL   Úservice_namerK  rL  Z	days_left)rE   r  rï  râ  rD   r9  rL   rð  rK  r¢  r  rD  rN  )r-  rd   re   r  k  s   ö
öz&RenewalAPIView.get.<locals>.<listcomp>c                    s    i | ]\}}|ˆ   |¡ ¡ “qS rd   )r�   r  )r"  rD   rK  )Úbaserd   re   r  w  s      z&RenewalAPIView.get.<locals>.<dictcomp>)r,  r5  r„  r-  )rû  rñ  r    r   r¤   rO   rë  rS   r�  r�   rç  rÍ   rÌ   r	  ri  rC   r¢  )r^   r_   r-  Útabsr„  rF  rþ  Z	page_rowsrZ  r9   r5  rd   )r†  r-  re   rO   P  s>    üÿÿþÿ
õzRenewalAPIView.getNrC  rd   rd   rd   re   r�  H  s   r�  c              	   C   s>   zt  t| ƒdd… d¡ ¡ W S  ttfk
r8   Y dS X dS )z9'2026-10-10' -> date, or None when it is not a real date.NrH  r
  )r   r+  r]   r   rÒ  rÏ   rÚ  rd   rd   re   Ú	read_date{  s    rˆ  c                   @   s   e Zd ZdZefZdd„ ZdS )ÚRenewalRenewAPIViewaé  
    POST /api/v1/renewals/<client_service id>/renew/     ("Mark renewed" button)
         { "new_date": "2027-10-10",            next renewal date (required)
           "renewed_on": "2026-10-09",          day it was renewed (default today, not in the future)
           "old_date": "2026-10-10",            the date the screen showed (stops double click / two staff)
           "remarks": "paid by UPI" }
    Saves a RenewalHistory row and moves the service to the new renewal date.
    c              
   C   sb  t |ƒ}|r|S |j}tƒ }i }|}| d¡dkr|t| d¡ƒ}|d krRd|d< n*||krdd|d< n|tdddƒk r|d|d< t| d¡ƒ}|d krœd	|d< nDtdddƒ|  krÀtd
ddƒksÌn d|d< n|rà||kràd|d< t| d¡pîdƒ ¡ }	t|	ƒdk�rd|d< |�r"t	t
|ƒ|d�S t ¡ �� ztj ¡  dd¡j|d�}
W n0 tjk
�r|   t	dtjƒ Y W  5 Q R £ S X |
jjtk�r t	dƒW  5 Q R £ S t| d¡�p°dƒd d… }|
j�rÎ|
j ¡ nd}|�rú||k�rút	dtjƒW  5 Q R £ S tjj|
j|
j|
j|||	|jd� ||
_|
jdgd� W 5 Q R X t|
j|
j |
jj!| ¡ t"|ƒdœd d!�S )"NÚ
renewed_onrÅ  z"Renewed date must be a valid date.z$Renewed date can't be in the future.rX  r   zRenewed date is out of range.Únew_datezNext renewal date is required.rY  r>  rZ  z"Next renewal date is out of range.z1Next renewal date must be after the renewed date.rD  rÅ   éÿ   z#Remarks can be 255 letters at most.r  rï  rð  rª   zRenewal not foundzThis client is inactive.Úold_daterH  z:This renewal was already updated. Please refresh the list.)rï  rð  r�  r‹  rŠ  rD  rf  rK  rv  )rE   r  r…  rK  rL  zRenewal saved successfullyr6  )#rû  r9   rñ  rO   rˆ  r   r]   rÌ   r…  r¦   r  rÑ  r}  rë  rS   Úselect_for_updater�  rT   r.   r‘   rï  rç  rK  r¢  r›   rì  r’   rð  ra   r•   rC   rE   r  rD   r  )r^   r_   rE   r-  r9   r-  rõ  rŠ  r‹  rD  r  ZshownÚcurrentrd   rd   re   rf   Ž  st    


&
     þ   þýzRenewalRenewAPIView.postNr  rd   rd   rd   re   r‰  ƒ  s   r‰  c                   @   s   e Zd ZdZefZdd„ ZdS )ÚClientRenewalHistoryAPIViewz[GET /api/v1/clients/<client_id>/renewal-history/?page=&service=   newest first, 10 per pagec           	      C   s–   t |ƒ}|r|S tjj|d� ¡ s.tdtjƒS tjj|d� 	dd¡}|j
 dd¡ ¡ }| ¡ rn|jt|ƒd�}t||ƒ\}}dd	„ |D ƒ}t||d
�S )Nrª   r  r  rð  rf  rÅ   ru  c                 S   sT   g | ]L}|j |j|jjt|jƒt|jƒt|jƒ|j|j	rH|j	j
pJ|j	jnd dœ‘qS )rÅ   )rE   rM  r…  r�  r‹  rŠ  rD  Zdone_by)rE   rM  rð  rD   r  r�  r‹  rŠ  rD  rf  r[   r1   r  rd   rd   re   r  Ú  s   	øøz3ClientRenewalHistoryAPIView.get.<locals>.<listcomp>r+  )rû  ré  rS   r�   r�   r¦   r.   r‘   rì  r�  r¤   rO   rÌ   rW  rÎ   r	  rC   )	r^   r_   r  r-  Úhistoryrð  rF  rZ  r9   rd   rd   re   rO   Í  s    	÷
zClientRenewalHistoryAPIView.getNrC  rd   rd   rd   re   r�  É  s   r�  )s   %PDF-re  rf  )s   ÿØÿÚjpgz
image/jpeg)s   ‰PNG

Úpngz	image/pngc                 C   s>   |   d¡}|  d¡ tD ] \}}}| |¡r||f  S qdS )zPLooks at the real file bytes (not the file name) -> (ext, content_type) or None.rñ   r   N)r‘  rŽ  ÚUPLOAD_SIGNATURESrV  )rú  ÚheadÚ	signaturerm  rC  rd   rd   re   Úsniff_uploadï  s    


r—  c                   @   s6   e Zd ZdZefZeefZdd„ Z	dd„ Z
dd„ ZdS )	ÚClientDocumentAPIViewa‡  
    POST   /api/v1/clients/<client_id>/documents/   multipart: file, doc_type, remarks
    GET    /api/v1/client-documents/<id>/           the file (login needed; ?download=1 to save)
    DELETE /api/v1/client-documents/<id>/           removes the record AND the file from the media folder
    Saved in MEDIA_ROOT/client_documents/<client id>/  - never served as a public /media/ link.
    c              
   C   sž  t |ƒ}|r|S ztjj|d�}W n" tjk
rD   tdtjƒ Y S X |j d¡}|j	 d¡p`d 
¡ }|j	 d¡ptd 
¡ d d… }|s–td	dd	id
�S |ttƒkr²tdddid
�S |jdkrÌtdddid
�S |jtd d krúdt› d�}t|d|id
�S t|ƒ}	|	�sd}t|d|id
�S |j ¡ tk�r<tdt› d�ƒS |	\}
}tj |j¡d d… }d|
› �|_t||||||j||jd�}| ¡  tt|ƒdtjd�S )Nrª   r  ÚfilerA  r~  rD  rÅ   rŒ  zPlease choose a file.r  zInvalid document type.r   zThe file is empty.i   z#File is too large. Maximum size is z MB.z'Only PDF, JPG or PNG files are allowed.zA client can have at most z documents.zupload.)rï  rA  r™  rB  rC  r’  rD  rf  zDocument uploaded successfullyr/  )rû  ré  rS   rO   rT   r¦   r.   r‘   ri  r9   rÌ   r\  ræ  r’  ÚMAX_UPLOAD_MBr—  rG  r  ÚMAX_DOCS_PER_CLIENTrY  rX  ÚbasenamerD   rê  ra   r•   rC   rF  r¶   )r^   r_   r  r-  rï  ÚuploadrA  rD  r³  Úkindrm  rC  rB  Údocrd   rd   re   rf      sP    
      þzClientDocumentAPIView.postc              
   C   sœ   t |ƒ}|r|S ztjj|d�}|j d¡}W n( tjttfk
rV   t	dt
jƒ Y S X t||jpdd|j d¡dk|jp‚d|j› �d�}d	|d
< d|d< |S )Nrª   ÚrbúFile not foundzapplication/octet-streamZdownloadrØ   z	document-)rC  Úas_attachmentÚfilenameÚnosniffzX-Content-Type-Optionszprivate, no-storezCache-Control)rû  rê  rS   rO   r™  rŒ  rT   ÚFileNotFoundErrorrÏ   r¦   r.   r‘   râ  rC  r¤   rB  rE   )r^   r_   rE   r-  rŸ  Úhandler6   rd   rd   re   rO   +   s"     ýzClientDocumentAPIView.getc                 C   sT   t |ƒ}|r|S ztjj|d� ¡  W n" tjk
rH   tdtjƒ Y S X t	dd�S )Nrª   r¡  zDocument deleted successfullyr6  )
rû  rê  rS   rO   r¨   rT   r¦   r.   r‘   rC   r7  rd   rd   re   r¨   =   s    zClientDocumentAPIView.deleteN)rh   ri   rj   rD  r$   rp   rä  rã  Zparser_classesrf   rO   r¨   rd   rd   rd   re   r˜  ù  s   (r˜  c                 C   sX   g }t | j ¡ dd„ d�D ]2}| |jrB|jj› dt|jƒ› d�n|jj¡ qd |¡S )Nc                 S   s   | j j ¡ S rl   rI  r‡  rd   rd   re   rˆ  K   r‰  zservices_text.<locals>.<lambda>rŠ  z
 (renewal r–  ú, )	r8  r#  rQ  rÐ   rK  rð  rD   r  r  )rä  r*  rJ  rd   rd   re   Úservices_textI   s    0r¨  c                 C   s(  ddl m} ddlm}m}m} ddlm} |ƒ }|j}d|_	dddd	d
dddddddddddddddddg}| 
dd„ |D ƒ¡ t|dƒD ]T\}	\}
}||j||	ƒ _|jd|	d�}|d d!d"�|_|d#d$d%�|_|d&d d'�|_qŒd(|jd _| D ]¨}| 
|j|j|j|j|j|j|j|j|jt|jƒ|jt |ƒ|j!|j"t#|j$ƒ|j%|j&t'k�rTd)nd*|j(�rbd+nd,t)|j*ƒ|j+d- ,t-d.d/„ |j. /¡ D ƒƒ¡t)|j0ƒg¡ qò|j1d0d1�D ] }|D ]}|d2d d'�|_�q°�q¨d3D ].}t2d0|j3d ƒD ]}d4|j||d�_4�qâ�qÎd5|_5|j6|j7_8t9 :¡ }| ;|¡ | <¡ S )6Nr   )ÚWorkbook)Ú	AlignmentÚFontÚPatternFill)Úget_column_letterZClients)ú	Client IDé   )zClient Nameé   )zShop / Business Nameé   )zShop Addressé&   )ZCityé   )ZPincoderH  )ZMobileé   )ÚEmailr±  )rn  r¯  )ro  é   )ZGSTINrì  )zServices (renewal dates)é(   )z	Bank Nameé   )zAccount Holderé   )zAccount No.rì  )ZIFSCr¯  )ÚStatusrH  )zFile Deliveredr´  )zDelivered Onr¯  )ZNotesé"   )Z	Documentsr±  )zAdded Onr>  c                 S   s   g | ]\}}|‘qS rd   rd   )r"  r›  rþ  rd   rd   re   r  ^   s     z'build_clients_excel.<locals>.<listcomp>r   )rO  ÚcolumnTZFFFFFF)ÚboldÚcolorZsolidZ6B0F14)ZfgColorÚcenter)ZverticalÚ	wrap_texté   ÚActiveÚInactiveZ	Deliveredr»  r§  c                 S   s   h | ]}|  ¡ ’qS rd   )rE  r  rd   rd   re   r$  n   s     z&build_clients_excel.<locals>.<setcomp>r?   )Zmin_rowÚtop)r…   rð   rH  rP  ú@ZC2)=Zopenpyxlr©  Zopenpyxl.stylesrª  r«  r¬  Zopenpyxl.utilsr­  r(  rï  rÐ   rR  Zcolumn_dimensionsÚwidthÚcellZfontÚfillÚ	alignmentZrow_dimensionsÚheightrâ  rD   r9  r¾   râ   r¿   rL   r;   rÜ   r  r:  r;  r¨  r<  r=  r  r>  r?  r.   rç  rO  r  rP  r@  r  r8  rG  rQ  rÜ  Ú	iter_rowsrh  Zmax_rowÚnumber_formatZfreeze_panesÚ
dimensionsZauto_filterÚrefr�  r�  r•   Úgetvalue)r  r©  rª  r«  r¬  r­  ÚwbÚwsrQ  r#  rþ  rÆ  rÇ  rä  rO  ÚcolrJ  Úbufferrd   rd   re   ri  P   s’                      ü                ú

ri  c                    s   ddl m‰ ddlm‰ ddlm‰ m‰ ddlm}m	} ddl
m‰ ddlm‰m}m}m}m} |dd	d
dd�}|d|dd�}|d|ˆjd�‰|ƒ }	|f‡‡fdd„	‰‡fdd„}
‡‡fdd„dD ƒg}| D �]"}dd„ t|j ¡ dd„ d�D ƒ}| ˆ|j|ƒˆdˆ|jƒ› dˆ|jƒ› �|ƒ|
|j|jƒ|
|j�o@d|j› �|j�oVd t|jƒ› �|j�ohd!|j› �ƒ|
|Ž |
|j d" !d#d$„ |j"|j#fD ƒ¡ƒ|
|j$|j%|j&�o²d%t'|j&ƒ› �|j(�oÄd&|j(› �ƒ|
|j)t*k�rØd'nd(|j+�ræd)nd*ƒg¡ qÌ‡ ‡‡‡fd+d,„}t, -¡ }||ˆˆ ƒd-ˆ d-ˆ d-ˆ d.ˆ d/d0d1�}ˆˆ ƒd d2ˆ  ‰d3d4d5d4d6d6d5d3g}||‡fd7d„|D ƒd8d9�}| .|d:d;d<ˆ /d=¡fd>d?d@ˆjˆ /dA¡gfdBd;d@dCˆ /dD¡fdEdFdGgƒ¡ ˆdH|	dI ƒˆdJt0ƒ dK›dLt1| ƒ› dM�|	dN ƒ|d8dOˆ ƒ|g}|j2|||dP� | 3¡ S )QNr   )Úescape)Úcolors)ÚA4Ú	landscape)ÚParagraphStyleÚgetSampleStyleSheet)rº   )Ú	ParagraphÚSimpleDocTemplateÚSpacerÚTableÚ
TableStylerÇ  Ú	Helveticarð   rò   )ÚfontNameZfontSizeZleadingr½  zHelvetica-Bold)Úparentrà  r•  )rá  Z	textColorc                    s   ˆ ˆt | pdƒƒ dd¡|ƒS )NrÅ   Ú
z<br/>)r]   r6  )r[  Ústyle)rÚ  rÔ  rd   re   rQ  Œ   s    zbuild_clients_pdf.<locals>.Pc                     s   ˆ d  dd„ | D ƒ¡ƒS )Nrâ  c                 s   s   | ]}|r|V  qd S rl   rd   )r"  Úlrd   rd   re   rŒ  �   s      z3build_clients_pdf.<locals>.stack.<locals>.<genexpr>)r  )Úlines)rQ  rd   re   Ústack�   s    z build_clients_pdf.<locals>.stackc                    s   g | ]}ˆ |ˆƒ‘qS rd   rd   r  )rQ  r•  rd   re   r  ’   s     z%build_clients_pdf.<locals>.<listcomp>)r®  zClient / BusinessZContactzPAN / Aadhaar / GSTINZServicesÚAddressZBankrº  c                 S   s0   g | ](}|j j› |jr&d t|jƒ› �nd ‘qS )z - rÅ   )rð  rD   rK  r  rN  rd   rd   re   r  ”   s   ÿc                 S   s   | j j ¡ S rl   rI  r‡  rd   rd   re   rˆ  –   r‰  z#build_clients_pdf.<locals>.<lambda>rŠ  z<b>z	</b><br/>zPAN: z	Aadhaar: zGST: rd  c                 s   s   | ]}|r|V  qd S rl   rd   r(  rd   rd   re   rŒ  ž   s      z$build_clients_pdf.<locals>.<genexpr>zA/c: zIFSC: rÂ  rÃ  zFile: DeliveredzFile: Pendingc                    sl   |   ¡  |  dd¡ |  ˆj¡ |  dˆ dˆ d¡ |  ˆˆ ƒd dˆ  dˆ d|j› �¡ |  ¡  d S )Nrß  rð   r>  rñ   zManju Associates - Confidentialr   zPage )Z	saveStateZsetFontZsetFillColorZgreyZ
drawStringZdrawRightStringrü  ZrestoreState)ZcanvasrŸ  )rÖ  rÕ  r×  rº   rd   re   Úfooter£   s    *z!build_clients_pdf.<locals>.footerr>  r´  zClient ListzManju Associates)ZpagesizeZ
leftMarginZrightMarginZ	topMarginZbottomMarginrï  ZauthorrÁ  gÃõ(\�Âµ?g333333Ã?gìQ¸…ëÁ?g      À?c                    s   g | ]}ˆ | ‘qS rd   rd   rI  )rÆ  rd   re   r  °   s     r   )Z	colWidthsZ
repeatRowsZ
BACKGROUND©r   r   )éÿÿÿÿr   z#6B0F14ZROWBACKGROUNDS)r   r   ©rê  rê  z#FBF1DEZGRIDg      Ð?z#D9C9A3)ZVALIGNré  rë  ZTOP)Z
TOPPADDINGré  rë  re  )ZBOTTOMPADDINGré  rë  re  zManju Associates - Client ListZTitlezGenerated on z%d-%m-%Y %H:%Mz | z
 client(s)ZNormalr…   )ZonFirstPageZonLaterPages)4Zxml.sax.saxutilsrÔ  Zreportlab.librÕ  Zreportlab.lib.pagesizesrÖ  r×  Zreportlab.lib.stylesrØ  rÙ  Zreportlab.lib.unitsrº   Zreportlab.platypusrÚ  rÛ  rÜ  rÝ  rÞ  Úwhiter8  r#  rQ  rÐ   râ  rD   r9  rL   r;   rÜ   r:  r  r;  r¾   r  râ   r¿   r<  r=  r>  r  r?  r.   rç  rO  r�  r�  ÚsetStyleZHexColorrò  r…  ÚbuildrÏ  )r  rØ  rÙ  rÛ  rÜ  rÝ  rÞ  rÇ  r½  Ústylesræ  r9   rä  Zservice_linesrè  rÓ  rŸ  ZratiosÚtableZstoryrd   )	rÖ  rQ  rÚ  rÕ  rÔ  r•  r×  rº   rÆ  re   rj  ~   sf    
þ
 >"4$ø" ÿ û"ürj  )F)N)F)F)F)þÚdjango.confr   Zdjango.shortcutsr   Úmodelsr   r   r   r   r	   r
   r   r   r   r   r   r   Údjango.core.exceptionsr   Zrest_framework.exceptionsr   Údjango.contrib.authr   r   Zrest_framework_simplejwt.tokensr   Údjango.contrib.auth.hashersr   Údjango.contrib.auth.modelsr   Údjango.utilsr   Zdjtzr   r   r   Zcv2r[  rY  Únumpyr–  ÚsysrY  r�  Údjango.httpr   Úbase64ÚPILr   r   r   Údjango.db.modelsr    Zrest_framework.genericsr!   r"   Úserializersr#   Zrest_framework.permissionsr$   r%   rR  Údjango.core.mailr&   Zschool.settingsr'   ZpdfkitrQ   r–   r(   Údjango.utils.cryptor)   r*   Zrest_framework.responser,   Úrest_frameworkr.   Zrest_framework.viewsr/   r0   rk   r~   r   r€   r�   rš   r�   r©   r½   rí   r  r	  rE  rJ  rt  ru  r´  r,  r€  r‚  ÚLockr�  rƒ  rˆ  r^  rZ  r   rµ  r¸  rÉ  ÚdecimalrÀ  rÁ  rË  rÐ  rÕ  rÖ  rÛ  r   rè  r.  r/  r	  r
  r  r  r  r  r  r$  r3  r8  r+  r2  r5  r7  r9  r:  r|  r”  r˜  r™  r¨  r«  r¬  r´  rµ  r¾  rÃ  rÍ  rÏ  Ú	django.dbrÑ  rÒ  rÓ  rÔ  rÕ  rÛ  rÙ  rÞ  rà  rå  rí  rü  rý  r  r  r  r)  r*  r;  r@  ÚloggingÚ	getLoggerrh   rU  rX  r`  ra  re  rl  r‚  r†  r‡  rˆ  rŸ  r§  r…  r©  r¶  rÜ  rÝ  Údjango.core.paginatorrÞ  rß  rà  rá  râ  Zrest_framework.parsersrã  rä  Z#rest_framework_simplejwt.exceptionsrå  ræ  rç  rè  ré  rê  rë  rì  rí  rö  rø  r   r  rh  rš  r›  rñ  rò  rZ   rC   rP   r¦   r÷  rû  r	  r  r  r  r  r  r  r  r  r!  r"  rx  rF  rH  rT  rW  r`  ra  r�  rˆ  r‰  r�  r”  r—  r˜  r¨  ri  rj  rd   rd   rd   re   Ú<module>   s@  8Zj& I   CJ+^   Ibý	\w y
&UV 
 v ;    .?L)!1P/@b 
 =h? 4       *  9  & * d),

k( .3F ý
P.