
    byj9                         d dl Z d dlZd dlZd dlZd dlmZ d dlmZ d dlm	Z	m
Z
 d dlmZmZ dZddd	d
dZh dZg dZd Z G d dej&                        Zy)    N)escape)http)AccessErrorValidationError)content_dispositionrequestz"hr_holidays.group_hr_holidays_userconfirmvalidaterefusecancel)pendingapprovedrejected	cancelled>   full_day	part_time
first_halfsecond_half)
employee_nameleave_type_codeleave_base_type
start_dateend_datepart_time_startpart_time_endreasonstatusreviewer_notec                     | j                   xs d}d|vr|j                         j                         S |j                  dd      d   j                         j                         S )a  This deployment names leave types "Full Name . CODE" (e.g. "Annual
    Leave . AL") -- the trailing segment after the last '.' is the code,
    same convention leave_type_colors.js's leaveTypeAbbr() uses client-side
    for display; this is the server-side equivalent, used for lookup. .   )namestripupperrsplit)
leave_typer#   s     C/home/susu/odoo-hr-migration/xeno_leave/controllers/leave_import.py_leave_type_coder)   '   sV    
 ?? bD
$zz|!!##;;sAq!'')//11    c                       e Zd Z ej                  ddd      d        Z ej                  ddddg      d	        Zed
        Zed        Z	ed        Z
y)XenoLeaveImportz!/xeno_leave/leave_import/templater   user)typeauthc                    t         j                  j                  j                  t              st        d      t         j                  d   j                  g       }t        j                         }|j                  }d|_
        |j                  t               |d   D ]N  }t        j                  j                  dd      |_        t        j                  j!                  dd	
      |_        P t         j                  d   j                  dgd      }|d d }|j                  |r|j$                  nd|rt'        |      ndddddddddg
       d}t        j                  j                  d      |j)                  |dd      _        g d}t+        |      D ]  \  }	}
|j)                  ||	z   d|
        dj-                  d |D              }|j)                  |t/        |      z   dz   dd|        t1        dg d       D ]  \  }}||j2                  |   _         t7        j8                         }|j;                  |       |j=                  d!       t        j>                  |jA                         d"d#tC        d$      fg%      S )&N8Only Time Off Officers can use the Leave Request import.hr.leave.typezLeave Requestsr"   TFFFFFF)boldcolorsolid2563EB)fgColorhr.employee)active=T)limitz
John SmithALr   z6/1/2026z8/1/2026r    zSample leave reasonr      )r4   zNOTES:)rowcolumnvalue)zemployee_name: must match an existing employee's full Name exactly (case-insensitive); if two employees share a name, the row will be skipped and reported so you can tell them apartzLleave_type_code: the code after the dot in the leave type name (e.g. AL, SL)z@leave_base_type: full_day | part_time | first_half | second_halfzWpart_time_start / part_time_end: HH:MM, required only when leave_base_type is part_timezFstart_date / end_date: format D/M/YYYY, e.g. 5/1/2026 = 5 January 2026z1status: pending | approved | rejected | cancelledzreviewer_note: optionalzMA row overlapping an employee's existing leave will be skipped with an error.   , c              3   R   K   | ]  }t        |       d |j                   d ! yw)z ()N)r)   r#   ).0lts     r(   	<genexpr>z8XenoLeaveImport.leave_import_template.<locals>.<genexpr>\   s(     VB-b12"RWWIQ?Vs   %'zAvailable leave type codes: 
ABCDEFGHIJ)
      rJ      rL   rK         
      r   )Content-TypezAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetzContent-Dispositionz"Leave_Request_Import_Template.xlsxheaders)"r   envr-   	has_groupHR_OFFICER_GROUPr   searchopenpyxlWorkbookr:   titleappend_TEMPLATE_HEADERSstylesFontfontPatternFillfillr#   r)   cell	enumeratejoinlenzipcolumn_dimensionswidthioBytesIOsaveseekmake_responsereadr   )selfleave_typesworkbooksheetrb   example_employeeexample_type	notes_rownotesinotecodescolrh   outputs                  r(   leave_import_templatez%XenoLeaveImport.leave_import_template4   s]   {{))*:;XYYkk/299"=$$&&&'!H 	OD ,,$h,GDI 33GX3NDI	O #;;}5<<>S=T\]<^"2A%5!!<.:\*
JB!9b	
 	 	CK??CWCW]aCWCb

y(
;@
 !' 	@GAtJJ9q=$J?	@ 		V+VV

y3u:-1!7w? 	 	A l,TU 	7JC16E##C(.	7 fA$$KKMV&(;<`(ab
 	
r*   z/xeno_leave/leave_import/uploadPOST)r.   r/   methodsc           
        ) t         j                  j                  j                  t              st        d      	 t        j                  |d      }|j                  }|j                  d      }	 t        |      D cg c]  }t        |xs d      j                         ! }}t!        |      D 	ci c]  \  }}	|	|
 c}	})d
D 
cg c]  }
|
)vr|

 }}
|r'| j                  ddj#                  |       gdd      S dA)fd	}t         j                  d   j%                         }t         j                  d   j%                         }t         j                  d   j%                         }|j'                  g       }|D ci c]  }t)        |      | }}d}g }t!        |d      D ]*  \  }}|t+        d |D              rt         ||d            j                         }t         ||d            j                         j-                         }t         ||d      xs d      j                         j/                         }| j1                   ||d            }| j1                   ||d            }t         ||d            j                         }t         ||d      xs d      j                         j/                         }t         ||d            j                         }t         ||d            j                         }t         ||d            j                         } |s|j3                  d | d!       |s|j3                  d | d"       |r|s|j3                  d | d#       ||k  r|j3                  d | d$       |t4        vr|j3                  d | d%       |t6        vr|j3                  d | d&| d'       (|j'                  d(d)|fg      }!|!s|j3                  d | d*| d+       Yt9        |!      d,kD  r5dj#                  d- |!D              }"|j3                  d | d.| d/|" d0       |!}#|j;                  |      }$|$s|j3                  d | d1| d+       |dk7  r0|$j<                  s$|j3                  d | d.|$j>                   d2        |#j@                  |$j@                  ||||xs d3d4}%|d5k(  rC|r| s|j3                  d | d6       A| jC                  |      |%d7<   | jC                  |       |%d8<   	 t         j                  jD                  jG                         5  |jI                  dd9      jK                  |%      }&t4        |   }'|'d:k(  r|&jM                          n-|'d;k(  r|&jO                          n|'d<k(  r|&jQ                  d3=       |r|&jS                  tU        |      >       d d d        |d,z  }- | j                  ||d@      S # t        $ r | j                  dgdd      cY S w xY wc c}w # t        $ r | j                  d	gdd      cY S w xY wc c}	}w c c}
w c c}w # 1 sw Y   xY w# tV        $ r=}(|j3                  d | d?|(jX                  r|(jX                  d   n|(        Y d }(~(d }(~(wt        $ r"}(|j3                  d | d?|(        Y d }(~(d }(~(ww xY w)BNr1   T)	data_onlyz7Could not read this file -- please upload a .xlsx file.r   )errorsimported)values_onlyr    zThe file is empty.)r   r   r   r   zMissing required column(s): rC   c                 ^    j                  |      }||t        |       k\  s| |   |S | |   S N)getre   )r?   r#   defaultrw   col_idxs       r(   rb   z1XenoLeaveImport.leave_import_upload.<locals>.cell   s6    D!AyASMSV^q6Mr*   r9   r2   zhr.leaverB   )startc              3   $   K   | ]  }|d u  
 y wr    )rF   vs     r(   rH   z6XenoLeaveImport.leave_import_upload.<locals>.<genexpr>   s     !9!t)!9s   r   r   r   r   r   r   r   r   r   r   r   r   zRow z: employee_name is required.z: leave_type_code is required.z9: start_date and end_date must be valid dates (D/M/YYYY).z*: end_date must be on or after start_date.z<: status must be one of pending/approved/rejected/cancelled.z: leave_base_type 'z' is not recognized.r#   z=ilikez: Employee 'z' not found.r"   c              3   V   K   | ]!  }|j                   xs d |j                    # yw)zid N)xeno_employee_codeid)rF   ms     r(   rH   z6XenoLeaveImport.leave_import_upload.<locals>.<genexpr>   s(     !X1!"6"6"FCv,"F!Xs   ')z: 'z"' matches more than one employee (z#) -- can't tell which one, skipped.z: Leave type code 'zX' doesn't support Half-Day/Part-time (enable Flexible Duration on the leave type first).F)employee_idholiday_status_idxeno_request_unitrequest_date_fromrequest_date_tor#   r   zE: part_time_start and part_time_end are required for part_time leave.request_hour_fromrequest_hour_to)xeno_hr_direct_createtracking_disabler
   r   r   )notify_responsibles)bodyz: )r   r   )r    )-r   rT   r-   rU   rV   r   rX   load_workbook	Exception_json_responser:   	iter_rowsnextstrr$   StopIterationrc   rd   sudorW   r)   allr%   lower_to_date_strr[   _STATUS_TO_ODOO_STATE_VALID_REQUEST_UNITSre   r   xeno_flexible_durationr#   r   _to_hour_floatcr	savepointwith_contextcreate_xeno_hr_created_approve_xeno_hr_created_reject_force_cancelmessage_postr   r   args)*ro   ufilekwargsrq   rr   	rows_iterhheaderrw   r#   cmissingrb   Employee	LeaveTypeLeaverp   rG   type_by_coder   r   row_numr?   emp_name	type_code	base_typer   r   r   r   r   pt_startpt_endmatchesry   employeer'   valsleave
odoo_stateer   s*                                            @r(   leave_import_uploadz#XenoLeaveImport.leave_import_uploado   s   {{))*:;XYY	9--etDH
 OOO5		Z48ODqc!'rl((*DFD +4F*;<wq$47<\ (w&  ( (&&9$))G:L9MNO]^(` a a	 ;;}-224KK0557	J',,.&&r*;FGR(,b0GG%iq9 |	LGS{c!9S!994_56<<>HD&789??AGGIID&78FJGMMOUUWI**4\+BCJ((c:)>?Hc8,-335Fc8,9	:@@BHHJFS/ :;AACM4%678>>@Hc?34::<FWI-IJKWI-KLMXWI-fgh*$WI-WXY22WI-ijk 44WI-@K_`aoo('C&DEGWI\(<PQ7|a		!XPW!XX7)3xj 1wACD H%)))4JWI-@<XYJ&z/P/P7)3z&7 8J KL   ({{%/]]%.%/#+%D K'vMMD	 2B #C D,0,?,?,I()*.*=*=f*E&'+[[^^--/ $G "...2T / fTl  "7v!>J!Z/668#x/557#x/  +++F$**}0E*FI$GX MHy|	| ""F#KLL}  	9&&3l2m56(8 9 9	9 E 	Z&&3G2HVW'XYY	Z =(  Hh$G $GJ # WIRQVVq	/KLM WIRs34s   W% 1X >$X	"X 2X2X8=X=(Y5BYY%XX	X X/.X/Y	Y	Z=2ZZ=Z88Z=c                 @   t        | t        j                  t        j                  f      r| j                  d      S t	        |       j                         } | sy dD ]3  }	 t        j                  j                  | |      j                  d      c S  y # t        $ r Y Bw xY w)N%Y-%m-%d)z%d/%m/%Yr   )
isinstancedatetimedatestrftimer   r$   strptime
ValueError)rA   fmts     r(   r   zXenoLeaveImport._to_date_str  s     ehmmX->->?@>>*--E
  "+ 	C((11%=FFzRR	
   s   .B	BBc                 B   t        | t        j                        r| j                  | j                  dz  z   S t        |       j                         j                  d      }|r|d   rt        |d         nd}t        |      dkD  r|d   rt        |d         nd}||dz  z   S )Ng      N@:r   r"   )
r   r   timehourminuter   r$   splitintre   )rA   partsr   r   s       r(   r   zXenoLeaveImport._to_hour_float)  s    eX]]+::t 333E
  "((-"uQxCaMQ Z!^aCaMa1t8|r*   c                 X    t        j                  t        j                  |       dg      S )N)rQ   zapplication/jsonrR   )r   rm   jsondumps)payloads    r(   r   zXenoLeaveImport._json_response2  s)    $$JJw*N)OQ 	Qr*   N)__name__
__module____qualname__r   router|   r   staticmethodr   r   r   r   r*   r(   r,   r,   2   s    TZZ3&vN8
 O8
t TZZ1VV\U]^cM _cMJ  &   Q Qr*   r,   )r   ri   r   rX   
markupsafer   odoor   odoo.exceptionsr   r   	odoo.httpr   r   rV   r   r   r\   r)   
Controllerr,   r   r*   r(   <module>r      sc     	     8 27  	  N  2CQdoo CQr*   