U
    ŷig@                     @   s  d dl mZmZ d dlmZmZmZ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 d dlmZmZ d dlmZ d dlmZm Z m!Z!m"Z"m#Z#m$Z$m%Z%m&Z& d dl'm(Z( d dl)m*Z* eddgdZ+ee,ee, ee dddZ-ee.dddZ/ee.dddZ0eee.ee,ddddZ1e+j2ded ed!d"d#d$ed!d%d&ededeefe.e.ee, ee, ed'd(d)Z3e+4d*eefe"ed+d,d-Z5e+4d.eefe#ed+d/d0Z6e+4d1eefe$ed+d2d3Z7e+j2d4ee% d edeefee. ed5d6d7Z8e+j2d8e%d eefe,ed9d:d;Z9e+4d<eefe,ed9d=d>Z:e+j;d8d?d@eefe,ed9dAdBZ<e+2dCeefe,ed9dDdEZ=dS )F    )ListOptional)	APIRouterDependsHTTPExceptionQuery)Response)Session
joinedload)date)defaultdict)get_db)Employee)Company)LoanTransaction)
PayrollRunPayrollRunItem)Benefit)PayrollPreviewResponse
PayrollRowCompanySummaryPayrollExportRequestTHRExportRequestPayrollExportUnifiedRequestPayrollRunOutTHRCashAdvance)
get_or_404)build_kopramandiri_csvz/api/payrollpayroll)prefixtags)db
company_idemployee_idsreturnc                 C   sP   |  tttjttjttjtj|ktj	
|tjdktj S )NT)queryr   optionsr
   company_relloansbenefitsfilterr"   idin_activeorder_bynameall)r!   r"   r#    r1   9/var/www/html/me.goteku.com/backend/app/routes/payroll.py_get_employees_for_export   s    

r3   )empr$   c                 C   s   t dd | jD S )Nc                 s   s   | ]}|j d kr|jV  qdS r-   N)statusmonthly_deduction).0lr1   r1   r2   	<genexpr>4   s     
 z)_active_loan_deduction.<locals>.<genexpr>)sumr(   r4   r1   r1   r2   _active_loan_deduction3   s    r=   c                 C   s   t dd | jD S )Nc                 s   s   | ]}|j d kr|jV  qdS r5   )r6   monthly_benefit)r8   br1   r1   r2   r:   8   s     
 z"_active_benefit.<locals>.<genexpr>)r;   r)   r<   r1   r1   r2   _active_benefit7   s    r@   N)r!   r4   total_to_applytransaction_datedescriptionr$   c              
      s   dd |j D }|rdkr dS tdd |D  t|D ]\}} dkr|t|d k rnt|j   }qt fdd|dd	 D  }nt| }t||j}	|	dkrq:|j|	 }
t|j	|j	||d|	|
d
}|
|_|
dkrd|_
| | q:dS )zNDistribute `total_to_apply` across the employee's active loans proportionally.c                 S   s   g | ]}|j d kr|qS )r-   )r6   r8   lnr1   r1   r2   
<listcomp>C   s     
 z)_apply_loan_deduction.<locals>.<listcomp>r   Nc                 s   s   | ]}|j V  qd S N)r7   rD   r1   r1   r2   r:   G   s     z(_apply_loan_deduction.<locals>.<genexpr>   c                 3   s    | ]}t |j   V  qd S rG   )roundr7   rD   Zstandard_totalrA   r1   r2   r:   N   s   )loan_idemployee_idrB   rC   debitcreditbalancepaid)r(   r;   	enumeratelenrI   r7   minremaining_balancer   r+   r6   add)r!   r4   rA   rB   rC   Zactive_loansiloanshareZ
credit_amtnew_balancetxr1   rJ   r2   _apply_loan_deduction;   s:    

	r\   z/preview)response_model.rH      )gelei  )r_   )monthyearr"   r#   r!   c                 C   sz  | tttjttjttjtjdk}|rF|tj	|k}|rpdd |
dD }|tj|}|tj }g }tdd }	|D ]}
t|
}t|
}|
j| | }|
j	pd}|
jr|
jjnd}||	| d	< |	| d
  d7  < |	| d  |7  < |t|
j|
j|
jr$|
jjnd |
j|
j|
j||||
j	|d qdd |	 D }tdd |D }t|||dS )NTc                 S   s   g | ]}|  r|  qS r1   )strip)r8   rW   r1   r1   r2   rF   y   s      z#preview_payroll.<locals>.<listcomp>,c                   S   s   ddddS )NZUnknownr   )r/   counttotalr1   r1   r1   r1   r2   <lambda>       z!preview_payroll.<locals>.<lambda>nonez
No Companyr/   re   rH   rf   )rM   r/   	bank_nameaccount_numberaccount_namebase_salarybenefitloan_deduction
net_salaryr"   company_namec                 S   s,   g | ]$\}}t ||d  |d |d dqS )r/   re   rf   )r"   rq   employee_count	total_net)r   )r8   cidvr1   r1   r2   rF      s   c                 s   s   | ]}|j V  qd S rG   )rs   )r8   sr1   r1   r2   r:      s     z"preview_payroll.<locals>.<genexpr>)rowssummarygrand_total)r%   r   r&   r
   r'   r(   r)   r*   r-   r"   splitr+   r,   r.   r/   r0   r   r=   r@   rm   appendr   rj   rk   rl   itemsr;   r   )ra   rb   r"   r#   r!   r%   Zids	employeesrw   Zcompany_totalsr4   loan_dedrn   netrt   cnameZ	summariesry   r1   r1   r2   preview_payrollh   s\    

	r   z/export-csv)bodyr!   c                 C   s~   t |t| jd}t|| j| j}| jp,t }dd |D }t|||}d| j	 | j
dd|j d}t|dd	d
| idS )Nr   c                 S   s&   g | ]}|j |j|jt| d qS rk   r/   amount)rk   rl   rm   r=   r8   er1   r1   r2   rF      s
   z&export_payroll_csv.<locals>.<listcomp>payroll_02d_.csvtext/csvContent-Dispositionattachment; filename=content
media_typeheaders)r   r   r"   r3   r#   transfer_dater   todayr   rb   ra   r/   r   r   r!   companyr}   transferrw   csv_contentfilenamer1   r1   r2   export_payroll_csv   s    	r   z/export-thrc                 C   sv   t |t| jd}t|| j| j}| jp,t }dd |D }t|||}d| j	 d|j
 d}t|ddd	| id
S )Nr   c                 S   s   g | ]}|j |j|jd qS r   )rk   rl   rm   r   r1   r1   r2   rF      s
   z"export_thr_csv.<locals>.<listcomp>thr_r   r   r   r   r   r   )r   r   r"   r3   r#   r   r   r   r   rb   r/   r   r   r1   r1   r2   export_thr_csv   s    	r   z/exportc                 C   s  t |t| jd}t|| j| j}dd | jD }dd | jD }t }g }g }|D ]}	| j	dkr|
|	jd}
d}d}|	j|
 }|
dk}nDd}
t|	}t|	}|	j|kr||	j }d}n|}d}|	j| | }| j	dkrtd|n|}|dkr||	j|	j|d	 ||	j|	j|	j|	j|	j|||
||d

 qTtdd |D }t| j| j| j	| j|j|t|dd}|| |  |D ]$}tf d|ji|}|| q|  t|||}| j	dkrd| j d|j d}nd| j | jdd|j d}t|ddd| idS )a  
    Unified payroll/THR export endpoint.
    - export_type "regular": base_salary minus loan deductions (with per-employee overrides)
    - export_type "thr": base_salary only, no deductions
    - Transfer date = today (date of actual export)
    - Loan transactions are NOT recorded here; use POST /runs/{id}/run to record them.
    Always creates a PayrollRun record for audit history.
    r   c                 S   s   i | ]}|j |jqS r1   )rM   ro   )r8   or1   r1   r2   
<dictcomp>   s      z"export_unified.<locals>.<dictcomp>c                 S   s   i | ]}|j |jqS r1   )rM   cash_advance)r8   car1   r1   r2   r      s     thrr   TFr   )
rM   employee_namerl   rk   rm   rn   ro   r   
net_amounthas_overridec                 s   s   | ]}|d  V  qdS )r   Nr1   )r8   rr1   r1   r2   r:   "  s     z!export_unified.<locals>.<genexpr>)ra   rb   export_typer"   rq   total_amountrr   recorded_transactionsrun_idr   r   r   r   r   r   r   r   r   )r   r   r"   r3   r#   	overridesthr_cash_advancesr   r   r   getr+   rm   r=   r@   maxr{   rk   rl   r/   r;   r   ra   rb   rS   rV   flushr   commitr   r   )r   r!   r   r}   Zoverride_mapZcash_advance_mapr   csv_rowsZrun_items_datar4   Zemp_cash_advancer~   rn   r   Zis_overrideZstandard_dedr   r   runZ	item_dataitemr   r   r1   r1   r2   export_unified   s    









r   z/runs)rb   r!   c                 C   s>   | tttj}| r*|tj| k}|tj	 
 S )zJReturn all payroll export runs, optionally filtered by year, newest first.)r%   r   r&   r
   r|   r*   rb   r.   run_datedescr0   )rb   r!   r%   r1   r1   r2   list_payroll_runsE  s    r   z/runs/{run_id})r   r!   c                 C   s:   | tttjtj| k }|s6tddd|S )z/Return a single payroll run with all its items.  Payroll run not foundstatus_codedetail)	r%   r   r&   r
   r|   r*   r+   firstr   r   r!   r   r1   r1   r2   get_payroll_runQ  s    
r   z/runs/{run_id}/runc                 C   s  | tttjtj| k }|s6tddd|j	rHtddd|j
 }|jdkr|jD ]z}|jrb|jdkrxqb| tttjtj|jk }|sqb|jrdnd	}t|||j|d
|j d|jd|  qbd|j d|jd}nd|j }d|_	|  d|iS )a"  
    Record loan deduction transactions for a previously exported payroll run.
    Uses the stored loan_deduction per item and distributes it across the
    employee's current active loans proportionally.
    Can only be called once (no-op is prevented via recorded_transactions flag).
    r   r   r     z4Transactions have already been recorded for this runZregularr   z (adjusted) zPayroll deduction /r   zLoan transactions recorded for zTHR marked as executed for Tmessage)r%   r   r&   r
   r|   r*   r+   r   r   r   r   r   r   rM   ro   r   r(   r   r\   rb   ra   r   )r   r!   r   Ztx_dater   r4   suffixr   r1   r1   r2   run_payroll_transactions_  sH    	





r      )r   c                 C   sR   | ttj| k }|s*tddd|jr<tddd|| |  dS )z
    Delete a payroll export run. Only allowed if transactions have NOT been recorded.
    Once 'Run' has been executed, the run is locked and cannot be deleted.
    r   r   r   r   zOCannot delete a run that has already been executed (loan transactions recorded)N)	r%   r   r*   r+   r   r   r   deleter   r   r1   r1   r2   delete_payroll_run  s    
r   z/runs/{run_id}/downloadc                 C   s   | tttjtj| k }|s6tddd| t	t	j|j
k }|sbtddd|j }dd |jD }t|||}|jdkrd|j d	|j d
}nd|j |jdd	|j d
}t|ddd| idS )zDRegenerate and return the CSV for a previously recorded payroll run.r   r   r   zCompany no longer existsc                 S   s(   g | ] }|j pd |jp|j|jdqS )r   r   )rk   rl   r   r   )r8   r   r1   r1   r2   rF     s
   
z(download_payroll_run.<locals>.<listcomp>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   rb   r/   ra   r   )r   r!   r   r   r   r   r   r   r1   r1   r2   download_payroll_run  s0    

	
r   )>typingr   r   fastapir   r   r   r   fastapi.responsesr   sqlalchemy.ormr	   r
   datetimer   collectionsr   app.core.databaser   app.models.employeer   app.models.companyr   app.models.loan_transactionr   app.models.payroll_runr   r   app.models.benefitr   app.schemas.payrollr   r   r   r   r   r   r   r   app.helpers.crudr   Zapp.helpers.csv_exportr   routerstrr3   intr=   r@   r\   r   r   postr   r   r   r   r   r   r   r   r   r1   r1   r1   r2   <module>   s~   (
-
Bg6