U
    !êÆjTˆ ã                   @   s’  d dl Z d dlZd dl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 d d	lmZ 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 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 Z d dl#m$Z$m%Z%m&Z& ddlmZmZmZmZmZ e$dƒZ'ddej(fdd„Z)ej*fdd„Z+dd„ Z,dd„ Z-G dd„ deƒZ.G dd„ deƒZ/G dd „ d eƒZ0G d!d"„ d"eƒZ1G d#d$„ d$eƒZ2d%d&„ Z3d'd(„ Z4d d)lm5Z5 e5ƒ ZG d*d+„ d+eƒZ6G d,d-„ d-eƒZ7d d.l8m9Z9 d d/l:m;Z; G d0d1„ d1eƒZ<G d2d3„ d3eƒZ=G d4d5„ d5eƒZ>G d6d7„ d7eƒZ?dd8lm@Z@mAZA d9d:„ ZBG d;d<„ d<eƒZCd dlmZ d d	lmZ d dlmZ d dlmZ d d=l
mZD dd>lmEZEmFZFmZ d?d@„ ZGG dAdB„ dBeƒZHG dCdD„ dDeƒZIG dEdF„ dFeƒZJd dlKZKd d.l8m9Z9 d dGlmLZL d d/l:m;Z; d dlmZM d d
lmZ d d	lmZ d dlmZ ddHlmEZEmNZNmFZF dIZOddJeMj(fdKd„Z)eMj*fdLd„Z+dMdN„ ZPdOdP„ ZQdQdR„ ZRdSdT„ ZSdUdV„ ZTdWdX„ ZUdYdZ„ ZVd[d\„ ZWd]d^„ ZXG d_d`„ d`eƒZYG dadb„ dbeƒZZG dcdd„ ddeƒZ[G dedf„ dfeƒZ\G dgdh„ dheƒZ]d dlmZ d d	lmZ d dlmZ ddilm^Z^ G djdk„ dkeƒZ_dS )lé    N)ÚauthenticateÚlogin)ÚUser)ÚContentFile)Útransaction)ÚQ©Ústatus)ÚAPIView©ÚResponse)ÚIsAuthenticated)ÚRefreshTokené   )ÚCompanyÚCustomerÚProductÚProfilesÚInvoiceÚInvoiceItem)Úmake_password)ÚObjectDoesNotExist)ÚDecimalÚInvalidOperationÚROUND_HALF_UP)r   r   r   r   r   z0.01c                 C   s.   t |ddœd dœ|rd|ini d| i–|d�S )NÚsuccess©ÚcodeÚresponse)r	   ÚerrorÚmessageÚdatar   r   ©r!   r    r   © r#   ú./var/www/html/CISBACKEND/school/myapp/views.pyÚok'   s    þ üûr%   c                 C   s   t |ddœd| dœ|d�S ©NÚfailedr   T©r	   r   r    r   r   ©r    r   r#   r#   r$   Úfail0   s    ýür*   c              
   C   s^   | dks| dkr t d|› d�ƒ‚ztt| ƒƒW S  tt tfk
rX   t d|› d�ƒ‚Y nX dS )zÓ
    Validate + coerce a value into a Decimal, raising a clear message on bad
    input. Goes through str() first so binary floating-point artifacts
    (e.g. 0.1 + 0.2 != 0.3) never leak into money fields.
    NÚ ú'z' is required.z' must be a valid number.)Ú
ValueErrorr   Ústrr   Ú	TypeError)ÚvalueÚ
field_namer#   r#   r$   Ú
to_decimal8   s    r2   c                 C   s   t | ƒjttd�S )zKRound a Decimal to exactly 2 places using standard rounding (not banker's).)Úrounding)r   ÚquantizeÚ
TWO_PLACESr   )r0   r#   r#   r$   Úq2F   s    r6   c                   @   s   e Zd ZdZdd„ ZdS )ÚLoginAPIViewu<  
    Accepts either a username or an email in `username`, plus `password`.
    `fcm_token` (optional) is stored against the profile for push notifications â€”
    it is intentionally NOT written into `pincode`; that was a bug in the
    previous version. Adjust the field name below to match your Profile model.
    c                 C   sŒ  |j }| d¡pd ¡ }| d¡}| d¡}|r4|s@tdtjƒS t d|¡}|rŽztj	j|d�}|j
}W q’ tjk
rŠ   tdtjƒ Y S X n|}t|||d	�}	|	d kr´tdtjƒS |	jsÆtd
tjƒS t||	ƒ t |	¡}
d }d }d }zTtj	j|	jd�}|�r||_|jdgd� |j�r(| |jj¡nd }|j}|j}W n tjk
�rR   Y nX t|	j
|	j|	j
|	j|	jt|
ƒt|
j ƒ|d||dœdd�S )NÚusernamer+   ÚpasswordÚ	fcm_tokenz)Username/email and password are required.z[^@]+@[^@]+\.[^@]+)Zemail__iexactzInvalid username or password.)r8   r9   zThis account has been disabled.©Úuser_id©Úupdate_fieldsÚloop)ÚnameÚidr8   ÚemailZisSuperZrefreshÚtokenÚprofileZcompanynameÚphoneÚrolezLogin success©r    )!r!   ÚgetÚstripr*   r	   ÚHTTP_400_BAD_REQUESTÚreÚmatchr   Úobjectsr8   ÚDoesNotExistÚHTTP_401_UNAUTHORIZEDr   Ú	is_activeÚHTTP_403_FORBIDDENr   r   Zfor_userr   rA   r:   ÚsaveÚprofilesÚbuild_absolute_uriÚurlrE   rF   r%   rB   Úis_superuserr.   Zaccess_token)ÚselfÚrequestr!   Zusername_or_emailr9   r:   Úis_emailÚmatchedZusername_to_authÚuserrC   Úprofile_photorE   rF   rD   r#   r#   r$   ÚpostT   sb    





õôzLoginAPIView.postN)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r]   r#   r#   r#   r$   r7   L   s   r7   c                   @   sP   e Zd ZefZdd„ Zddd„Zddd„Zdd	d
„Zdd„ Z	dd„ Z
dd„ ZdS )ÚCompanyAPIViewc                 C   s�   d|j kr|j d S | d¡}| ddtt ¡ ƒ› d�¡}|rŒz6d|krV| d¡d }| ¡ }t |¡}t||d�W S  t	k
rŠ   Y d S X d S )	NÚlogoÚlogo_base64Úlogo_filenameZlogo_z.jpgú,r   ©r@   )
ÚFILESrH   ÚintÚtimeÚsplitrI   Úbase64Ú	b64decoder   Ú	Exception)rW   rX   r!   rd   re   Z
image_datar#   r#   r$   Ú_handle_logo—   s    



zCompanyAPIView._handle_logoNc                 C   sT   |j |j|j|j|j|j|j|j|j|j	r8| 
|j	j¡nd dœ
}|d k	rP||d< |S )N)
rA   Úcompany_nameÚaddressÚmobilerB   Ú
gst_numberÚbank_detailsÚ
dealers_inÚinvoice_termsrc   Úrow)rA   rp   rq   rr   rB   rs   rt   ru   rv   rc   rT   rU   )rW   rX   Úcompanyrw   Úpayloadr#   r#   r$   Ú
_serialize©   s    özCompanyAPIView._serializeFc                 C   sz   i }|  d¡}|s*|r"t|ƒ ¡ s*d|d< |  d¡}|rPt dt|ƒ¡sPd|d< |  d¡}|rvt dt|ƒ¡svd|d< |S )	Nrp   zCompany name is required.rB   z^[^@\s]+@[^@\s]+\.[^@\s]+$zEnter a valid email address.rr   ú^[0-9+\-\s]{7,15}$úEnter a valid mobile number.©rH   r.   rI   rK   rL   )rW   r!   ÚpartialÚerrorsrp   rB   rr   r#   r#   r$   Ú	_validateº   s    


zCompanyAPIView._validatec                    sÄ   |d k	rNzt jj|d�}W n" t jk
r<   tdtjƒ Y S X tˆ ˆ |¡ƒS ˆ j	 dd¡ 
¡ }t j ¡  d¡}|r¢| t|d�t|d�B t|d�B t|d	�B ¡}‡ ‡fd
d„t|dƒD ƒ}t|ƒS )N©rA   úNo company foundÚsearchr+   ú-created_at)Zcompany_name__icontains©Zgst_number__icontains©Zmobile__icontains)Zemail__icontainsc                    s    g | ]\}}ˆj ˆ ||d �‘qS ©)rw   ©rz   ©Ú.0ÚiÚc©rX   rW   r#   r$   Ú
<listcomp>Û   s     z&CompanyAPIView.get.<locals>.<listcomp>r   )r   rM   rH   rN   r*   r	   ÚHTTP_404_NOT_FOUNDr%   rz   Úquery_paramsrI   ÚallÚorder_byÚfilterr   Ú	enumerate)rW   rX   rA   rx   rƒ   ÚqsÚ	data_listr#   r�   r$   rH   Ê   s(    ÿþýÿzCompanyAPIView.getc                 C   sÐ   |j }|  |¡}|r t|tjƒS |  ||¡}zltjj| 	d¡| 	d¡| 	d¡| 	d¡| 	d¡| 	d¡| 	d¡| 	d¡pxd |d	�	}t
|  ||¡d
tjd�W S  tk
rÊ } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nrp   rq   rr   rB   rs   rt   ru   rv   )	rp   rq   rr   rB   rs   rt   ru   rv   rc   zCompany added successfullyr)   )r!   r€   r*   r	   rJ   ro   r   rM   ÚcreaterH   r%   rz   ÚHTTP_201_CREATEDrn   r.   )rW   rX   r!   r   rc   rx   Úer#   r#   r$   r]   Þ   s,    
÷ÿzCompanyAPIView.postc              
   C   sH  |j }ztjj|d�}W n" tjk
r:   tdtjƒ Y S X | j|dd�}|rZt|tj	ƒS z´|  
||¡}| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d	|j¡|_| d
|j¡|_| d|j¡|_| d|j¡|_|rò||_| ¡  t|  ||¡dd�W S  tk
�rB } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nr�   r‚   T©r~   rp   rq   rr   rB   rs   rt   ru   rv   zCompany updated successfullyrG   )r!   r   rM   rH   rN   r*   r	   r�   r€   rJ   ro   rp   rq   rr   rB   rs   rt   ru   rv   rc   rR   r%   rz   rn   r.   )rW   rX   rA   r!   rx   r   rc   r™   r#   r#   r$   Úputö   s0    zCompanyAPIView.putc                 C   sH   zt jj|d�}W n" t jk
r4   tdtjƒ Y S X | ¡  tdd�S )Nr�   r‚   úCompany deleted successfullyrG   )	r   rM   rH   rN   r*   r	   r�   Údeleter%   )rW   rX   rA   rx   r#   r#   r$   r�     s    zCompanyAPIView.delete)N)F)N)r^   r_   r`   r   Úpermission_classesro   rz   r€   rH   r]   r›   r�   r#   r#   r#   r$   rb   ”   s   


rb   c                   @   sH   e Zd ZefZddd„Zddd„Zddd„Zd	d
„ Zdd„ Z	dd„ Z
dS )ÚCustomerAPIViewNc                 C   s.   |j |j|j|j|jdœ}|d k	r*||d< |S )N©rA   r@   rq   rs   rr   rw   r    )rW   rX   Úcustomerrw   ry   r#   r#   r$   rz     s    ûzCustomerAPIView._serializeFc                 C   sT   i }|  d¡}|s*|r"t|ƒ ¡ s*d|d< |  d¡}|rPt dt|ƒ¡sPd|d< |S )Nr@   zCustomer name is required.rr   r{   r|   r}   )rW   r!   r~   r   r@   rr   r#   r#   r$   r€   +  s    

zCustomerAPIView._validatec                    sº   |d k	rNzt jj|d�}W n" t jk
r<   tdtjƒ Y S X tˆ ˆ |¡ƒS ˆ j	 dd¡ 
¡ }t j ¡  d¡}|r˜| t|d�t|d�B t|d�B ¡}‡ ‡fd	d
„t|dƒD ƒ}t|ƒS )Nr�   úNo customer foundrƒ   r+   r„   ©Zname__icontainsr…   r†   c                    s    g | ]\}}ˆj ˆ ||d �‘qS r‡   rˆ   r‰   r�   r#   r$   rŽ   E  s     z'CustomerAPIView.get.<locals>.<listcomp>r   )r   rM   rH   rN   r*   r	   r�   r%   rz   r�   rI   r‘   r’   r“   r   r”   )rW   rX   rA   r¡   rƒ   r•   r–   r#   r�   r$   rH   5  s$    ÿþÿzCustomerAPIView.getc              
   C   sž   |j }|  |¡}|r t|tjƒS zFtjj| d¡| d¡| d¡| d¡d�}t	|  
||¡dtjd�W S  tk
r˜ } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nr@   rq   rs   rr   )r@   rq   rs   rr   zCustomer added successfullyr)   )r!   r€   r*   r	   rJ   r   rM   r—   rH   r%   rz   r˜   rn   r.   )rW   rX   r!   r   r¡   r™   r#   r#   r$   r]   H  s     
üÿzCustomerAPIView.postc              
   C   sð   |j }ztjj|d�}W n" tjk
r:   tdtjƒ Y S X | j|dd�}|rZt|tj	ƒS z^| d|j
¡|_
| d|j¡|_| d|j¡|_| d|j¡|_| ¡  t|  ||¡d	d
�W S  tk
rê } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nr�   r¢   Trš   r@   rq   rs   rr   zCustomer updated successfullyrG   )r!   r   rM   rH   rN   r*   r	   r�   r€   rJ   r@   rq   rs   rr   rR   r%   rz   rn   r.   )rW   rX   rA   r!   r¡   r   r™   r#   r#   r$   r›   Y  s"    zCustomerAPIView.putc                 C   s^   zt jj|d�}W n" t jk
r4   tdtjƒ Y S X |j ¡ rLtdtj	ƒS | 
¡  tdd�S )Nr�   r¢   z9This customer has invoices attached and can't be deleted.zCustomer deleted successfullyrG   )r   rM   rH   rN   r*   r	   r�   ÚinvoicesÚexistsrJ   r�   r%   )rW   rX   rA   r¡   r#   r#   r$   r�   n  s    
ÿzCustomerAPIView.delete)N)F)N©r^   r_   r`   r   rž   rz   r€   rH   r]   r›   r�   r#   r#   r#   r$   rŸ     s   



rŸ   c                   @   sH   e Zd ZefZddd„Zddd„Zddd„Zd	d
„ Zdd„ Z	dd„ Z
dS )ÚProductAPIViewNc                 C   s2   |j |j|jt|jƒ|jdœ}|d k	r.||d< |S )N)rA   r@   Úhsn_codeÚdefault_rateÚunitrw   )rA   r@   r¨   r.   r©   rª   )rW   rX   Úproductrw   ry   r#   r#   r$   rz   ~  s    ûzProductAPIView._serializeFc              	   C   sz   i }|  d¡}|s*|r"t|ƒ ¡ s*d|d< |  d¡}|dkrvzt|ƒdk rRd|d< W n  ttfk
rt   d|d< Y nX |S )Nr@   zProduct name is required.r©   )Nr+   r   z Default rate cannot be negative.z$Default rate must be a valid number.)rH   r.   rI   Úfloatr/   r-   )rW   r!   r~   r   r@   Úrater#   r#   r$   r€   Š  s    

zProductAPIView._validatec                    s°   |d k	rNzt jj|d�}W n" t jk
r<   tdtjƒ Y S X tˆ ˆ |¡ƒS ˆ j	 dd¡ 
¡ }t j ¡  d¡}|rŽ| t|d�t|d�B ¡}‡ ‡fdd	„t|d
ƒD ƒ}t|ƒS )Nr�   úNo product foundrƒ   r+   r„   r£   )Zhsn_code__icontainsc                    s    g | ]\}}ˆj ˆ ||d �‘qS r‡   rˆ   )rŠ   r‹   Úpr�   r#   r$   rŽ   ¤  s     z&ProductAPIView.get.<locals>.<listcomp>r   )r   rM   rH   rN   r*   r	   r�   r%   rz   r�   rI   r‘   r’   r“   r   r”   )rW   rX   rA   r«   rƒ   r•   r–   r#   r�   r$   rH   ˜  s    zProductAPIView.getc              
   C   s¤   |j }|  |¡}|r t|tjƒS zLtjj| d¡| d¡| d¡pDd| dd¡d�}t	|  
||¡dtjd	�W S  tk
rž } ztt|ƒƒ W Y ¢S d }~X Y nX d S )
Nr@   r¨   r©   r   rª   ÚKg)r@   r¨   r©   rª   zProduct added successfullyr)   )r!   r€   r*   r	   rJ   r   rM   r—   rH   r%   rz   r˜   rn   r.   )rW   rX   r!   r   r«   r™   r#   r#   r$   r]   §  s     

üÿzProductAPIView.postc              
   C   sð   |j }ztjj|d�}W n" tjk
r:   tdtjƒ Y S X | j|dd�}|rZt|tj	ƒS z^| d|j
¡|_
| d|j¡|_| d|j¡|_| d|j¡|_| ¡  t|  ||¡d	d
�W S  tk
rê } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nr�   r®   Trš   r@   r¨   r©   rª   zProduct updated successfullyrG   )r!   r   rM   rH   rN   r*   r	   r�   r€   rJ   r@   r¨   r©   rª   rR   r%   rz   rn   r.   )rW   rX   rA   r!   r«   r   r™   r#   r#   r$   r›   ¸  s"    zProductAPIView.putc                 C   s^   zt jj|d�}W n" t jk
r4   tdtjƒ Y S X |j ¡ rLtdtj	ƒS | 
¡  tdd�S )Nr�   r®   z6This product is used in invoices and can't be deleted.zProduct deleted successfullyrG   )r   rM   rH   rN   r*   r	   r�   Úinvoice_itemsr¥   rJ   r�   r%   )rW   rX   rA   r«   r#   r#   r$   r�   Í  s    
ÿzProductAPIView.delete)N)F)Nr¦   r#   r#   r#   r$   r§   {  s   


r§   c                   @   sN   e Zd ZefZddd„Zdd„ Zddd„Zdd	„ Zd
d„ Z	dd„ Z
dd„ ZdS )ÚInvoiceAPIViewNc                 C   sŽ   dd„ |j  ¡ D ƒ}|j|j|j|j|jj|jj|jj	|j
|j|jt|jƒt|jƒt|jƒt|jƒt|jƒt|jƒ|dœ}|d k	rŠ||d< |S )Nc              
   S   s>   g | ]6}|j |j|jj|jjt|jƒt|jƒt|jƒd œ‘qS ))rA   r«   Zproduct_namer¨   Úquantityr­   Úamount)	rA   Ú
product_idr«   r@   r¨   r.   r³   r­   r´   )rŠ   Úitemr#   r#   r$   rŽ   Þ  s   
øùz-InvoiceAPIView._serialize.<locals>.<listcomp>)rA   Úinvoice_numberÚinvoice_dater¡   Zcustomer_nameZcustomer_gst_numberZcustomer_addressÚeway_bill_noÚeway_bill_dateÚ
vehicle_noÚsubtotalÚcgstÚsgstÚigstÚ	round_offÚgrand_totalÚitemsrw   )rÂ   r‘   rA   r·   r¸   Úcustomer_idr¡   r@   rs   rq   r¹   rº   r»   r.   r¼   r½   r¾   r¿   rÀ   rÁ   )rW   rX   Úinvoicerw   rÂ   ry   r#   r#   r$   rz   Ý  s0    
öïzInvoiceAPIView._serializec           
      C   s^  |sdS g }t ƒ }t|dƒD �]6\}}| d¡}|sHdd|› d�f  S t|ƒ|krhdd|› d�f  S | t|ƒ¡ tjj|d� ¡ sœdd|› d	�f  S z(t	| d
d¡d
ƒ}t	| dd¡dƒ}W n@ t
k
�r }	 z dd|› d|	› �f W Y ¢  S d}	~	X Y nX |dk�r$dd|› d�f  S |dk �rBdd|› d�f  S | |||dœ¡ q|dfS )zPReturns (cleaned_items, error_message_or_None). Also rejects duplicate products.)NzAdd at least one line item.r   r«   NzLine z: select a product.z/: this product is already added to the invoice.r�   z: product not found.r³   r   r­   z: z": quantity must be greater than 0.z: rate cannot be negative.)rµ   r³   r­   )Úsetr”   rH   r.   Úaddr   rM   r“   r¥   r2   r-   Úappend)
rW   Ú
items_dataÚcleanedZseen_productsÚidxÚitrµ   Zqtyr­   r™   r#   r#   r$   Ú_validate_items  s0    
.

zInvoiceAPIView._validate_itemsc                    s°   |d k	rNzt jj|d�}W n" t jk
r<   tdtjƒ Y S X tˆ ˆ |¡ƒS ˆ j	 dd¡ 
¡ }t j ¡  d¡}|rŽ| t|d�t|d�B ¡}‡ ‡fdd	„t|d
ƒD ƒ}t|ƒS )Nr�   úNo invoice foundrƒ   r+   r„   )Zinvoice_number__icontains)Zcustomer__name__icontainsc                    s    g | ]\}}ˆj ˆ ||d �‘qS r‡   rˆ   )rŠ   Úrr‹   r�   r#   r$   rŽ   0  s     z&InvoiceAPIView.get.<locals>.<listcomp>r   )r   rM   rH   rN   r*   r	   r�   r%   rz   r�   rI   r‘   r’   r“   r   r”   )rW   rX   rA   rÄ   rƒ   r•   r–   r#   r�   r$   rH   "  s    ÿzInvoiceAPIView.getc                 C   s8   |dk rdS |dk rdS |dk r$dS t |ƒdkr4dS d S )Nr   zCGST cannot be negative.zSGST cannot be negative.zIGST cannot be negative.r   u6   Round off must be a small adjustment (less than â‚¹1).)Úabs)rW   r½   r¾   r¿   rÀ   r#   r#   r$   Ú_validate_tax_fields3  s    z#InvoiceAPIView._validate_tax_fieldsc                    sv  |j }| d¡pd ¡ }| d¡}| dg ¡}|s:tdƒS tjj|d� ¡ r\td|› d�ƒS |rrtjj|d	� ¡ sztd
ƒS | d¡sŒtdƒS |  	|¡\}}|r¦t|ƒS zTt
| d¡p¶ddƒ}t
| d¡pÊddƒ}	t
| d¡pÞddƒ}
t
| d¡pòddƒ}W n4 tk
�r. } ztt|ƒƒ W Y ¢S d }~X Y nX |  ||	|
|¡}|�rNt|ƒS zît ¡ �Æ ttdd„ |D ƒtdƒƒƒ}t|| |	 |
 | ƒ}|dk �r®tdƒW  5 Q R £ W S tjj|| d¡|| d¡| d¡�pÖd | d¡|t|ƒt|	ƒt|
ƒt|ƒ|d�‰ tj ‡ fdd„|D ƒ¡ W 5 Q R X t|  |ˆ ¡dtjd�W S  tk
�rp } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nr·   r+   r¡   rÂ   zInvoice number is required.©r·   úInvoice number 'ú' is already in use.r�   úA valid customer is required.r¸   zInvoice date is required.r½   r   r¾   r¿   rÀ   c                 s   s   | ]}|d  |d  V  qdS ©r³   r­   Nr#   ©rŠ   r‹   r#   r#   r$   Ú	<genexpr>a  s     z&InvoiceAPIView.post.<locals>.<genexpr>Ú0õ?   Invoice total cannot be negative â€” check the entered amounts.r¹   rº   r»   )r·   r¸   rÃ   r¹   rº   r»   r¼   r½   r¾   r¿   rÀ   rÁ   c                    s:   g | ]2}t ˆ |d  |d |d t|d |d  ƒd�‘qS ©rµ   r³   r­   )rÄ   rµ   r³   r­   r´   ©r   r6   rÖ   ©rÄ   r#   r$   rŽ   u  s   ùûz'InvoiceAPIView.post.<locals>.<listcomp>zInvoice created successfullyr)   )r!   rH   rI   r*   r   rM   r“   r¥   r   rÌ   r2   r-   r.   rÐ   r   Úatomicr6   Úsumr   r—   r   Úbulk_creater%   rz   r	   r˜   rn   )rW   rX   r!   r·   rÃ   rÈ   Úcleaned_itemsÚerrr½   r¾   r¿   rÀ   r™   Útax_errr¼   rÁ   r#   rÜ   r$   r]   @  sj    

"

ôø
ÿzInvoiceAPIView.postc              
      s\  |j }ztjj|d�‰ W n" tjk
r:   tdtjƒ Y S X | d¡}|r~|ˆ jkr~tjj	|d�j
|d� ¡ r~td|› d�ƒS d }d|kr¬|  | dg ¡¡\}}|r¬t|ƒS zTt| dˆ j¡dƒ}t| d	ˆ j¡d	ƒ}t| d
ˆ j¡d
ƒ}	t| dˆ j¡dƒ}
W n4 tk
�r4 } ztt|ƒƒ W Y ¢S d }~X Y nX |  |||	|
¡}|�rTt|ƒS |d k	�rzttdd„ |D ƒtdƒƒƒnˆ j}t|| | |	 |
 ƒ}|dk �rªtdƒS �zDt ¡ �� |�pÄˆ jˆ _| dˆ j¡ˆ _| dˆ j¡ˆ _| dˆ j¡�púd ˆ _| dˆ j¡ˆ _| d¡�rFtjj	|d d� ¡ �s:tdƒ‚| d¡ˆ _ |d k	�r~ˆ j! "¡  #¡  t$j %‡ fdd„|D ƒ¡ |ˆ _t|ƒˆ _t|ƒˆ _t|	ƒˆ _t|
ƒˆ _tˆ jˆ j ˆ j ˆ j ˆ j ƒˆ _&ˆ  '¡  W 5 Q R X t(|  )|ˆ ¡dd�W S  tk
�r$ } ztt|ƒƒ W Y ¢S d }~X Y n4 t*k
�rV } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nr�   rÍ   r·   rÑ   rÒ   rÓ   rÂ   r½   r¾   r¿   rÀ   c                 s   s   | ]}|d  |d  V  qdS rÕ   r#   rÖ   r#   r#   r$   r×   §  s     z%InvoiceAPIView.put.<locals>.<genexpr>rØ   r   rÙ   r¸   r¹   rº   r»   r¡   rÔ   c                    s:   g | ]2}t ˆ |d  |d |d t|d |d  ƒd�‘qS rÚ   rÛ   rÖ   rÜ   r#   r$   rŽ   ¼  s   ùûz&InvoiceAPIView.put.<locals>.<listcomp>zInvoice updated successfullyrG   )+r!   r   rM   rH   rN   r*   r	   r�   r·   r“   Úexcluder¥   rÌ   r2   r½   r¾   r¿   rÀ   r-   r.   rÐ   r6   rÞ   r   r¼   r   rÝ   r¸   r¹   rº   r»   r   rÃ   rÂ   r‘   r�   r   rß   rÁ   rR   r%   rz   rn   )rW   rX   rA   r!   Z
new_numberrà   rá   r½   r¾   r¿   rÀ   r™   râ   Zprospective_subtotalZprospective_grand_totalr#   rÜ   r$   r›   „  sz    
"ÿ þ

ø




ÿ zInvoiceAPIView.putc                 C   sH   zt jj|d�}W n" t jk
r4   tdtjƒ Y S X | ¡  tdd�S )Nr�   rÍ   zInvoice deleted successfullyrG   )	r   rM   rH   rN   r*   r	   r�   r�   r%   )rW   rX   rA   rÄ   r#   r#   r$   r�   ×  s    zInvoiceAPIView.delete)N)N)r^   r_   r`   r   rž   rz   rÌ   rH   rÐ   r]   r›   r�   r#   r#   r#   r$   r²   Ú  s   
$!
DSr²   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: ©Ú	send_mailÚsettingsÚDEFAULT_FROM_EMAILrn   Úprint©rB   ÚotpÚsubjectr    r™   r#   r#   r$   Ú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 )Nrä   rå   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
        Fræ   rè   ré   rî   r#   r#   r$   Úsend_otp_emailsü  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ÚparamsrB   úReceived email:©rB   zEmail not foundr   TzEmail not registeredr(   é   Ú
1234567890©ÚlengthÚallowed_chars©ÚtargetÚargsÚSuccess©r	   r   r!   zError:úInternal Server Error)r!   rH   rí   r   rM   r“   r¥   r   r	   r�   ÚOtpr—   Úget_random_stringrï   ÚtimezoneÚnowÚotp_created_atrR   Ú	threadingÚThreadrñ   ÚstartÚHTTP_200_OKrn   ÚHTTP_500_INTERNAL_SERVER_ERRORr.   )rW   rX   r!   rB   r[   rï   r™   r#   r#   r$   r]     s8    

ý


ý


ýzSendotpAPIView.postN©r^   r_   r`   r]   r#   r#   r#   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 )NrB   rö   r÷   zEmail already registeredr   Tz;This email is already registered. Please use another email.r(   rø   rù   rú   )rB   rï   r  rý   r   r  r  )r!   rH   rí   r   rM   r“   r¥   r   r	   ÚHTTP_409_CONFLICTr  r  r—   r  r  r  r	  rò   r
  r  rn   r  r.   )rW   rX   r!   rB   rï   r[   r™   r#   r#   r$   r]   C  s0    

ý

ý

ýzSendotpsAPIView.postNr  r#   r#   r#   r$   r  B  s   r  )Ú	timedelta)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 )NrB   rï   r÷   r  é<   ©Úsecondsi‘  z&OTP expired. Please request a new one.T)r	   r    r   r   éÈ   zOTP VerifiedFé�  zInvalid OTPé”  zOTP not found)r�   rH   r  rM   r“   Úlatestr  r  r  r  r   r	   r  rï   rN   )rW   rX   rB   Zotp_enteredZuser_otpZexpiration_timer#   r#   r$   rH   f  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)rR   r   r   z"Profile image deleted successfullyr(   r'   zProfile not foundzID not providedzUser ID is required)r   rM   rH   rS   r�   rR   r   r	   r  r   r�   rJ   )rW   rX   rA   rD   r#   r#   r$   r�   �  s.    
ý

ý
ýzVerifyotpAPIView.deleteN)r^   r_   r`   rH   r�   r#   r#   r#   r$   r  e  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 )NrA   r�   r;   z../static/dummy.png)r@   rB   rE   Úf_nameZl_namerD   rA   r   r   r  ZFailedTzCompany not foundr(   )rH   r   rM   r   rA   rS   rU   r@   rB   rE   Ú
first_nameÚ	last_namer   r	   r  r   r�   )rW   rX   ÚkwargsrA   r[   rx   Úprr!   r#   r#   r$   rH   ²  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;   r   r   zProfile updated successfullyr(   r'   TzMissing required field: zAn error occurred: )r!   rH   r   rM   r[   rA   rS   rR   r   r	   r˜   ÚKeyErrorrJ   r.   rn   r  )rW   rX   r!   ZphoZtaker™   r#   r#   r$   r]   Ú  s.    

ý

ý
ýzProfileupdateAPIView.postc                 C   s  |j }|j d¡}zÀtjj|d�}tjj|d�}| d|j¡|_| d|j¡|_| d|j¡|_| d|j	¡|_	| 
¡  | d|j	¡|_	| d|j¡|_| d|j¡|_|r²||_| 
¡  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  r;   r�   r  Zfirst_namesr  Zemail_idZphone_nor   r   úUser updated successfullyr(   r'   TzUser not found)r!   rh   rH   r   rM   r   r8   r  r  rB   rR   rE   r@   rS   r   r	   r  r   r�   )rW   rX   rA   r!   ÚphotoÚmmÚsdr#   r#   r$   r›      s6    
ý

ýzProfileupdateAPIView.putN)r^   r_   r`   r   rž   rH   r]   r›   r#   r#   r#   r$   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¬zhtjj |d�}|j|j|j|j|j|j|j	|j
|j|jrZ| |jj¡nd 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jdddgd� d¡}g }t|dƒD ]N\}}| ||j|j|j|j|j|j|j	|j
|j�r| |jj¡nd dœ
¡ qÖ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 )NrA   r;   )
rA   r8   rE   r9   rB   rF   ÚcourseÚbatchr	   r\   r   r   r  r'   TzNo student foundr(   é   é   r   )Zrole__inr„   r   )
rw   rA   ZemployeeNamerB   rE   r	   rF   r&  r'  r"  )rH   r   rM   r<   r@   rE   r9   rB   rF   r&  r'  r	   rS   rT   rU   r   r  rN   r�   r“   r’   r”   rÇ   rn   rJ   r.   )
rW   rX   r  rA   Ústudentr!   Z	employeesZemployee_listÚindexr™   r#   r#   r$   rH   ,  sj    
ô
ý

ýõ

ý

ýzRegisterAPIView.getc                 C   s  |j }|j d¡}zª| d¡}| d¡}| d¡}| d¡}| d¡}| d¡}	| d¡}
t|ƒ}tjj|||d	�}|j d¡}tjj|||||	|
|j||d
�	}t	dddœd ddœt
jd�W S  tk
�r
 } z.t	dddœddt|ƒ› �dœt
jd� W Y ¢S d }~X Y nX d S )Nr\   r8   rB   rE   r9   rF   r&  r'  )r8   rB   r9   )	r@   rB   rE   rF   r&  r'  r<   r9   rS   éÉ   r   r   zEmployee created successfullyr(   r   r  r'   TúError: )r!   rh   rH   r   r   rM   r—   r   rA   r   r	   r˜   rn   r.   rJ   )rW   rX   r!   r"  r8   rB   rE   r9   rF   r&  r'  Zhashed_passwordZvanrD   r™   r#   r#   r$   r]   l  sV    






ý÷ýüýüzRegisterAPIView.postc                 C   s,  |j }|j d¡}zæ|j d¡}| d¡}| d¡}| d¡}| d¡}| d¡}	| d¡}
| d¡}tjj|d	�}tjj|d
�}||_||_||_|	|_	|
|_
||_||_|r¶||_| ¡  t|ƒ}||_||_||_| ¡  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\   r8   rB   rE   r9   rF   r&  r'  r;   r�   r   r   r!  r(   r'   TzSomething went wrong)r!   rh   rH   r   rM   r   r@   rB   rE   rF   r&  r'  r9   rS   rR   r   r8   r   r	   r˜   r   rJ   )rW   rX   rA   r!   r"  r8   rB   rE   r9   rF   r&  r'  r#  r$  Zpassesr#   r#   r$   r›   ¢  sN    







ý

ý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 )NrA   r;   r�   r   r   rœ   r(   r'   TúNo data found)
rH   r   rM   r�   r   r   r	   r  r   r�   )rW   rÿ   r  Z
company_idr  rx   r#   r#   r$   r�   Ò  s"    

ý

ýzRegisterAPIView.deleteN©r^   r_   r`   rH   r]   r›   r�   r#   r#   r#   r$   r%  +  s   @60r%  c                   @   s,   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	S )
ÚCourseAPIViewc              
   C   sŒ   z>t j ¡  d¡}dd„ |D ƒ}ttjddœd |dœtjd�W S  tk
r† } z*ttjddœd	t	|ƒd
œtjd� W Y ¢S d }~X Y nX d S )Nr@   c                 S   s   g | ]}|j |jd œ‘qS )©rA   r@   r1  )rŠ   rŒ   r#   r#   r$   rŽ   ï  s     z%CourseAPIView.get.<locals>.<listcomp>r   r   r  r   r'   Tr(   )
ÚCourserM   r‘   r’   r   r	   r  rn   rJ   r.   )rW   rX   Zcoursesr!   r™   r#   r#   r$   rH   ì  s$    
ýü
ýüzCourseAPIView.getc              
   C   sð   zr|j  d¡pd ¡ }|s:ttjddœdddœtjd�W S tjj|d	�}ttj	d
dœd d|j
|jdœdœtj	d�W S  tk
r¤   ttjddœdddœtjd� Y S  tk
rê } z*ttjddœdt|ƒdœtjd� W Y ¢S d }~X Y nX d S )Nr@   r+   r'   r   TúCourse name is requiredr(   r   rg   r   zCourse added successfullyr1  ©r	   r   r    r!   úThis course already exists)r!   rH   rI   r   r	   rJ   r2  rM   r—   r˜   rA   r@   ÚIntegrityErrorrn   r.   )rW   rX   r@   r&  r™   r#   r#   r$   r]   ü  sF    
ýü
üû
ýü

ýüzCourseAPIView.postc              
   C   s0  z°zt jj|d�}W n6 t jk
rJ   ttjddœdddœtjd� Y W S X |j d¡pZd	 ¡ }|s„ttj	ddœdd
dœtj	d�W S ||_
| ¡  ttjddœd ddœtjd�W S  tk
râ   ttj	ddœdddœtj	d� Y S  tk
�r* } z*ttj	ddœdt|ƒdœtj	d� W Y ¢S d }~X Y nX d S )Nr�   r'   r   TúCourse not foundr(   r   r@   r+   r3  r   zCourse updated successfullyr5  )r2  rM   rH   rN   r   r	   r�   r!   rI   rJ   r@   rR   r  r6  rn   r.   )rW   rX   Úpkr&  r@   r™   r#   r#   r$   r›     sZ    
ýü
ýü
ýü
ýü

ýüzCourseAPIView.putc                 C   s¢   z6t jj|d�}| ¡  ttjddœd ddœtjd�W S  t jk
rj   ttjddœdd	dœtjd� Y S  t	j
k
rœ   ttjddœdd
dœtjd� Y S X d S )Nr�   r   r   zCourse deleted successfullyr(   r   r'   Tr7  z+This course is in use and cannot be deleted)r2  rM   rH   r�   r   r	   r  rN   r�   Údjango_modelsÚProtectedErrorrJ   )rW   rX   r8  r&  r#   r#   r$   r�   A  s4    
ýü
ýü

ýüzCourseAPIView.deleteNr/  r#   r#   r#   r$   r0  ê  s   'r0  )ÚSeoSettingsr2  c                 C   s"   | j | j| j| j| jpd| jdœS )Nr+   ©rA   Ú	page_slugÚ
meta_titleÚmeta_descriptionÚmeta_keywordsÚ
updated_atr<  )Úseor#   r#   r$   Úseo_to_dict[  s    úrC  c                   @   s$   e Zd Zdd„ Zdd„ Zdd„ ZdS )Ú
SeoAPIViewc              
   K   s°   |j  d¡}zV|r6tjj|d� ¡ }|r0t|ƒnd }ndd„ tj ¡ D ƒ}tt	j
ddœd |dœƒW S  tk
rª } z*tt	jddœd	t|ƒd
œt	jd� W Y ¢S d }~X Y nX d S )Nr=  ©r=  c                 S   s   g | ]}t |ƒ‘qS r#   )rC  )rŠ   Úsr#   r#   r$   rŽ   u  s     z"SeoAPIView.get.<locals>.<listcomp>r   r   r  r'   Tr(   r   )r�   rH   r;  rM   r“   ÚfirstrC  r‘   r   r	   r  rn   rJ   r.   )rW   rX   r  r=  rB  r!   r™   r#   r#   r$   rH   n  s&    
ý

ýüzSeoAPIView.getc           
   
   C   s.  |j }zÒ| d¡pd ¡ }| d¡p&d ¡ }| d¡p8d ¡ }| d¡pJd ¡ }|r\|r\|s|ttjddœdd	d
œtjd�W S tjj||||dœd�\}}t|r¤tj	ntj
ddœd |r¸dndt|ƒdœ|rÎtj	ntj
d�W S  tk
�r( }	 z0ttjddœddt|	ƒ› �d
œtjd� W Y ¢S d }	~	X Y nX d S )Nr=  r+   r>  r?  r@  r'   r   Tz7page_slug, meta_title and meta_description are requiredr(   r   )r>  r?  r@  )r=  Údefaultsr   zSEO created successfullyzSEO updated successfullyr4  r-  )r!   rH   rI   r   r	   rJ   r;  rM   Úupdate_or_creater˜   r  rC  rn   r.   )
rW   rX   r!   r=  r>  r?  r@  rB  Úcreatedr™   r#   r#   r$   r]   ƒ  sN    
ýüýþ
	þ
ùø

ýüzSeoAPIView.postc                 O   st   |j  d¡}z0tjj|d�}| ¡  ttjddœd ddœƒW S  tk
rn   ttj	ddœdd	dœtj	d
� Y S X d S )Nr=  rE  r   r   zSEO deleted successfullyr(   r'   Tr.  r   )
r�   rH   r;  rM   r�   r   r	   r  r   r�   )rW   rX   rÿ   r  r=  rB  r#   r#   r$   r�   ­  s"    
ý

ýüzSeoAPIView.deleteN)r^   r_   r`   rH   r]   r�   r#   r#   r#   r$   rD  f  s   *rD  )Úmodels)ÚExamÚQuestionr   c                 C   sX   z4t | dd ƒpt | dd ƒ}|r2t |dd ƒr2|jW S W n tk
rH   Y nX |  ¡ pV| jS ©NrS   rD   r@   ©Úgetattrr@   rn   Úget_full_namer8   ©r[   rD   r#   r#   r$   Úget_student_display_nameÎ  s    rS  c                   @   s,   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	S )
ÚExamAPIViewc              
   C   sÊ   z||j  d¡}|j  d¡}tj d¡ ¡  d¡}|r@|j|d�}|rP|j|d�}dd„ |D ƒ}tt	j
dd	œd |d
œt	j
d�W S  tk
rÄ } z*tt	jdd	œdt|ƒdœt	jd� W Y ¢S d }~X Y nX d S )Nr&  r*  r„   ©r&  )Ú
student_idc                 S   s6   g | ].}|j |jt|jƒ|j|j|j|j|jd œ‘qS ))rA   r*  Ústudent_nameÚtitler&  ÚdateÚdurationr	   )	rA   rV  rS  r*  rX  r&  rY  rZ  r	   )rŠ   r™   r#   r#   r$   rŽ   è  s   	øøz#ExamAPIView.get.<locals>.<listcomp>r   r   r  r   r'   Tr(   )r�   rH   rL  rM   Úselect_relatedr‘   r’   r“   r   r	   r  rn   rJ   r.   )rW   rX   r&  rV  Úexamsr!   r™   r#   r#   r$   rH   Ý  s4    	÷
ýü
ýüzExamAPIView.getc              
      sB  zÀ|j ‰ dddddg}‡ fdd„|D ƒ}|rXttjdd	œd
dd |¡› �dœtjd�W S tjjˆ d d�}tjj	|ˆ d ˆ d ˆ d ˆ d ˆ  dd¡d�}ttj
dd	œd dd|jidœtj
d�W S  tjk
rô   ttjdd	œd
ddœtjd� Y S  tk
�r< } z*ttjdd	œd
t|ƒdœtjd� W Y ¢S d }~X Y nX d S )Nr*  rX  r&  rY  rZ  c                    s   g | ]}ˆ   |¡s|‘qS r#   ©rH   ©rŠ   Úf©ry   r#   r$   rŽ     s     
 z$ExamAPIView.post.<locals>.<listcomp>r'   r   TúMissing fields: ú, r(   r   r�   r	   Ú	Scheduled)r*  rX  r&  rY  rZ  r	   r   zExam created successfullyrA   r4  úSelected student does not exist)r!   r   r	   rJ   Újoinr   rM   rH   rL  r—   r˜   rA   rN   rn   r.   )rW   rX   Úrequired_fieldsÚmissingr*  Úexamr™   r#   r`  r$   r]   ÿ  sZ    
ýü
ú
üû
ýü

ýüzExamAPIView.postc              
   C   s.  zzt jj|d�}|j}d|kr2tjj|d d�|_dD ]}||kr6t|||| ƒ q6| ¡  tt	j
ddœd ddœt	j
d�W S  t jk
r®   tt	jd	dœd
ddœt	jd� Y S  tjk
rà   tt	jd	dœd
ddœt	jd� Y S  tk
�r( } z*tt	jd	dœd
t|ƒdœt	jd� W Y ¢S d }~X Y nX d S )Nr�   r*  )rX  r&  rY  rZ  r	   r   r   zExam updated successfullyr(   r   r'   TúExam not foundrd  )rL  rM   rH   r!   r   r*  ÚsetattrrR   r   r	   r  rN   r�   rJ   rn   r.   )rW   rX   r8  rh  ry   Úfieldr™   r#   r#   r$   r›   '  sP    
ýü
ýü

ýü

ýüzExamAPIView.putc                 C   s¢   z6t jj|d�}| ¡  ttjddœd ddœtjd�W S  t jk
rj   ttjddœdd	dœtjd� Y S  t	j
k
rœ   ttjddœdd
dœtjd� Y S X d S )Nr�   r   r   zExam deleted successfullyr(   r   r'   Tri  z4This exam is linked to records that prevent deletion)rL  rM   rH   r�   r   r	   r  rN   r�   r9  r:  rJ   )rW   rX   r8  rh  r#   r#   r$   r�   J  s4    
ýü
ýü

ýüzExamAPIView.deleteNr/  r#   r#   r#   r$   rT  Û  s   "(#rT  c                   @   s,   e Zd Zdd„ Zdd„ Zdd„ Zdd„ Zd	S )
ÚQuestionAPIViewc              
   C   s¨   zZ|j  d¡}tj ¡  d¡}|r.|j|d�}dd„ |D ƒ}ttj	ddœd |dœtj	d	�W S  t
k
r¢ } z*ttjd
dœdt|ƒdœtjd	� W Y ¢S d }~X Y nX d S )Nr&  r„   rU  c              	   S   s*   g | ]"}|j |j|j|j|j|jd œ‘qS )©rA   r&  ÚquestionÚoptionsÚanswerÚmarksrm  )rŠ   Úqr#   r#   r$   rŽ   o  s   úúz'QuestionAPIView.get.<locals>.<listcomp>r   r   r  r   r'   Tr(   )r�   rH   rM  rM   r‘   r’   r“   r   r	   r  rn   rJ   r.   )rW   rX   r&  Ú	questionsr!   r™   r#   r#   r$   rH   g  s.    ù	
ýü
ýüzQuestionAPIView.getc              
      s(  zØ|j ‰ dddddg}‡ fdd„|D ƒ}|rXttjdd	œd
dd |¡› �dœtjd�W S ˆ d }ˆ d |krŒttjdd	œd
ddœtjd�W S tjjˆ d ˆ d |ˆ d ˆ d d�}ttjdd	œd dd|j	idœtjd�W S  t
k
�r" } z*ttjdd	œd
t|ƒdœtjd� W Y ¢S d }~X Y nX d S )Nr&  rn  ro  rp  rq  c                    s   g | ]}ˆ   |¡s|‘qS r#   r]  r^  r`  r#   r$   rŽ   ˆ  s     
 z(QuestionAPIView.post.<locals>.<listcomp>r'   r   Tra  rb  r(   r   ú/Correct answer must be one of the given options)r&  rn  ro  rp  rq  r   zQuestion added successfullyrA   r4  )r!   r   r	   rJ   re  rM  rM   r—   r˜   rA   rn   r.   )rW   rX   rf  rg  ro  rn  r™   r#   r`  r$   r]   „  sX    
ýü
ýüû
üû
ýüzQuestionAPIView.postc              
   C   s>  z¼t jj|d�}|j}| d|j¡}| d|j¡}||krZttjddœdddœtjd	�W S | d
|j	¡|_	| d|j
¡|_
||_||_| d|j¡|_| ¡  ttjddœd ddœtjd	�W S  t jk
rð   ttjddœdddœtjd	� Y S  tk
�r8 } z*ttjddœdt|ƒdœtjd	� W Y ¢S d }~X Y nX d S )Nr�   ro  rp  r'   r   Trt  r(   r   r&  rn  rq  r   zQuestion updated successfullyúQuestion not found)rM  rM   rH   r!   ro  rp  r   r	   rJ   r&  rn  rq  rR   r  rN   r�   rn   r.   )rW   rX   r8  rn  ry   ro  rp  r™   r#   r#   r$   r›   ¬  sT    
ýü
ýü
ýü

ýüzQuestionAPIView.putc                 C   sp   z6t jj|d�}| ¡  ttjddœd ddœtjd�W S  t jk
rj   ttjddœdd	dœtjd� Y S X d S )
Nr�   r   r   zQuestion deleted successfullyr(   r   r'   Tru  )	rM  rM   rH   r�   r   r	   r  rN   r�   )rW   rX   r8  rn  r#   r#   r$   r�   Ó  s$    
ýü
ýüzQuestionAPIView.deleteNr/  r#   r#   r#   r$   rl  e  s   ('rl  c                   @   s   e Zd Zdd„ ZdS )ÚStudentDeleteAPIViewc              
   C   s¶   z6t jj|d�}| ¡  ttjddœd ddœtjd�W S  t jk
rj   ttjddœdd	dœtjd� Y S  t	k
r° } z*ttj
ddœdt|ƒdœtj
d� W Y ¢S d }~X Y nX d S )
Nr;   r   r   úStudent deleted successfullyr(   r   r'   TúStudent not found)r   rM   rH   r�   r   r	   r  rN   r�   rn   rJ   r.   )rW   rX   r8  r*  r™   r#   r#   r$   r�   é  s4    
ýü
ýü

ýüzStudentDeleteAPIView.deleteN)r^   r_   r`   r�   r#   r#   r#   r$   rv  ç  s   rv  )ÚCount)rL  ÚExamAttemptrM  é   r+   c                 C   s   t |ddœd || dœ|d�S )Nr   r   r4  r   r   r"   r#   r#   r$   r%     s    üûc                 C   s   t |ddœd| dœ|d�S r&   r   r)   r#   r#   r$   r*   (  s    ýüc                 C   sX   z4t | dd ƒpt | dd ƒ}|r2t |dd ƒr2|jW S W n tk
rH   Y nX |  ¡ pV| jS rN  rO  rR  r#   r#   r$   rW  0  s    rW  c              	   C   sH   z(t | ƒ d¡\}}t|ƒd t|ƒ W S  ttfk
rB   Y dS X dS )zF'30:00' -> 1800, '25:11' -> 1511. Returns 0 if the value is malformed.ú:r  r   N)r.   rk   ri   r-   r/   )r0   Úminutesr  r#   r#   r$   Úparse_duration;  s
    r~  c                 C   s4   | dkrdS | dkrdS | dkr$dS | dkr0dS d	S )
NéZ   zA+éK   ÚAr  ÚBé(   ÚCÚFr#   )Ú
percentager#   r#   r$   Ú	grade_forD  s    r‡  c                 C   s,   | j tt| jjƒd� }t|t ¡   ¡ ƒS )Nr  )	Ú
started_atr  r~  rh  rZ  ri   r  r  Útotal_seconds)ÚattemptÚdeadliner#   r#   r$   Úseconds_leftP  s    rŒ  c                 C   s†   |r|j dkrdS |r$|j dkr$dS | j dkr2dS | j dkr@dS t ¡ }| j|krhd	d
d| jd›d�fS | j|k rvdS |dkr‚dS dS )uT   Returns (state, can_start, message) â€” single source of truth for the Start button.Ú	Submitted)Ú	CompletedFr+   Ú
InProgress)r�  Tr+   Ú	Cancelled)r�  FzThis exam has been cancelled.rŽ  )ZClosedFzThis exam is closed.ZUpcomingFzThis exam opens on z%d %b %Yz$. You can start it only on that day.)ZMissedFzThe exam date has passed.r   )Ú	AvailableFz1No questions have been added for this course yet.)r‘  Tr+   )r	   r  Ú	localdaterY  )rh  rŠ  Úquestion_countÚtodayr#   r#   r$   Ú
exam_stateU  s     



r•  c                 C   sÌ   | j dkr| S tj | j¡}t|ƒ}d}| j ¡ D ]0\}}| t	|ƒ¡}|r2|r2||j
kr2|d7 }q2|rxt|d | ƒnd}|| _|| _|| _t|ƒ| _d| _ t ¡ | _|  ¡  tjj| jd�jdd� | S )z;Grade the attempt and lock it. Safe to call more than once.r�  r   r   éd   r�   rŽ  r   )r	   rM  rM   Úin_bulkÚquestion_idsÚlenÚanswersrÂ   rH   ri   rp  ÚroundÚtotal_questionsÚcorrect_countr†  r‡  Úgrader  r  Úsubmitted_atrR   rL  r“   Úexam_idÚupdate)rŠ  rs  ÚtotalZcorrectÚqidÚselectedrn  r†  r#   r#   r$   Úfinalizej  s&    



r¥  c                 C   s@   | j }| j|j|j|j|j| j| j| j| j| j	|j
t|jƒdœS )N)Ú
attempt_idr   rX  r&  rY  r�  rœ  r†  rž  rŸ  rV  rW  )rh  rA   rX  r&  rY  r�  rœ  r†  rž  rŸ  rV  rW  r*  )rŠ  rh  r#   r#   r$   Úresult_payload„  s    ôr§  c                 C   s¬   t j | j¡}g }| jD ]R}| |¡}|s,qt|jƒ}t | j	› d|j	› �¡ 
|¡ | |j	|j|dœ¡ qd| j	| j| jj| jjdœt| jjƒtt| ƒdƒt| jƒ|dœS )zAWhat the exam screen needs. Note: no `answer` field on questions.ú-)rA   rn  ro  F)rA   rX  r&  r   )Úfinishedr¦  rh  Úduration_secondsZremaining_secondsZcurrent_indexrs  )rM  rM   r—  r˜  rH   Úlistro  ÚrandomÚRandomrA   ÚshufflerÇ   rn  r   rh  rX  r&  r~  rZ  ÚmaxrŒ  r™  rš  )rŠ  rs  Úorderedr£  rr  ro  r#   r#   r$   Úattempt_payload–  s"    



ùr±  c                 C   s   t j dd¡j|| jd�S )Nrh  Úexam__student)rA   r²  )rz  rM   r[  rH   r[   )rX   r¦  r#   r#   r$   Úget_attempt­  s     ÿr³  c                   @   s   e Zd ZegZdd„ ZdS )ÚStudentExamListAPIViewc                 C   s  zàdd„ t j d¡jtdƒd�D ƒ}tjj|jd� dd¡ 	d	d
¡}g }|D ]Š}t
|dd ƒ}| |jd¡}t|||ƒ\}}	}
|j|j|j|j|jt|jƒ|||	|
d dœ}|rÌ|jdkrÌ|j|d< t|ƒ|d< | |¡ qLt|ƒW S  tk
�r } ztt|ƒƒ W Y ¢S d }~X Y nX d S )Nc                 S   s   i | ]}|d  |d “qS )r&  Únr#   )rŠ   rw   r#   r#   r$   Ú
<dictcomp>»  s   ÿ z.StudentExamListAPIView.get.<locals>.<dictcomp>r&  rA   )rµ  )r*  rŠ  r*  z-dateú-idr   )rA   rX  r&  rY  rZ  rª  r“  ÚstateÚ	can_startZstart_messageÚresultr�  r“  rº  )rM  rM   ÚvaluesÚannotatery  rL  r“   r[   r[  r’   rP  rH   r&  r•  rA   rX  rY  rZ  r~  r	   rœ  r§  rÇ   r%   rn   r*   r.   )rW   rX   Úcountsr\  r!   rh  rŠ  r“  r¸  r¹  r    r¶   r™   r#   r#   r$   rH   ¹  sH    þ ÿ þÿõ

zStudentExamListAPIView.getN©r^   r_   r`   r   rž   rH   r#   r#   r#   r$   r´  ¶  s   r´  c                   @   s   e Zd ZegZdd„ ZdS )ÚStudentExamStartAPIViewc              
   C   s|  �z@zt j d¡j||jd�}W n$ t jk
rD   tdtjƒ Y W S X t	|dd ƒ}|rj|j
dkrjtdƒW S |r®|j
dkr®t|ƒdkr t|ƒ td	t|ƒd
œƒW S tt|ƒƒW S ttjj|jd�jdd	d�ƒ}t|d t|ƒƒ\}}}|sôt|pîdƒW S t|jƒdk�rtdƒW S t |¡ tjj||t|ƒdœd�\}}	tt|ƒƒW S  tk
�rv }
 ztt|
ƒƒ W Y ¢S d }
~
X Y nX d S )Nr*  )rA   r*  ri  rŠ  r�  z%You have already completed this exam.r�  r   T)r©  rº  rU  rA   )ÚflatzThis exam cannot be started.z>Exam duration is not set correctly. Please contact your admin.)r˜  rœ  )rh  rH  )rL  rM   r[  rH   r[   rN   r*   Úhttpr�   rP  r	   rŒ  r¥  r%   r§  r±  r«  rM  r“   r&  Úvalues_listr•  r™  r~  rZ  r¬  r®  rz  Úget_or_creatern   r.   )rW   rX   r   rh  rŠ  Zpool_idsr¸  r¹  r    Ú_r™   r#   r#   r$   r]   è  s6    


þ
zStudentExamStartAPIView.postN©r^   r_   r`   r   rž   r]   r#   r#   r#   r$   r¿  å  s   r¿  c                   @   s   e Zd ZegZdd„ ZdS )ÚStudentAttemptAnswerAPIViewc           	   
   C   sr  �z6zt ||ƒ}W n$ tjk
r6   tdtjƒ Y W S X |jdkrLtdƒW S t|ƒt k rhtdtj	ƒW S zt
|j d¡ƒ}W n" ttfk
rž   tdƒ Y W S X ||jkr´tdƒW S t|ƒ}||jkrÒtdd�W S |j d	¡pàd
}|�rtjj|d� ¡ }|�r||jk�rtdƒW S ||j|< |jdgd� tdd�W S  tk
�rl } ztt|ƒƒ W Y ¢S d }~X Y nX d S )NúAttempt not foundr�  z%This exam has already been submitted.z
Time is upZquestion_idzInvalid questionzAlready answeredrG   r¤  r+   r�   zInvalid optionrš  r=   ZSaved)r³  rz  rN   r*   rÁ  r�   r	   rŒ  ÚGRACE_SECONDSÚHTTP_410_GONEri   r!   rH   r/   r-   r˜  r.   rš  r%   rM  rM   r“   rG  ro  rR   rn   )	rW   rX   r¦  rŠ  r£  Úkeyr¤  rn  r™   r#   r#   r$   r]     s8    






z StudentAttemptAnswerAPIView.postNrÅ  r#   r#   r#   r$   rÆ    s   rÆ  c                   @   s   e Zd ZegZdd„ ZdS )ÚStudentAttemptSubmitAPIViewc              
   C   s„   zLzt ||ƒ}W n$ tjk
r4   tdtjƒ Y W S X t|ƒ tt|ƒdƒW S  t	k
r~ } ztt
|ƒƒ W Y ¢S d }~X Y nX d S )NrÇ  zExam submitted)r³  rz  rN   r*   rÁ  r�   r¥  r%   r§  rn   r.   )rW   rX   r¦  rŠ  r™   r#   r#   r$   r]   >  s    z StudentAttemptSubmitAPIView.postNrÅ  r#   r#   r#   r$   rË  ;  s   rË  c                   @   s   e Zd ZegZdd„ ZdS )ÚStudentMarksheetAPIViewc              
   C   sl   z4t jj|jdd� dd¡ d¡}tdd„ |D ƒƒW S  tk
rf } ztt	|ƒƒ W Y ¢S d }~X Y nX d S )Nr�  )r²  r	   rh  r²  z-submitted_atc                 S   s   g | ]}t |ƒ‘qS r#   )r§  )rŠ   Úar#   r#   r$   rŽ   X  s     z/StudentMarksheetAPIView.get.<locals>.<listcomp>)
rz  rM   r“   r[   r[  r’   r%   rn   r*   r.   )rW   rX   Zattemptsr™   r#   r#   r$   rH   Q  s     ÿþÿzStudentMarksheetAPIView.getNr¾  r#   r#   r#   r$   rÌ  N  s   rÌ  )ÚStudentprofilesc                   @   s.   e Zd Zd
dd„Zdd„ Zdd„ Zdd	„ ZdS )ÚStudentProfileAPIViewNc           	      C   sb  |r†zXt jj|d�}ttjddœ|j|j|j|j	|j
|j|j|j|jrN|jjnd dœ	dœƒW S  t jk
r„   tdddœd	d
� Y S X t j ¡  d¡}|j dd¡ ¡ }|j dd¡ ¡ }|j dd¡ ¡ }|rÜ|j|d�}|rì|j|d�}|� rþ|j|d�}g }|D ]D}| |j|j|j|j	|j
|j|j|j|j�r>|jjnd dœ	¡ �qttjddœ|dœƒS )Nr�   r   r   )	rA   r@   rB   rE   ÚskillsÚ	educationÚ
experienceÚlocationÚresume)r	   r!   Trx  ©r   r    r  r   r·  rÐ  r+   rÓ  r@   )Zskills__icontains)Zlocation__icontainsr£   )rÎ  rM   rH   r   r	   r  rA   r@   rB   rE   rÐ  rÑ  rÒ  rÓ  rÔ  rU   rN   r‘   r’   r�   rI   r“   rÇ   )	rW   rX   rA   r*  ZstudentsZskills_qZ
location_qZname_qr!   r#   r#   r$   rH   }	  st    þÿ
õû
þýÿõþûzStudentProfileAPIView.getc                 C   sà   |j }zŽtjj| d¡| d¡| d¡| d¡| d¡| d¡| d¡|j d¡d	�}ttjd
dœd|j	|j
|j|j|j|j|j|jdœg ddœƒW S  tk
rÚ } z(ttjddœdt|ƒdœdd� W Y ¢S d }~X Y nX d S )Nr@   rB   rE   rÐ  rÑ  rÒ  rÓ  rÔ  )r@   rB   rE   rÐ  rÑ  rÒ  rÓ  rÔ  r   r   zStudent saved successfully)rA   r@   rB   rE   rÐ  rÑ  rÒ  rÓ  zMJob searching in progress. We'll notify you once matching openings are found.)r	   r    r*  ÚjobsZ
ai_messager'   Tr(   iô  r   )r!   rÎ  rM   r—   rH   rh   r   r	   r˜   rA   r@   rB   rE   rÐ  rÑ  rÒ  rÓ  rn   r  r.   )rW   rX   r!   r*  r™   r#   r#   r$   r]   Ê	  sN    
øþøî
þúùzStudentProfileAPIView.postc                 C   sì   z¾t jj|d�}|j}| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j¡|_| d|j	¡|_	| d|j
¡|_
|j d	¡r |j d	¡|_| ¡  ttjd
dœddœƒW S  t jk
ræ   tdddœdd� Y S X d S )Nr�   r@   rB   rE   rÐ  rÑ  rÒ  rÓ  rÔ  r   r   zStudent updated successfully©r	   r    Trx  rÕ  r  r   )rÎ  rM   rH   r!   r@   rB   rE   rÐ  rÑ  rÒ  rÓ  rh   rÔ  rR   r   r	   r  rN   )rW   rX   rA   r*  r!   r#   r#   r$   r›   ý	  s4    þû
þýzStudentProfileAPIView.putc                 C   s\   z.t jj|d�}| ¡  ttjddœddœƒW S  t jk
rV   tdddœd	d
� Y S X d S )Nr�   r   r   rw  r×  Trx  rÕ  r  r   )rÎ  rM   rH   r�   r   r	   r  rN   )rW   rX   rA   r*  r#   r#   r$   r�   "
  s     þû
þýzStudentProfileAPIView.delete)Nr/  r#   r#   r#   r$   rÏ  t	  s   	
M3%rÏ  )`rK   rj   rl   Údjango.contrib.authr   r   Údjango.contrib.auth.modelsr   Údjango.core.files.baser   Ú	django.dbr   Údjango.db.modelsr   Úrest_frameworkr	   Zrest_framework.viewsr
   Úrest_framework.responser   Zrest_framework.permissionsr   Zrest_framework_simplejwt.tokensr   rK  r   r   r   r   r   r   Údjango.contrib.auth.hashersr   Údjango.core.exceptionsr   Údecimalr   r   r   r5   r  r%   rJ   r*   r2   r6   r7   rb   rŸ   r§   r²   rñ   rò   ró   rô   r  Údatetimer  Údjango.utilsr  r  r  r%  r0  r;  r2  rC  rD  r9  rL  rM  rS  rT  rl  rv  r¬  ry  rÁ  rz  rÈ  rW  r~  r‡  rŒ  r•  r¥  r§  r±  r³  r´  r¿  rÆ  rË  rÌ  rÎ  rÏ  r#   r#   r#   r$   Ú<module>   sÄ    	H 	__  
& I} @n_  &			/,*  