
    vgK                     R   d 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lmZmZmZmZmZ dd	lmZmZ dd
lmZ ddlmZmZmZ d Zd Z ej>                  d      rd Z d Z!d Z"d Z#de$fdZ%d Z&	 	 ddZ'	 	 	 	 	 ddZ(	 	 	 	 	 	 	 d dZ)d Z*d!dZ+d Z,d Z-d Z.y)"zH
methods.py

Payroll related module to write custom calculation methods
    N)datedatetime	timedeltarelativedelta)apps)	Paginator)FQ)get_company_leave_datesget_date_rangeget_holiday_datesget_paginationget_working_days)CompanyLeavesHolidays)get_horilla_model_class)Contract	DeductionPayslipc                 .    || z
  }|j                   dz   }|S )a  
    Calculates the total number of days in a given period.

    Args:
        start_date (date): The start date of the period.

        end_date (date): The end date of the period.
    Returns:
        int: The total number of days in the period, including the end date.

    Example:
        start_date = date(2023, 1, 1)
        end_date = date(2023, 1, 10)
        days_on_period = get_total_days(start_date, end_date)
       days)
start_dateend_datedelta
total_dayss       +/var/www/horilla/payroll/methods/methods.pyget_total_daysr       s!      z!EaJ    c                    t        j                  d      r| j                  j                  d      }nd}d}d}d}d}g }g }	t	        ||      d   }
|r|j                         r|D ]~  }|j                  j                  dk(  r2|j                         }||D cg c]  }||cxk  r|k  rn n| c}z   }N|j                         }|	|D cg c]  }||cxk  r|k  rn n| c}z   }	 t               }|d   }|d	   }t        t        |      t        |
      z
        }t        t        |	      t        |
      z
        }	t        |      |z
  }t        |	      |z
  }||||z   ||	|	|z   d
S c c}w c c}w )a  
    This method is used to return all the leaves taken by the employee
    between the period.

    Args:
        employee (obj): Employee model instance
        start_date (obj): the start date from the data needed
        end_date (obj): the end date till the date needed
    leaveapproved)statusNr   company_leave_datespaidhalf_unpaid_leaveshalf_paid_leaves)
paid_leaveunpaid_leavestotal_leavespaid_leave_datesunpaid_leave_datesleave_dates)r   is_installedleaverequest_setfilterr   existsleave_type_idpaymentrequested_datesfind_half_day_leaveslistsetlen)employeer   r   approved_leavesr*   unpaid_leave	paid_halfunpaid_halfr-   r.   r&   instanceall_the_paid_leave_taken_datesr   all_unpaid_leave_taken_dateshalf_day_datas                   r   
get_leavesrD   1   s    !"33::*:MJLIK*:x@AVW?113' 	H%%--7 2:1I1I1K.#3 >7!T5X5 7 $  08/G/G/I,%7 <;!T5X5 ; &"	( )*M 45K01IC 01C8K4LLMc"45<O8PPQ%&2J)*[8L !%"\1,0),<<	 	37;s   E$E)
attendancec                    t        dd      }|j                  j                  | ||fd      }|D cg c]  }|j                   }}t	        ||      d   }t        | ||      d   }t        t        |      t        |      z
  t        |      z
        }	|	|D 
cg c]Q  }
|
t        ||      v s?|
t        t        t        |j                        t        |j                        z               v r|
S c}
z   }	|||	dS c c}w c c}
w )a   
        This method is used to render attendance details between the range

        Args:
            employee (obj): Employee user instance
            start_date (obj): start date of the period
            end_date (obj): end date of the period
        rE   )	app_labelmodelT)employee_idattendance_date__rangeattendance_validatedworking_days_onr/   )attendances_on_period
present_onconflict_dates)r   objectsr2   attendance_dater   rD   r8   r9   r   r   year)r;   r   r   
AttendancerM   rE   rN   working_days_between_ranger/   rO   r   s              r   get_attendancerU   t   s=    -|<X
 * 2 2 9 9 $.#9!% !: !
 :O
+5J&&

 
 &6j(%K&
" !:x@O*+'()+

 ("+
(X>>+JOO<-hmm<= +
 
 &;$,
 	
3
+
s   C8AC=c                     t        j                  d      sdddS t        | ||      }|d   }d}|D ]  }||j                  |j                  z
  z   }  |dz  }t        ||z  d      }	|	dt        |      ddS )
    Hourly salary computation for period.

    Args:
        employee (obj): Employee instance
        wage (float): wage of the employee
        start_date (obj): start of the pay period
        end_date (obj): end date of the period
    rE   r   )	basic_payloss_of_payrM   i  z.2frX   rY   	paid_daysunpaid_days)r   r0   rU   at_work_secondovertime_secondfloatr:   )
r;   wager   r   attendance_datarM   total_worked_hour_in_secondrE   wage_in_secondrX   s
             r   hourly_computationrd      s     \*
 	
 %Xz8DO+,CD"#+ 

&A%%
(B(BB'
#
 D[N.+FFLNI ./	 r!   c            
         g } g }t        t        dt        t        |                         }t        t        dt        t        |                        }t        |      dz  }t        |      dz  }||z   }t        |      dz  }||||dS )z
    This method is used to return the half day leave details

    Args:
        employee (obj): Employee model instance
        start_date (obj): start date of the period
        end_date (obj): end date of the period
    N      ?)half_day_query_sethalf_day_leavesr)   r(   )r8   r2   r9   r:   )paid_querysetunpaid_querysetpaid_leavesr+   r>   r?   querysetr,   s           r   r7   r7      s     MOvdD]);$<=>Kd3+?&@ABMK 3&Im$s*K]*Hx=4'L&'%)	 r!   c                    t        ||      }|d   }t        | ||      }| j                  j                  d      j	                         }||z  }d}	t        ||      }
| j                  j                  d|
d      j                  d	      j                         }| j                  j                  d|
d
      j                  d      j                  t        d            j                         }||z   dz  }| j                  j                  dd      j	                         }|d   |z
  }|j                  r||z  }	n|j                  }||z  }	|j                  r||	z
  }||	||dS )rW   total_working_daysactivecontract_statusr   unpaidr$   leave_type_id__paymentstart_date__inr%   full_daystart_date_breakdownrt   end_date__inr%   end_date_breakdownr   r   rf   T	is_activerq   r+   rZ   )r   rD   contract_setr2   firstr   r1   excludecountr
   calculate_daily_leave_amountdeduction_for_one_leave_amountdeduct_leave_from_basic_pay)r;   r`   r   r   working_day_datarn   
leave_datacontractrX   rY   
date_range,half_day_leaves_between_period_on_start_date*half_day_leaves_between_period_on_end_dateunpaid_half_leavesr+   fixed_penaltys                   r   daily_computationr      s    (
H=)*>?Hj(;J$$++H+EKKMH))IK
H5J!!((#+% 	) 	

 
j	1	 1 	!!((#+*Z 	) 	
 
J	/	AjM	*	 / 	5
4	5
 $$++ , eg  /2DDM,,$, ??$5+++	 "'$	 r!   returnc                    t        j                  |j                  |j                        d   }t	        |j                  |j                  |      }t	        |j                  |j                  d      }t        ||      d   }| |z  }d|iS )zD
    This method is used to calculate daily salary for the date
    r   rn   day_wage)calendar
monthrangerR   monthr   r   )r`   	wage_datelast_dayr   r   working_daysr   s          r   get_daily_salaryr   "  s|     ""9>>9??CAFHINNIOOX>Hinniooq9J#J9:NOLl"H 	H r!   c           
         g }fdt        |j                  j                  z
  dz  |j                  z   j                  z
  dz         D        D ]  }|j                  }|j                  }|t        dd      z   t        d      z
  j                  }|t        |      z   }t        ||      }t        |j                  d      |j                  |            d   }	t        ||d      k  rt        ||d      n}
t        |
|      d   }||||
j                  d	      |j                  d	      ||	| |	z  d
}|j                  |       |t        dd      z   j                  d      } |S )z>
    This method is used to find the months between range
    c              3   <   K   | ]  }t        |       z     yw))monthsNr   ).0ir   s     r   	<genexpr>z'months_between_range.<locals>.<genexpr>7  s#       	]!,,s      r   )dayr   r   )r   rn   )rR   r   r   z%Y-%m-%d)r   rR   r   r   r   working_days_on_periodworking_days_on_monthper_day_amount)rangerR   r   r   r   minr   replacer   strftimeappend)r`   r   r   months_datacurrent_dater   rR   days_in_monthcurrent_end_dater   month_start_datetotal_working_days_on_period
month_infos    `           r   months_between_ranger   1  s    K]]Z__,2nn 
 /V ""   =Qq99Mq<QQ
# 	
 (-M*JJ/: 0  Q ')=)=-)=)P!

!  Dd%Q?? d%Q/ 	
 (8.(

( $
 !*33J?(11*=&B%:"#$

 	:&$}1'EENNSTNU_/Vb r!   c                     |S )z
    Compute yearly taxable amount custom logic
    eg:
        default_yearly_taxable_amount = monthly_taxable_amount * 12
     )monthly_taxable_amountdefault_yearly_taxable_amountargskwargss       r   compute_yearly_taxable_amountr   k  s
     )(r!   c                     | S )z5
    Method to convert yearly taxable to monthly
    r   )federal_tax_for_period
yearly_taxr   r   r   r   r   s          r   convert_year_tax_to_periodr   y  s
     "!r!   c                     | S )z,
    Compute net pay | Additional logic
    r   )	net_pay	gross_paytotal_pretax_deductiontotal_post_tax_deductiontotal_tax_deductionsfederal_taxloss_of_pay_amountr   r   s	            r   compute_net_payr     s	     Nr!   c                 h   d}t        |||      }t        | ||      }|D ]  }||d   |d   z  z   } | j                  j                  d      j	                         }d}	t        ||      }
t        j                  d      r| j                  j                  d|
d	      j                  d
      j                         }| j                  j                  d|
d      j                  d
      j                  t        d            j                         }nd}d}|}|}||z   dz  }| j                  j                  dd      j	                         }t        |d   |z
        }|d   d   |z
  }t        ||      d   }|j                  r||z  }	n|j                  }||z  }	|j                   r||	z
  }||	|||dS )rW   r   r   r   ro   rp   r#   rr   r$   rs   rv   rw   ry   r{   r   r}   rf   Tr~   r+   )r`   r   r   )rX   rY   
month_datar\   r[   )r   rD   r   r2   r   r   r   r0   r1   r   r   r
   absr   r   r   r   )r;   r`   r   r   rX   r   r   datar   rY   r   start_date_leavesend_date_leavesr   r   r   r+   r[   daily_computed_salaryr   s                       r   monthly_computationr     s    I%dJAJHj(;J 
)*T2B-CC
	

 $$++H+EKKMHK
H5J!%%,,'/)! - 
 W*W5UW 	 %%,,'/'! - 
 W
W3W*W.UW 	 3D01@. 	5
4	5
 $$++ , eg  
?36HHIM167-GI,$*M ,,$(== ??$5+++	" $ r!   c                 p   t         j                  j                  | d      j                         }||S ||j                  n|}|j
                  }d}|dk(  r!t        | |||      }t        |||      }||d<   n4|dk(  r!t        | |||      }t        |||      }||d<   nt        | |||      }||d<   ||d<   |S )	z
    This method is used to compute salary on the start to end date period

    Args:
        employee (obj): Employee instance
        start_date (obj): start date of the period
        end_date (obj): end date of the period
    ro   )rI   rq   Nhourlyr   dailycontract_wager   )
r   rP   r2   r   r`   	wage_typerd   r   r   r   )r;   r   r   r`   r   r   r   r   s           r   compute_salary_on_periodr     s     &&h ' eg   L8==dD""IDH!(D*hG)$
HE
'\	g	 4XF)$
HE
'\ #8T:xH DDKr!   c                 P    t        | t                     }|j                  |      } | S )z2
    This method is used to paginate queryset
    )r	   r   get_page)qrysetpage_number	paginators      r   paginator_qryr     s(     &."23I,FMr!   c                    | d   }|j                  d      |j                  d      |j                  d      |j                  d      g}|D ]  }|s|D ]  }|j                  d      s|j                  dd      dkD  s+t        j                  j                  |j                  d      	      j	                         }|sk|j                  |j
                        }||j                  z  d
z  }|j
                  |d<   ||d<     | S )zD
    This method is used to calculate the employer contribution
    pay_datapretax_deductionspost_tax_deductionstax_deductionsnet_deductionsdeduction_idemployer_contribution_rater   )idd   based_onemployer_contribution_amount)getr   rP   r2   r   r   employer_rate)r   pay_head_datadeductions_to_process
deductions	deductionobjectamountr   s           r   calculate_employer_contributionr     s    $M-./0*+*+	 , 
' 	MM.1!&BAFJ&..55$==8 6 eg  !.!2!26??!C"V%9%998 4 17	*-8 ""@A& Kr!   c                  H   t         j                  j                  | d   | d   | d         j                         }||n	t               }| d   |_        | j                  d      |_        | d   |_        | d   |_        | d   |_	        t        | d   d      |_        t        | d	   d      |_        t        | d
   d      |_        t        | d   d      |_        t        | d   d      |_        | d   |_        |j#                          |j$                  j'                  | d          |S )z;
    This method is used to save the generated payslip
    r;   r   r   )rI   r   r   
group_namer%   rX      r   r   r   r   r   installments)r   rP   r2   r   rI   r   r   r   r   r%   roundrX   r   r   r   r   r   saveinstallment_idsr9   )r   filtered_instancer@   s      r   save_payslipr   8  s.     ..:&,'
# /  eg	 
 %6$A wyH!*-H **\2H .Hz*HX&HOvk2A6H"6/#:A>Hvk2A6Hvk2A6HVI.2H#J/HMMO  !78Or!   )NN)NNNNN)NNNNNNN)N)/__doc__r   r   r   r   dateutil.relativedeltar   django.appsr   django.core.paginatorr	   django.db.modelsr
   r   base.methodsr   r   r   r   r   base.modelsr   r   horilla.methodsr   payroll.models.modelsr   r   r   r    rD   r0   rU   rd   r7   r   dictr   r   r   r   r   r   r   r   r   r   r   r!   r   <module>r     s     . . 0  + !  0 3 > >*>B 4\",
^!H6=@ 7v  "&)  "  !$NbDDr!   