a
    3j	                    @   s  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mZm	Z	m
Z
mZmZmZmZ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 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)m*Z* d dl+m,Z,m-Z-m.Z.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4 d dl5m6Z6 d dl7m8Z8m9Z9m:Z:m;Z;m<Z<m=Z= e  ee>Z?e?j#@e* e jABde?j#d< e?j#d s|eCde6De? ee?ZEdeE_FejGejHd e?jIJejH d dl7m6Z6mKZKmLZLmMZMmNZNmOZOmPZPmQZQm=Z=mRZRmSZSmTZTmUZUmVZVm8Z8m9Z9m:Z:m;Z;m<Z< eEjWdd ZXdd ZYe?Zddd Z[e?jZdddgdd d Z\e?Zd!ed"d# Z]e?Zd$ed%d& Z^e?Zd'eeYe$gd(d) Z_e?jZd*ddgdeeYe$e%e&e)gd+d, Z`e?jZd-ddgdd.d/ Zae?jZd0dgdeeYe$e&e)gd1d2 Zbe?Zd3eeYe$e%e&e)gd4d5 Zcd6d7 Zde?jZd8ddgdeeYe$e%e&e'e)gd9d: Zee?jZd;dgdeeYe$e%e&e'e)gd<d= Zfe?Zd>eeYe$e%e&e'e)gd?d@ Zge?jZdAddgdeeYe$gdBdC Zhe?jZdDddgdeeYe$e%e&e)gdEdF Zie?jZdGdgdeeYe$e%e&e)gdHdI Zje?jZdJdgdeeYe$e&gdKdL ZkdMdN Zle?jZdOddgdeeYe$e&e)e%gdPdQ Zme?jZdRdgdedSdT Zne?jZdUdgdedVdW Zoe?jZdXdgdedYdZ Zpe?jZd[dgded\d] Zqe?jZd^ddgdeeYe$e%e)gd_d` Zre?jZdaddgdeeYe$e(gdbdc Zse?jZddddgdededf Zte>dgkre?judhdie jABdjdkkdl dS )m    N)generate_evaluation_pdf)datetime)
Flaskrender_templateredirecturl_forflashrequestabortjsonifycurrent_app	send_file)LoginManager	UserMixin
login_userlogout_usercurrent_userlogin_required)	FlaskForm)secure_filename)load_dotenvwraps)or_)IntegrityError)ADMIN_ROLE_IDGERENTE_ROLE_IDSUPERVISOR_ROLE_IDEVALUADO_ROLE_IDTALENTO_HUMANO_ROLE_IDDIRECTOR_ROLE_IDConfig)		LoginFormOdiFormAssignOdiFormEditUserFormSearchUserByCedulaFormAssignLocationFormAssignCursosFormTalentoHumanoObservationFormChangePasswordForm)db)LocalizacionDivisionesGeneralesUnidadesGerenciasGeneralesCoordinacionesUbicacionPersonal
SECRET_KEYz>No SECRET_KEY set for Flask application. Check your .env file.login)level)r+   UserRolAno	TrimestreOdiRangoOdiPersonalr1   CompetenciaCompetenciaPersonalEscala
EvaluacionCursoPersonalr,   r-   r.   r/   r0   c                 C   s   t jt| S )N)r5   querygetint)user_id rE   /var/www/html/evaluacion/app.py	load_user/   s    rG   c                    s    fdd}|S )z
    A decorator to restrict access to routes based on user roles.
    `role_ids` should be a list of integer role IDs that are allowed to access the route.
    c                    s   t   fdd}|S )Nc                     sT   t jstdd ttdS t jd u s0t jvrFtdd ttdS  | i |S )Nu2   Debes iniciar sesión para acceder a esta página.warningr3   u.   No tienes permiso para acceder a esta página.danger	dashboard)r   is_authenticatedr   r   r   id_rol)argskwargs)frole_idsrE   rF   decorated_function:   s    

z<role_required.<locals>.decorator.<locals>.decorated_functionr   )rO   rQ   rP   )rO   rF   	decorator9   s    z role_required.<locals>.decoratorrE   )rP   rS   rE   rR   rF   role_required4   s    rT   /c                   C   s   t jsttdS ttdS )Nr3   rJ   )r   rK   r   r   rE   rE   rE   rF   homeK   s    rV   z/loginGETPOST)methodsc                  C   s   t jrttdS t } |  rtjj| j	j
d }|r|| jj
r|jr|jtkrtjj|jd }|stdd ttdS t| tdd tjd	}t|ptdS |r|jstd
d n
tdd tdd| dS )NrJ   )usuarioid_personaluS   No tiene una ubicación asignada. Por favor, contacte con un Gerente/Administrador.rI   r3   u   Inicio de sesión exitoso.successnextu?   Tu cuenta está inactiva. Por favor, contacta al administrador.u"   Usuario o contraseña incorrectos.z
login.htmlu   Iniciar Sesión)titleform)r   rK   r   r   r"   validate_on_submitr5   rA   	filter_byusernamedatafirstZcheck_passwordpasswordZactiverL   r   r1   r\   r   r   r	   rM   rB   r   )r`   user	ubicacionZ	next_pagerE   rE   rF   r3   V   s&    




z/logoutc                   C   s   t   tdd ttdS )Nu   Has cerrado sesión.inforV   )r   r   r   r   rE   rE   rE   rF   logoutn   s    
rj   z
/dashboardc                   C   s   t dddS )Nzdashboard.htmlZ	Dashboardr_   r   rE   rE   rE   rF   rJ   u   s    rJ   z/admin_panelc                  C   sp   t jttttjtjk } g }| D ]8\}}||j	|j
|j|j|j|j|j|j|jd	 q*td|dS )N)	r\   cedulanombreapellidonacionalidadestaturL   Zrol_descripcionrc   zadmin_panel.html)Zpersonal)r+   sessionrA   r5   r6   joinrL   allappendr\   rm   rn   ro   rp   rq   descripcionrZ   r   )Zpersonal_with_rolesZ
users_dataZpersonal_userZrol_objrE   rE   rF   admin_panelz   s"    
rw   z/manage_odisc               
   C   s  t  } tjtkr$tjtj }ntjj	tj
dtj }| jjr|  rzZtjj	tj
d }t| jj| jjtj
d}tj| tj  tdd ttdW S  ty } z<tj  td| d tjjd| d	d
 W Y d }~n
d }~0 0 ntjdkrdtjv rtjj dt!d}tj |}|rtjtks\|j
tj
krzDt"jj	|d r~tdd n tj#| tj  tdd W n@ ty } z&tj  td| d W Y d }~n
d }~0 0 n
tdd n
tdd ttdS t$d| |dS )Nr[   )rv   pesor\   u   ¡ODI añadido exitosamente!r]   manage_odisu   Error al añadir ODI: rI   zError adding ODI: Texc_inforX   deleteZodi_id_to_edittypeid_odiuU   No se puede eliminar este ODI porque ya está asignado a personal en una evaluación.rH   u   ¡ODI eliminado exitosamente!Error al eliminar ODI: z)No tienes permiso para eliminar este ODI.zODI no encontrado.zmanage_odis.html)r`   all_odis)%r#   r   rL   r   r9   rA   order_byrv   rt   rb   r\   Zsubmitrd   ra   r1   re   rx   r+   rr   addcommitr   r   r   	Exceptionrollbackapploggererrorr	   methodr`   rB   rC   r;   r|   r   )r`   r   locZnew_odieodi_idZodi_to_deleterE   rE   rF   ry      sT    



.

(
ry   z/edit_odi/<int:odi_id>c                 C   s   t j| }t|d}tjj| d d u}| r|rV|j|j_	|j
|j
_	tdd || tj  tdd ttdS td|||d	S )
Nobjr   z@No se puede modificar el peso de un ODI que ya ha sido asignado.rI   zODI actualizado exitosamente.r]   ry   zedit_odi.html)r`   odiis_assigned)r9   rA   
get_or_404r#   r;   rb   re   ra   rv   rd   rx   r   Zpopulate_objr+   rr   r   r   r   r   )r   r   r`   r   rE   rE   rF   edit_odi   s    






r   z/delete_odi/<int:odi_id>c              
   C   s   t j| }zDtjj|jd r.tdd n tj	
| tj	  tdd W nZ ty } zBtj	  td| d tjjd|  d| d	d
 W Y d }~n
d }~0 0 ttdS )Nr   zWNo se puede eliminar el ODI porque tiene asignaciones de ODIs personalizadas asociadas.rI   zODI eliminado exitosamente.r]   r   zError deleting ODI : Trz   ry   )r9   rA   r   r;   rb   r   re   r   r+   rr   r|   r   r   r   r   r   r   r   r   )r   r   r   rE   rE   rF   
delete_odi   s    

2r   z/supervisor_pagec                   C   s   t dddS )Nzsupervisor_page.htmlu   Página de Supervisorrk   rl   rE   rE   rE   rF   supervisor_page  s    r   c                 C   s  g }d}|dkr|dkrt jj| ||dtt jtjktt jtjkt j	 }|D ]f}zt
|jj}W n ty   d}Y n0 t
|jj}||jj|jj||jj|d ||| 7 }qZg }	d}
|dkr|dkrtjj| ||dttjtjkttjtjktj	 }|D ]j}zt
|jj}W n tyL   d}Y n0 t
|jj}|	|jj|jj||jj|d |
|| 7 }
q ||
 }|}d}d}|dkr|dkr|dkrtjj| ||d d u}|dkr&|s&tjtjdktj  }|r&||jkr&t
|j}|dkrltjtj|ktj|ktjd B  }|rh|j}nd}d }d	}d
}|dkr|dkrtjj| ||d }|r|j}|j pd	}|j!r|j!j"}|t#t
|d|	t#t
|
dt#t
|d|||||d
S )N        r\   id_anoid_trimestre)idrv   rx   rango_descripcionZrango_valorN/AFr   zFuera de Escala Definida zNo disponible   )
assigned_odistotal_odi_scoreassigned_competenciastotal_competencia_scoretotal_evaluacion_scoreescala_remarkevaluacion_aprobacionevaluacion_observacion
has_courseevaluador_name)$r;   rA   rb   rs   r9   r   r:   id_rangor   rt   floatrangorv   
ValueErrorr   rx   ru   r=   r<   id_competenciacompetenciar@   re   r>   filterrequiere_cursomaximodescZminimois_r?   
aprobacionobservacionZ	evaluador	full_nameround)rD   ano_idtrimestre_idr   r   Zodi_assignments
assignmentrango_valueodi_pesor   r   Zcompetencia_assignmentscompetencia_pesor   final_evaluacion_scorer   r   highest_safe_escalaZmatched_escalar   r   r   existing_evaluacionrE   rE   rF   get_evaluado_data  s    




r   z/evaluado_pagec               	   C   s   t j} tjtjtjtj	 
 }dd |D }tjtjtjtj 
 }dd |D }d}d}tjdkrttjdd}ttjdd}|dks|dkrt| ||}	t|	S t| ||}	t|	S t| ||}
tdd	|||||
d
S )Nc                 S   s   g | ]}|j |jd qS )r   descriptionr   rv   ).0yrE   rE   rF   
<listcomp>      z!evaluado_page.<locals>.<listcomp>c                 S   s   g | ]}|j |jd qS r   r   rv   )r   trE   rE   rF   r     r   r   rX   r   r   zevaluado_page.htmlu   Página de Evaluación Personal)r_   Zyears
trimestersinitial_ano_idinitial_trimestre_idinitial_data)r   r\   r+   rr   rA   r7   r   rv   r   r   rt   r8   r   Zascr	   r   rC   jsonrB   r   r   r   )rD   Zunique_years_queryZyears_for_dropdownZunique_trimesters_queryZtrimesters_for_dropdownr   r   Zselected_ano_idZselected_trimestre_idrd   r   rE   rE   rF   evaluado_page  s:    
r   z/save_evaluacion_feedbackc            
   
   C   sP  t  } tj}t| d}t| d}| d}| dd }|d u r^tdddd	fS |du r||s|tdd
dd	fS z~tj	j
|||d }|r||_||_tj| d}n(t|||g g ||dd}tj| d}tj  td|ddfW S  tyJ }	 z6tj  td|	  tddddfW  Y d }	~	S d }	~	0 0 d S )Nr   r   r   r   r   Fu   Aprobación no especificada.)r]   message  u4   La observación es requerida si no está de acuerdo.r   u1   Feedback de evaluación actualizado exitosamente.)r\   r   r   ids_odi_personalids_competencia_personalr   r   	ids_cursou.   Feedback de evaluación guardado exitosamente.T   z"Error saving evaluation feedback: z%Error interno al guardar el feedback.  )r	   get_jsonr   r\   rC   rB   stripr   r?   rA   rb   re   r   r   r+   rr   r   r   r   r   print)
rd   Zuser_personal_idr   r   r   r   r   r   Znew_evaluacionr   rE   rE   rF   save_evaluacion_feedback  sN    




r   z-/generate_pdf/<int:ano_id>/<int:trimestre_id>c           	   
   C   s   t tj| |}tj| }tj|}|r4t|jnd}d}tj	rRtj	j
dkrRd}t|tjtj||dd|rxt|jnd||d}tdtj d|rt|jnd	 d|rt|jnd
 d}t|d|ddS )Nr   r      ZCaracasr   )rd   Zcolaborador_nameZcolaborador_cedulaperiodo_descr   Zano_descr   	city_nameZEvaluacion__yearZ	trimesterz.pdfFzapplication/pdf)as_attachmentdownload_namemimetype)r   r   r\   r7   rA   rB   r8   strrv   rh   id_localizacionr   r   rm   rZ   r   )	r   r   rd   ano	trimestrer   r   bufferfilenamerE   rE   rF   generate_pdf  s0    
:r   z/admin/edit_user/<int:user_id>c              
   C   s  t j| }t|d}tjdkr8t|j|j_|j	|j	_|
 rntd t|jj}td| dt| d |dk|_td|j d	t|j d |jjr||jj td
 |j	j|_	z<tj  td td|j d|j dd ttdW S  tyj } zTtj  td|  tdt| d tjjd|  d| dd W Y d }~n
d }~0 0 n`tjdkrtd |j D ]\}}td| d|  qtd|jj dt|jj d td||dS )Nr   rW   zCDEBUG: form.validate_on_submit() returned TRUE. Proceeding to save.zIDEBUG: On POST, submitted_estatu_value (after explicit str conversion): 'z	' (Type: )Truez5DEBUG: On POST, user.estatu (calculated for saving): z (Type: z<DEBUG: Password data present, password hash will be updated.z&DEBUG: db.session.commit() successful.Usuario  z actualizado exitosamente.r]   rw   z'DEBUG: !!! EXCEPTION DURING DB COMMIT: z Error al actualizar el usuario: rI   zError updating user r   Trz   rX   z&DEBUG: Form validation failed. Errors:z	  Field '': z7DEBUG: On POST (validation failed), form.estatu.data: 'zedit_user.html)r`   rg   )r5   rA   r   r%   r	   r   r   rq   rd   rL   ra   r   r~   rf   set_passwordr+   rr   r   r   rn   ro   r   r   r   r   r   r   r   errorsitemsr   )rD   rg   r`   Zsubmitted_estatu_valuer   
field_namer   rE   rE   rF   	edit_user  s>    







4"r   z/assign_odic            $   
   C   s  t  } tjdkr(d| j_d| j_d| j_tjj	t
jd }t
jtkrZtjtj }nRtjttjt
jktjg dtj }tjdt
j dt| d tjtj }g }|rhtttg}t
jtkrttg}t j|t jt
jkt j!dkg}|j"d	kr$|#tj$|j$k n|#tj"|j"k t%j&t 'tt jtjkj| t j(t j) }d
gdd |D  | j_*t+jt+j }dd |D }| , r| jj}	| jj}
| jj}|st-dd t.t/dS t0|}d}d}d}zXdd tj12dD }d}|rDt%j&t%j34tj5tj|6 pBd}|dkrvt-d| dd t.t/d|	|
|dW S t7jj	||	|
d }dd |D }|D ]}tj18d| }|rt0|dkrt-d| dd t%j&9  t.t/d  W S t0|}||v r,|| }|j:|krR||_:|d	7 }n&t7|||	|
|d}t%j&;| |d	7 }q|D ](}||vrZt%j&<||  |d	7 }qZdd tj12d D }t=jj	||	|
d }d!d |D }|D ]}tj18d"| }|rt0|dkrt0|}||v r"|| }|j:|krH||_:|d	7 }n&t=|||	|
|d#}t%j&;| |d	7 }q|D ](}||vrPt%j&<||  |d	7 }qPt%j&>  d$d t7jj	||	|
d D } d%d t=jj	||	|
d D }!t?jj	||	|
d }"|"st?||	|
dd&}"t%j&;|" t
j|"_@| |"_A|!|"_Bt%j&>  t-d'| d(| d)| d*d+ t.t/d|	|
|dW S  tCy }# zHt%j&9  tjjDd,|# dd- t-d.|# d t.t/dW  Y d }#~#S d }#~#0 0 tEd/| |||d0S )1NrW   r   r[   )r   r      User z	 fetched z ODIs (Own + Universals)Tr   )r   --- Selecciona un Evaluado ---c              	   S   s.   g | ]&}|j |j d |j d|j dfqS r   z (C.I.: r   r\   rn   ro   rm   )r   r   rE   rE   rF   r   ~  r   zassign_odi.<locals>.<listcomp>c                 S   s   g | ]}|j |jd qS )r   rv   r   r   rrE   rE   rF   r     r   z"Por favor, selecciona un evaluado.rI   
assign_odir   c                 S   s    h | ]}|   rt|qS rE   r   isdigitrC   r   xrE   rE   rF   	<setcomp>  r   zassign_odi.<locals>.<setcomp>Zodi_ids2   u]   Error: El peso total de los ODI debe ser exactamente 50. El total actual de tu selección es .r   r   personal_idr   c                 S   s   i | ]}|j |qS rE   r   r   arE   rE   rF   
<dictcomp>  r   zassign_odi.<locals>.<dictcomp>Z
odi_rango_u   Rango inválido para ODI )r\   r   r   r   r   c                 S   s    h | ]}|   rt|qS rE   r  r  rE   rE   rF   r    r   Zcompetencia_idsc                 S   s   i | ]}|j |qS rE   )r   r
  rE   rE   rF   r    r   Zcompetencia_rango_)r\   r   r   r   r   c                 S   s   g | ]
}|j qS rE   )id_odi_personalr
  rE   rE   rF   r     r   c                 S   s   g | ]
}|j qS rE   )id_competencia_personalr   crE   rE   rF   r     r   )r\   r   r   r   u   Asignación completada: z	 nuevas, z actualizadas, z eliminadas.r]   zError in assign_odi: rz   u"   Error al procesar la asignación: zassign_odi.html)r`   r   all_competencias
all_rangos)Fr$   r	   r   r   rd   r   r	  r1   rA   rb   r   r\   re   rL   r   r9   r   rv   rt   r   r   r   in_r   r   ri   lenr<   r   r   r   r   r5   rq   r   ru   id_unidadesr+   rr   rs   rn   ro   choicesr:   ra   r   r   r   rC   r`   getlistfuncsumrx   Zscalarr;   rB   r   r   r   r|   r=   r   r?   Zid_evaluadorr   r   r   r   r   )$r`   current_user_locationr   r  evaluados_for_dropdownallowed_rolesbase_filterr  Zall_rangos_serializedr   r   Zpersonal_id_strr	  Zassignments_madeZassignments_updatedZassignments_deletedZsubmitted_odi_idsZ
total_pesoZexisting_odi_assignmentsZexisting_odi_mapr   Zrango_id_strrango_iditemZnew_aZeidZsubmitted_comp_idsZexisting_comp_assignmentsZexisting_comp_mapZcidZnew_cZecidZcurrent_odi_idsZcurrent_comp_idsZeval_recordr   rE   rE   rF   r   H  s   


 





.










  


"r   z/get_assigned_odisc               
   C   s  t jjdtd} t jjdtd}t jjdtd}t| ||gsNtddidfS zltjj| ||d	t
tjt
tj }g }|D ]*}||j|jj|jj|j|jjd	 qt|W S  ty  } z,td
|  tddidfW  Y d }~S d }~0 0 d S )Nr	  r}   r   r   r   u)   Parámetros incompletos para buscar ODIs.r   r   )r   Zodi_descripcionr   r  r   zError fetching assigned ODIs: z'Error interno al cargar ODIs asignados.r   )r	   rM   rB   rC   rt   r   r;   rA   rb   optionsr+   
joinedloadr   r   ru   r   rv   rx   r   r   loggingr   )r	  r   r   r   resultsassignr   rE   rE   rF   get_assigned_odis  s6    

	

r%  z/get_assigned_competenciasc               
   C   s  t jjdtd} t jjdtd}t jjdtd}t| ||gsNtddidfS zttjj| ||d	t
tjt
tjtj }g }|D ]*}||j|jj|jj|j|jjd	 qt|W S  ty } z,td
|  tddidfW  Y d }~S d }~0 0 d S )Nr	  r}   r   r   r   u1   Parámetros incompletos para buscar competencias.r   r   )Zcompetencia_idZcompetencia_descripcionr   r  r   z&Error fetching assigned competencias: z/Error interno al cargar competencias asignadas.r   )r	   rM   rB   rC   rt   r   r=   rA   rb   r   r+   r!  r   r   r   r   ru   rv   rx   r   r   r"  r   )r	  r   r   r   r#  r$  r   rE   rE   rF   get_assigned_competencias$  s:    

	

r&  c                 C   sd   t d|  d t| ts&t d dS d| v oJ| ddd  tjd v }t d|  d	|  |S )
Nz#DEBUG: Checking allowed_file for: ''z%DEBUG: Filename is not a string type.Fr  r   ZALLOWED_EXTENSIONSzDEBUG: Is 'z' allowed? )r   
isinstancer   rsplitlowerr   config)r   Z
is_allowedrE   rE   rF   allowed_fileI  s    
r,  z/assign_cursosc            )      C   s 	  t  } tjtj  }dgdd |D  | j_t	jt	j
 }dgdd |D  | j
_tjjtjd }g }|stdd tjd	tj d
 ntttg}tjtkrttg}tj|tjtjktjdkg}|jdkr|tj|jk n|tj|jk tjt ttjtjkj!| tj"tj# }|}dgdd |D  | j$_| % r| jj&}| j
j&}	| j$j&}
|dks|	dks|
dkrtdd t't(dS t)jj|
||	d }dd |D }t* }t+j,D ]d}|-drz<|.d}t/|dkr&|d 0 r&|1t2|d  W n t3y<   Y n0 qd}t4|5 D ]j\}}||vrRzd }|j6rt7j8 t9j:d t7j8;|j6}|rt7j8<|rt7=| tj>d|  n|j6rtj?| td|j dd tj>d| d|
 d  |d7 }W n t@yf } z<td!|j d"| d# tjAd$| d%|  W Y d }~n^d }~0  tBy } z<td&|j d"| d tjAd'| d%|  W Y d }~n
d }~0 0 qRd}d}t+j,C D ]}|-drҐz|Ddd(}t+j,E|}d)| }t+jFE|}d }|r>|jGd(kr>tH|jGrt7j8ItJ|jG\}}tKL Md*}| d| | }t7j8 t9j:d |} z6|N|  t7j8 t9jOd+}!t7j8P| |!Dt7jQd,}W nZ tBy }" z@tjAd-| d%|"  td.|jG d"|" d d }W Y d }"~"n
d }"~"0 0 n(tjd/|jG  td0|jG d1d# |0 rrt2|}#|#|v rD||# }$d2}%|$j|kr|||$_d}%|r|$j6rt7j8 t9jOd+|$j6}&t7j8<|&rz t7=|& tj>d3|&  W n> t@y
 } z$tjAd4|& d%|  W Y d }~n
d }~0 0 ||$_6d}%|%rptj1|$ |d7 }td| d5d n,tjd6|# d7 td8|# d9d# W qn|std:d# W q|std;| d<d# t)|||
||	d=}'tj1|' td>| d?d@ tj>dA| d|
 d  |d7 }W nh tBy\ } zNtdB|p| dC| d tjAdD|p2| dEtj d%|  W Y d }~n
d }~0 0 qztjR  tS|||grg }(|dkr|(| dF |dkr|(| dG |dkr|(| dH tdIdJ |( d@ n
tdKd W n tTyR } zFtjU  tdL| d tjAdM|
 dNtj d%|  W Y d }~nhd }~0  tBy } zFtjU  tdO| d tjAdP|
 dNtj d%|  W Y d }~n
d }~0 0 t't(d||	|
dQS t+jVjEdRdt2dS}t+jVjEdTdt2dS}	t+jVjEdUdt2dS}
|| j_&|	| j
_&|
| j$_&tWdV| dWS )XN)r   u   --- Selecciona un Año ---c                 S   s   g | ]}|j |jfqS rE   r   )r   r   rE   rE   rF   r   ]  r   z!assign_cursos.<locals>.<listcomp>)r   z--- Selecciona un Trimestre ---c                 S   s   g | ]}|j |jfqS rE   r   )r   r   rE   rE   rF   r   a  r   r[   u   Error: No se encontró su información de ubicación. No se pueden cargar los evaluados. Por favor, contacte a un administrador.rI   r   z@ has no location info. No evaluados will be loaded for dropdown.Tr   )r   r   c              	   S   s.   g | ]&}|j |j d |j d|j dfqS r   r   )r   ZevaluadorE   rE   rF   r     r   r   u:   Por favor, selecciona Año, Trimestre y Evaluado válidos.assign_cursosr   c                 S   s   i | ]}|j |qS rE   )id_cursor  rE   rE   rF   r    r   z!assign_cursos.<locals>.<dictcomp>Zcurso_desc_r   r   r   ZUPLOAD_FOLDERzDeleted file: zCurso 'z' eliminado.ri   zDeleted CursoPersonal ID z for Personal ID r  z&Error al eliminar archivo para curso 'r   rH   z)Error deleting file for CursoPersonal ID r   zError al eliminar curso 'z Error deleting CursoPersonal ID r   Zcurso_file_z%Y%m%d%H%M%SstaticrU   zError saving file for course zError al guardar el archivo 'z*Attempted upload of disallowed file type: z#Tipo de archivo no permitido para "z". Solo se permiten PDFs.FzRemoved old file: zError removing old file z' actualizado.zSubmitted existing course ID z3 not found in existing DB records. Skipping update.zError: Curso existente con ID z# no encontrado en la base de datos.u8   Error: La descripción es requerida para un nuevo curso.zDAdvertencia: Se recomienda adjuntar un archivo para el nuevo curso 'z'.)rv   path_to_filer\   r   r   zNuevo curso 'u   ' añadido.r]   zAdded new CursoPersonal: zError al procesar curso "z": zError processing course 'z' for user u    cursos nuevos añadidos.z cursos actualizados.z cursos eliminados.u#   ¡Operación de cursos completada! r   zENo se realizaron cambios en los cursos para el evaluado seleccionado.z)Error de integridad de la base de datos: z'Integrity error saving cursos for user z by supervisor z%Error general al guardar los cursos: z%General error saving cursos for user r  r   r}   r   r	  zassign_cursos.html)r`   )Xr(   r7   rA   r   rv   r   rt   r   r  r8   r   r1   rb   r   r\   re   r   r   r   rH   r   r   r   rL   r5   r  rq   r   ru   r  r+   rr   rs   r   rn   ro   r	  ra   rd   r   r   r@   setr	   r`   
startswithsplitr  r  r   rC   r   listr   r0  ospathr   r+  basenameexistsremoveri   r|   OSErrorr   r   keysreplacerB   filesr   r,  splitextr   r   nowstrftimesave	root_pathrelpathsepr   anyr   r   rM   r   ))r`   Zanosr   r  r  r  r  Zevaluados_queryr   r   r	  Zexisting_cursosZexisting_curso_idsZpresent_curso_ids_on_submitkeypartsZcursos_deleted_countZexisting_idZ	curso_objZfile_to_delete_pathr   Zcursos_added_countZcursos_updated_countZcourse_identifierr   Zfile_keyZuploaded_fileZpath_to_store_in_dbfilename_baseext	timestampZnew_filenameZabsolute_save_pathZstatic_folder_absoluteZsave_eZcurso_idZcurso_to_updateZhas_updatesZold_absolute_pathZ	new_cursoZmessage_partsrE   rE   rF   r-  T  s`   













,2




.
@

4
6r-  z/get_personal_cursosc            	   
   C   sP  t  } | d}| d}| d}td| d| d|  t|||gsftd tdd	id
fS ztjj|||d }tdt	| d g }|D ]2}d }|j
rtd|j
d}||j|j|d qtdt	| d td|iW S  tyJ } zBtjd|  td|  tdt|ddfW  Y d }~S d }~0 0 d S )Nr	  r   r   z:DEBUG: AJAX call to /get_personal_cursos for Personal ID: z, Ano: z, Trimestre: z3DEBUG: Missing parameters for /get_personal_cursos.r   zMissing parametersr   r   zDEBUG: Found z  courses in DB for AJAX request.r/  )r   )r.  rv   r0  zDEBUG: Prepared z courses for JSON response.cursosz!Error fetching personal courses: z&DEBUG: Error in /get_personal_cursos: zError fetching data)r   detailsr   )r	   r   rB   r   rt   r   r@   rA   rb   r  r0  r   ru   r.  rv   r   r   r   r   r   )	rd   r	  r   r   rK  Zcursos_dataZcursoZfile_urlr   rE   rE   rF   get_personal_cursos@  s>    




rM  z/get_unidades/<int:div_id>c                 C   s>   | dkrt g S tjj| ddtj }t dd |D S )zJReturns Unidades (Gerencias Generales) for a given DivisionesGenerales id.r   Tid_divisiones_generalesvalidoc                 S   s   g | ]}|j |jd qS r   r  rn   r   rE   rE   rF   r   q  r   z get_unidades.<locals>.<listcomp>)r   r.   rA   rb   r   r  rt   )div_idr#  rE   rE   rF   get_unidadesj  s    rS  z(/get_gerencias_generales/<int:unidad_id>c                 C   s>   | dkrt g S tjj| ddtj }t dd |D S )uI   Returns GerenciasGenerales (Gerencias de Línea) for a given Unidades id.r   Tr  rP  c                 S   s   g | ]}|j |jd qS r   id_gerencias_generalesrn   r   rE   rE   rF   r   {  r   z+get_gerencias_generales.<locals>.<listcomp>)r   r/   rA   rb   r   rV  rt   )Z	unidad_idr#  rE   rE   rF   get_gerencias_generalest  s    rW  z%/get_coordinaciones/<int:gerencia_id>c                 C   s>   | dkrt g S tjj| ddtj }t dd |D S )z9Returns Coordinaciones for a given GerenciasGenerales id.r   TrV  rP  c                 S   s   g | ]}|j |jd qS r   id_coordinacionesrn   r   rE   rE   rF   r     r   z&get_coordinaciones.<locals>.<listcomp>)r   r0   rA   rb   r   rZ  rt   )Zgerencia_idr#  rE   rE   rF   get_coordinaciones~  s    r[  z/gerente_pagec               
   C   s  t  } t }tdftdftdfg|j_d }tjdkrtj	
drtj	j
dtd}zttj	
dd}ttj	
d	d}ttj	
d
d}ttj	
dd}|dkr|j jdd tjj|dd D 7  _|dkr|j jdd tjj|dd D 7  _|dkr8|j jdd tjj|dd D 7  _W n tyN   Y n0 | rtj
|}|rؐz.|jj|_|jjpd }	|jj}
|jj}|jj}|jj}|	dkrd  }
 } }}n`|
r|
dkr|
nd }
|r|dkr|nd }|r|dkr|nd }|r |dkr |nd }tjj|d }|r\|	|_|
|_||_||_||_n t||	|
|||d}tj| tj   t!dd t"t#dW S  ty } z&tj$  t!d| d W Y d }~n
d }~0 0 ndtj	v rtj	j
dtd}tj
|}|rtz$tj%| tj   t!dd W n@ tyr } z&tj$  t!d| d W Y d }~n
d }~0 0 t"t#dS | & rtjjt'| j(jd }|r|}|j|j_t!d |j) d!d" n
t!d#d tj*t+tj, }t-d$| |||d%d&S )'NZEvaluadoZ
SupervisorZGerenterX   Zuser_id_to_assignr}   rO  r   r  rV  rZ  c                 S   s   g | ]}|j |jfqS rE   rQ  )r   urE   rE   rF   r     s   z gerente_page.<locals>.<listcomp>TrN  c                 S   s   g | ]}|j |jfqS rE   rU  )r   grE   rE   rF   r     s   rT  c                 S   s   g | ]}|j |jfqS rE   rY  r  rE   rE   rF   r     s   rX  r   r[   )r\   r   rO  r  rV  rZ  u4   Configuración de usuario actualizada correctamente.r]   gerente_pagezError al guardar: rI   	remove_idu.   Ubicación de usuario eliminada correctamente.u   Error al eliminar ubicación: )rm   r   z encontrado.ri   zUsuario no encontrado.zgerente_page.htmlu   Gestión de Ubicaciones)search_formassign_form
found_usercurrent_locationsr_   ).r&   r'   r   r   r   rL   r  r	   r   r`   rB   rC   r  r.   rA   rb   rt   rV  r/   rZ  r0   r   validater5   rd   r   rO  r1   re   r+   rr   r   r   r   r   r   r   r|   ra   r   rm   rn   r   r!  Zuser_details_in_ubicacionr   )r`  ra  rb  rD   rR  Zuni_idZger_idZcoord_idZuser_to_updateZloc_valZdiv_valZuni_valZger_valZ	coord_valZexisting_locZnew_locr   r_  Zloc_to_removerg   rc  rE   rE   rF   r^    s    









(

&



r^  z/talento_humanoc                  C   s<  t jdkrt } | jt jd |  rt jd}| jj}|rz|rzt	j
|}|rn||_tj  tdd qtdd qtdd n4| j D ](\}}|D ]}td	| d
| d qqttdS tj
t	tjtjtjtt	jtjktt	jtjktt	jtjkt	jdk }g }|D ]\}}	}
}g }d}|jrt j
t j!"|j }|D ]h}zt#|j$j}W n t%t&fy   d}Y n0 |j'j(| }|)|j'j|j'j(||j$jd ||7 }qbg }d}|j*rdt+j
t+j,"|j* }|D ]h}zt#|j$j}W n t%t&fy*   d}Y n0 |j-j(| }|)|j-j|j-j(||j$jd ||7 }q|| }|}t.j
j/|j|j|jd0 d u}d}|dkr|st1j
t1j2dk3t1j45 0 }|r||j4krt#|j4}d}|)||	|
|||t6t#|dt6t#|d||d
 q&dd |D }t7d|d|dS )NrX   )Zformdataevaluacion_idu5   Observación de Talento Humano guardada exitosamente.r]   u   Evaluación no encontrada.r   u/   Datos incompletos para guardar la observación.zError en el campo 'r   talento_humanoFr   )rv   rx   scorer   r   r   Tr   )

evaluacionpersonal_nameano_nametrimestre_nameodi_detailscomp_detailsZtotal_scoreZfinal_scorer   	is_cappedc                 S   s$   i | ]}|d  j t|d  jdqS )rh  )observacion_th)Zid_evaluacionr)   ro  )r   Z	eval_dictrE   rE   rF   r  z  r   z"talento_humano.<locals>.<dictcomp>ztalento_humano_page.htmlu   Página de Talento Humano)disapproved_evaluacionesr_   forms)8r	   r   r)   processr`   ra   rB   ro  rd   r?   rA   r+   rr   r   r   r   r   r   r   r5   rn   r7   rv   r8   rs   r\   r   r   r   r   rt   r   r;   r  r  r   r   r   AttributeErrorr   rx   ru   r   r=   r  r   r@   rb   re   r>   r   r   r   r   r   r   )r`   re  r   rh  fieldr   r   Zdisapproved_evaluaciones_rawrp  ri  rj  rk  rl  r   Zodi_personal_assignmentsr   r   rg  rm  Ztotal_comp_scoreZcomp_personal_assignmentsr   r   r   rn  r   rq  rE   rE   rF   rf    s    





rf  z/change_passwordc               
   C   s   t  } t}|  rz0|| jj tj  t	dd t
tdW S  ty } z&tj  t	d| d W Y d}~n
d}~0 0 tdd|| d	S )
zK
    Allows the currently logged-in user to change their own password.
    ue   ¡Contraseña actualizada exitosamente! Usa tu nueva contraseña la próxima vez que inicies sesión.r]   rJ   u$   Error al actualizar la contraseña: rI   Nzchange_password.htmlu   Cambiar Contraseña)r_   rg   r`   )r*   r   ra   r   rf   rd   r+   rr   r   r   r   r   r   r   r   )r`   Zuser_to_editr   rE   rE   rF   change_password  s     


&ru  __main__z0.0.0.0i  FLASK_DEBUGr   )hostportdebug)vr5  r"  Zpdf_generatorr   r   flaskr   r   r   r   r   r	   r
   r   r   r   Zflask_loginr   r   r   r   r   r   Z	flask_wtfr   Zwerkzeug.utilsr   dotenvr   	functoolsr   Z
sqlalchemyr   Zsqlalchemy.excr   r+  r   r   r   r   r   r    r!   rq  r"   r#   r$   r%   r&   r'   r(   r)   r*   
extensionsr+   Zmodelsr,   r-   r.   r/   r0   r1   __name__r   from_objectenvironrB   r   Zinit_appZlogin_managerZ
login_viewbasicConfigINFOr   setLevelr5   r6   r7   r8   r9   r:   r;   r<   r=   r>   r?   r@   Zuser_loaderrG   rT   routerV   r3   rj   rJ   rw   ry   r   r   r   r   r   r   r   r   r   r%  r&  r,  r-  rM  rS  rW  r[  r^  rf  ru  runrE   rE   rE   rF   <module>   s   0 $, 
T



?
z33#. 4#
" j(~
x
