
    1(iG                     X    S SK rS SKrS SKrS SKrS SKrS SKJr  S SKJ	r	   " S S5      r
g)    N)Config)Teamc                   |   \ rS rSrSr\S 5       r\S 5       r\SS j5       r\SS j5       r	\S 5       r
\SS	 j5       r\SS
 j5       r\SS j5       r\SS j5       r\SS j5       r\SS j5       r\SS j5       r\S 5       r\S 5       r\S 5       r\SS j5       r\SS j5       r\SS j5       r\S S j5       rSrg)!AttendanceLog	   z7Model for managing attendance log data in the database.c                  H    [         R                  R                  [        R                  [        R
                  [        R                  [        R                  [        R                  S9n U $ ! [         R                  R                   a  n[        SU 35         SnAgSnAff = f)z"Establishes a database connection.)hostportuserpassworddatabasez$Error connecting to MySQL Database: N)mysql	connectorconnectr   DB_HOSTDB_PORTDB_USERDB_PASSWORDDB_NAMEErrorprint)connes     //var/www/fran/franai/models/attendance_model.pyget_db_connectionAttendanceLog.get_db_connection   sy    	??**^^^^^^++ + D K$$ 	8<=	s   A(A+ +B!	BB!c                  
   [         R                  5       n U (       d  g U R                  5       nUR                  S5        U R	                  5         [        S5        U R                  5       (       a!  WR                  5         U R                  5         gg! [        R                  R                   a  n[        SU 35         SnANhSnAff = f! U R                  5       (       a!  WR                  5         U R                  5         f f = f)z6Creates the attendance_logs table if it doesn't exist.Na-  
                CREATE TABLE IF NOT EXISTS attendance_logs (
                    id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
                    pid INT UNSIGNED NOT NULL,
                    recognition_timestamp DATETIME NOT NULL,
                    status VARCHAR(50) NOT NULL,
                    location_id INT UNSIGNED NULL,
                    similarity FLOAT NULL,
                    UNIQUE KEY unique_attendance (pid, recognition_timestamp),
                    FOREIGN KEY (location_id) REFERENCES locations(id)
                )
            z@[OK] 'attendance_logs' table exists or was successfully created.z(Error creating 'attendance_logs' table: )r   r   cursorexecutecommitr   r   r   r   is_connectedclose)r   r   r   s      r   create_table_if_not_exists(AttendanceLog.create_table_if_not_exists   s     ..0	[[]FNN   KKMTU   ""

 # $$ 	B<QC@AA	B   ""

 #s)   <B C/C=C
 CC
 
8DNc                    [         R                  R                  U 5      (       d  g[        R	                  5       nU(       d  g/ nUn [        U SSS9 n[        R                  " U5      nU H  n UR                  S5      nU(       d  M  [        R                  R                  US5      n	U(       a  X::  a  ML  UR                  [        US   5      UUR                  SS	5      [        US
   5      45        Ub  X:  a  U	nM  M     SSS5        U(       d  [#        S5        U$  UR%                  5       nSnUR'                  X5        UR)                  5         UR*                  n[#        S[-        U5       SU S35        UUR/                  5       (       a!  UR1                  5         UR1                  5         $ $ ! [        [        4 a     GM\  f = f! , (       d  f       N= f! [        [        R                   4 a  n
[#        SU
 35         Sn
A
gSn
A
ff = f! [2        R4                  R                    a`  n
[#        SU
 35        UR7                  5         Us Sn
A
UR/                  5       (       a!  WR1                  5         UR1                  5         $ $ Sn
A
ff = f! UR/                  5       (       a!  WR1                  5         UR1                  5         f f = f)z
Synchronizes records from the CSV incrementally based on the last sync time.
Returns the timestamp of the latest processed record.
Nr newline	Timestampz%Y-%m-%d %H:%M:%SUser IDStatusCheck-inLocationError reading CSV file: z-Scheduler: No new attendance records to sync.z[INSERT IGNORE INTO attendance_logs (pid, recognition_timestamp, status) VALUES (%s, %s, %s)u!   🔄 Incremental Sync: Processed z new records. Inserted z	 into DB.z&Error during incremental bulk insert: )ospathexistsr   r   opencsv
DictReadergetdatetimestrptimeappendint
ValueError	TypeErrorIOErrorr   r   r   executemanyr    rowcountlenr!   r"   r   r   rollback)csv_pathlast_sync_timer   records_to_insertlatest_timestamp_in_batchfilereaderrowtimestamp_strrecord_timer   r   queryinserted_counts                 r   sync_from_csv_incremental'AttendanceLog.sync_from_csv_incremental<   sn    ww~~h''..0$2!	hR0D-!C!(+(<,$&.&7&7&@&@Pc&d *k.K$)00I/)GGHj9J0	2  5<@g8C5 Ah) " 1> !AB,,	[[]FqEu8KKM#__N5c:K6L5MMdesdtt}~,   ""

 #/ '	2 ! !3 106 # 	,QC01	  $$ 	":1#>?MMO!!  ""

 #	"
   ""

 #s   G G/F3G	,F35G7AF3>GG !AH 3GGGG
GG G H6H		HJ/J
JJ 
JJ 8K
c           
         [         R                  R                  U 5      (       d  [        SU  S35        g[        R                  5       nU(       d  g/ n [        U SSS9 n[        R                  " U5      nU Hf  nUR                  S5      (       d  M  UR                  S5      (       d  M3  UR                  [        US   5      US   UR                  S	S
5      45        Mh     SSS5        U(       d  gSn UR                  5       nSn	UR                  X5        UR!                  5         UR"                  n[        S[%        U5       SU S35        [%        U5      U4UR'                  5       (       a!  UR)                  5         UR)                  5         $ $ ! , (       d  f       N= f! [        [        R                  4 a  n[        SU 35         SnAgSnAff = f! [*        R,                  R                   a[  n[        S[.         SU 35        [0        s SnAUR'                  5       (       a!  WR)                  5         UR)                  5         $ $ SnAff = f! UR'                  5       (       a!  WR)                  5         UR)                  5         f f = f)zy
Synchronizes records from the attendance CSV file to the database.
Uses 'INSERT IGNORE' to efficiently skip duplicates.
zInfo: CSV file not found at z. Skipping sync.)r   r   r&   r'   r(   r+   r*   r,   r-   Nr/   r   z
                INSERT IGNORE INTO attendance_logs (pid, recognition_timestamp, status)
                VALUES (%s, %s, %s)
            u    🔄 Attendance Sync: Processed z records. Inserted z new records.*Error fetching attendance status for user : )r0   r1   r2   r   r   r   r3   r4   r5   r6   r9   r:   r=   r   r   r>   r    r?   r@   r!   r"   r   r   user_idattendance_info)
rB   r   rD   rF   rG   rH   r   rL   r   rK   s
             r   sync_from_csvAttendanceLog.sync_from_csv   s%    ww~~h''0
:JKL..0	hR0D-!Cwwy))cggk.B.B)00I/,GGHj92  " 1 !	[[]FE u8KKM#__N4S9J5K4LL_`n_oo|}~()>9
   ""

 #G 10 # 	,QC01	* $$ 	#>wir!MN""  ""

 #		#   ""

 #ss   F# 0FF+7F"F# 5A&G 
F F#  F# #G=GGI6III II 8Jc                    SSS.n[         R                  5       nU(       d  U$  UR                  SS9nSnUR                  X@45        UR	                  5       nU(       a  SUS'   US   nUR                  S	5      US
'   UUR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aS  n[        SU  SU 35        Us SnAUR                  5       (       a!  WR                  5         UR                  5         $ $ SnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)z
Checks the database for a 'Check-in' record for a specific user for the current day.
Returns the status and the check-in time.
FN)has_attendancecheck_in_timeT
dictionarya6  
                SELECT recognition_timestamp 
                FROM attendance_logs 
                WHERE pid = %s 
                  AND status = 'Check-in' 
                  AND DATE(recognition_timestamp) = CURDATE()
                ORDER BY recognition_timestamp DESC
                LIMIT 1
            rW   recognition_timestampz%I:%M:%S %prX   rP   rQ   )r   r   r   r   fetchonestrftimer!   r"   r   r   r   r   )rR   rS   r   r   rK   result	timestampr   s           r   get_status_for_user!AttendanceLog.get_status_for_user   s=    .3TJ..0""	[[D[1FE NN5*-__&F48 01"#:;	3<3E3Em3T0"
   ""

 #	 $$ 	#>wir!MN""  ""

 #		#   ""

 #s0   AB4 4D%D $D%%D(  D%%D( (8E c                    [         R                  5       nU(       d  g UR                  5       nSnUR                  XpX!X445        UR	                  5          UR                  5       (       a!  UR                  5         UR                  5         gg! [        R                  R                   aa  n[        SU  SU 35        UR                  5          SnAUR                  5       (       a!  WR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)zt
Adds a new attendance record to the database with a specific timestamp.
Returns True on success, False on failure.
Fz
                INSERT INTO attendance_logs (pid, recognition_timestamp, status, location_id, similarity)
                VALUES (%s, %s, %s, %s, %s)
            Tz$Error adding attendance log for PID rQ   N)r   r   r   r   r    r!   r"   r   r   r   r   rA   )	pidstatusr_   location_id
similarityr   r   rK   r   s	            r   add_logAttendanceLog.add_log   s    ..0	[[]FE NN5	;"STKKM   ""

 # $$ 	8RsCDMMO  ""

 #	
   ""

 #s)   6B D*!DD DD 8Ec                     [         R                  U 5      nUS   (       d  SnOSn[        R                  " 5       R	                  SS9n[         R                  XXQU5      (       a  SUR                  5        S3nXFU4$ g)	z
Determines the attendance status (Check-in/Check-out) and adds a new record.
Returns the status, a message, and the timestamp used.
rW   r-   z	Check-outr   )microsecondzStaff z successfully)NzFailed to log attendanceN)r   r`   r   get_ph_timereplacerg   lower)rc   re   rf   status_inford   r_   messages          r   
add_recordAttendanceLog.add_record   s{     $77<+,F F&&(00Q0?	  ijQQv||~.m<GI--9    c                    [         R                  5       nU(       d  g UR                  SS9n/ nSn	/ n
U (       a%  U
R                  S5        UR                  U  S35        U(       a%  U
R                  S5        UR                  U S35        U(       a&  U
R                  S	5        UR                  S
U S
35        U
(       a  U	SSR	                  U
5      -   -  n	U	S-  n	U(       d  US-
  U-  nU	S-  n	UR                  X;/5        UR                  U	[        U5      5        UR                  5       nUUR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aN  n[        SU 35         SnAUR                  5       (       a!  WR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)zo
Retrieves a list of attendance logs with user and location details,
supporting date filtering and pagination.
NTrY   a  
                SELECT 
                    al.id,
                    al.pid,
                    CONCAT(s.first_name, ' ', s.last_name) AS name,
                    al.recognition_timestamp,
                    al.status,
                    loc.name AS location_name
                FROM 
                    attendance_logs al
                LEFT JOIN 
                    hris_core.employee_information_tbl s ON al.pid = s.pid
                LEFT JOIN 
                    locations loc ON al.location_id = loc.id
            al.recognition_timestamp >= %s	 00:00:00al.recognition_timestamp <= %s	 23:59:59.CONCAT(s.first_name, ' ', s.last_name) LIKE %s% WHERE  AND z' ORDER BY al.recognition_timestamp DESC    LIMIT %s OFFSET %sz$Error fetching all attendance data: r   r   r   r9   joinextendr   tuplefetchallr!   r"   r   r   r   r   )
start_dateend_datepagelimit	exportingsearch_termr   r   paramsrK   where_clausesoffsetresultsr   s                 r   get_all_attendance_with_details-AttendanceLog.get_all_attendance_with_details  s    ..03	[[D[1FFE  M$$%EFI67$$%EF
)45$$%UV+a01W\\-%@@@>>E(e+..uo.NN5%-0oo'G
   ""

 #	 $$ 	8<=  ""

 #		   ""

 #s*   DE$ $GGG GG 8Hc                    [         R                  5       nU(       d  g UR                  5       n/ nSn/ nU (       a%  UR                  S5        UR                  U  S35        U(       a%  UR                  S5        UR                  U S35        U(       a&  UR                  S5        UR                  SU S35        U(       a  US	S
R	                  U5      -   -  nUR                  U[        U5      5        UR                  5       S   nUUR                  5       (       a!  UR                  5         UR                  5         $ $ ! UR                  5       (       a!  WR                  5         UR                  5         f f = f)zW
Counts the total number of raw attendance logs, supporting date filtering and search.
r   zhSELECT COUNT(*) FROM attendance_logs al LEFT JOIN hris_core.employee_information_tbl s ON al.pid = s.pidrt   ru   rv   rw   rx   ry   rz   r{   )
r   r   r   r9   r   r   r   r\   r!   r"   )	r   r   r   r   r   r   rK   r   counts	            r   get_total_logs_count"AttendanceLog.get_total_logs_countP  s6   
 ..0	[[]FF~EM$$%EFI67$$%EF
)45$$%UV+a01W\\-%@@@NN5%-0OO%a(E  ""

 #t  ""

 #s   C(D= =8E5c                 n   [         R                  5       nU(       d  g UR                  SS9nUR                  S5        UR	                  5       nU(       a  US   OSn/ nSn	US:X  a  S	U	 S
3n
OSU	 S
3n
/ nU (       a%  UR                  S5        UR                  U  S35        U(       a%  UR                  S5        UR                  U S35        U(       a&  UR                  S5        UR                  SU S35        U(       a  U
SSR                  U5      -   -  n
UR                  U
[        U5      5        UR	                  5       nU(       a  X|S'   OSSUS.nUUR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aN  n[        SU 35         SnAUR                  5       (       a!  WR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)z~
Calculates summary statistics. The unique_users count is always the total
number of registered users, regardless of filters.
NTrY   z6SELECT COUNT(pid) as total_users FROM registered_userstotal_usersr   zXFROM attendance_logs al LEFT JOIN hris_core.employee_information_tbl s ON al.pid = s.pidlogsa	  
                    SELECT
                        COALESCE(SUM(CASE WHEN status = 'Check-in' THEN 1 ELSE 0 END), 0) AS checkin_count,
                        COALESCE(SUM(CASE WHEN status = 'Check-out' THEN 1 ELSE 0 END), 0) AS checkout_count
                    z
                a-  
                    SELECT
                        COUNT(DISTINCT CONCAT(al.pid, DATE(al.recognition_timestamp))) AS checkin_count,
                        COUNT(DISTINCT CASE WHEN al.status = 'Check-out' THEN CONCAT(al.pid, DATE(al.recognition_timestamp)) END) AS checkout_count
                    rt   ru   rv   rw   rx   ry   rz   r{   unique_users)checkin_countcheckout_countr   z"Error getting attendance summary: )r   r   r   r   r\   r9   r   r   r!   r"   r   r   r   r   )r   r   viewr   r   r   total_users_resulttotal_unique_usersr   	from_joinrK   r   summaryr   s                 r   get_attendance_summary$AttendanceLog.get_attendance_summaryt  s    ..09	[[D[1F NNST!'!2FX!3M!B^_ FrIv~ K  	 K  	 M$$%EFI67$$%EF
)45$$%UV+a01W\\-%@@@NN5%-0oo'G *<',-Tfg
   ""

 #	 $$ 	6qc:;  ""

 #		   ""

 #s*   D8F G9+G49G< 4G99G< <8H4c                 t   [         R                  5       nU(       d  g UR                  SS9n/ n	Sn
/ nU (       a%  UR                  S5        U	R                  U  S35        U(       a%  UR                  S5        U	R                  U S35        U(       a&  UR                  S	5        U	R                  S
U S
35        U(       a"  UR                  S5        U	R                  U5        U(       a  U
SSR	                  U5      -   -  n
U
S-  n
U
S-  n
U(       d  US-
  U-  nU
S-  n
U	R                  X</5        UR                  U
[        U	5      5        UR                  5       UR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aN  n[        SU 35         SnAUR                  5       (       a!  WR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)z
Retrieves a paginated or full, summarized list of daily attendance for each user,
showing the location of their first check-in of the day.
NTrY   a  
                WITH FirstCheckIn AS (
                    SELECT
                        pid,
                        DATE(recognition_timestamp) AS attendance_date,
                        location_id,
                        ROW_NUMBER() OVER(PARTITION BY pid, DATE(recognition_timestamp) ORDER BY recognition_timestamp ASC) as rn
                    FROM
                        attendance_logs
                    WHERE
                        status = 'Check-in'
                )
                SELECT
                    DATE(al.recognition_timestamp) AS attendance_date,
                    al.pid,
                    CONCAT(s.first_name, ' ', s.last_name) AS name,
                    s.company_email AS email,
                    ug.group_name AS team_name,
                    MIN(CASE WHEN al.status = 'Check-in' THEN al.recognition_timestamp END) AS check_in,
                    MAX(CASE WHEN al.status = 'Check-out' THEN al.recognition_timestamp END) AS check_out,
                    MAX(loc.name) AS location_name
                FROM
                    attendance_logs al
                LEFT JOIN
                    hris_core.employee_information_tbl s ON al.pid = s.pid
                LEFT JOIN
                    intra.tag_group tg ON s.pid = tg.user_id AND tg.workspace_default = 'Y'
                LEFT JOIN
                    intra.user_group ug ON tg.group_id = ug.GID AND ug.workspace_status = 1
                LEFT JOIN
                    FirstCheckIn fci ON al.pid = fci.pid AND DATE(al.recognition_timestamp) = fci.attendance_date AND fci.rn = 1
                LEFT JOIN
                    locations loc ON fci.location_id = loc.id
            rt   ru   rv   rw   rx   ry   zug.GID = %srz   r{   zH GROUP BY al.pid, DATE(al.recognition_timestamp), name, email, team_namez- ORDER BY attendance_date DESC, check_in DESCr|   r}   z!Error fetching daily attendance: r~   )r   r   r   r   r   r   team_gidr   r   r   rK   r   r   r   s                 r   get_daily_attendance"AttendanceLog.get_daily_attendance  s    ..0DK	[[D[1FF!EF M$$%EFI67$$%EF
)45$$%UV+a01$$]3h'W\\-%@@@__EDDE (e+..uo.NN5%-0??$
   ""

 #	 $$ 	5aS9:  ""

 #		   ""

 #s*   D;F G<.G7<G? 7G<<G? ?8H7c                    [         R                  5       nU(       d  g UR                  5       n/ nSn/ nU (       a%  UR                  S5        UR                  U  S35        U(       a%  UR                  S5        UR                  U S35        U(       a&  UR                  S5        UR                  SU S35        U(       a  US	S
R	                  U5      -   -  nUR                  U[        U5      5        UR                  5       S   UR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aN  n[        SU 35         SnAUR                  5       (       a!  WR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)z1Counts the total number of daily summary records.r   zSELECT COUNT(DISTINCT al.pid, DATE(al.recognition_timestamp)) FROM attendance_logs al LEFT JOIN hris_core.employee_information_tbl s ON al.pid = s.pidrt   ru   rv   rw   rx   ry   rz   r{   z!Error counting daily attendance: N)r   r   r   r9   r   r   r   r\   r!   r"   r   r   r   r   )	r   r   r   r   r   r   rK   r   r   s	            r   get_total_daily_count#AttendanceLog.get_total_daily_count  s    ..0A	[[]FF mEM$$%EFI67$$%EF
)45$$%UV+a01W\\-%@@@NN5%-0??$Q'
   ""

 #	 $$ 	5aS9:  ""

 #		   ""

 #s*   C&D; ;F'F"'F* "F''F* *8G"c                    [         R                  5       nU(       d  g UR                  SS9nSnUR                  X045        UR	                  5       nU(       a  US   OS UR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aQ  n[        SU  SU 35         SnAUR                  5       (       a!  WR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)zP
Retrieves the timestamp of the most recent attendance record for a given user.
NTrY   z
                SELECT recognition_timestamp 
                FROM attendance_logs 
                WHERE pid = %s 
                ORDER BY recognition_timestamp DESC 
                LIMIT 1
            r[   z(Error fetching last attendance for user rQ   r   r   r   r   r\   r!   r"   r   r   r   r   )rc   r   r   rK   r^   r   s         r   get_last_attendance_for_user*AttendanceLog.get_last_attendance_for_user1  s   
 ..0	[[D[1FE NN5&)__&F6<612$F
   ""

 #	 $$ 	<SEA3GH  ""

 #		   ""

 #s*   A B D4D D  DD 8E c                     [         R                  5       n U (       d  0 $ 0 n U R                  SS9nSnUR                  U5        UR	                  5       nU H  nUS   US   US   S.XS   '   M     UU R                  5       (       a!  UR                  5         U R                  5         $ $ ! [        R                  R                   aP  n[        S	U 35        0 s S
nAU R                  5       (       a!  WR                  5         U R                  5         $ $ S
nAff = f! U R                  5       (       a!  WR                  5         U R                  5         f f = f)zG
Retrieves the min, max, and average recognition scores for all users.
TrY   aE  
                SELECT 
                    pid, 
                    MIN(similarity) as min_score, 
                    MAX(similarity) as max_score,
                    AVG(similarity) as avg_score
                FROM attendance_logs 
                WHERE similarity IS NOT NULL
                GROUP BY pid
            	min_score	max_score	avg_score)r   r   r   rc   z-Error fetching all users recognition scores: Nr   r   r   r   r   r!   r"   r   r   r   r   )r   scoresr   rK   r   rH   r   s          r    get_all_users_recognition_scores.AttendanceLog.get_all_users_recognition_scoresM  s2   
 ..0I	[[D[1F	E NN5!oo'G!$[!1!$[!1!$[!1&5z"  
   ""

 #	 $$ 	A!EFI  ""

 #		   ""

 #s0   AB( (DDDD DD 8Ec           	         [         R                  5       nU(       a  U(       d  0 $  UR                  SS9nSnUR                  X@U45        UR	                  5       nU=(       d    0  UR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aV  n[        SU  SU SU 35        0 s SnAUR                  5       (       a!  WR                  5         UR                  5         $ $ SnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)zg
Retrieves the min, max, and average recognition scores for a single user
since a specific start date.
TrY   a;  
                SELECT 
                    MIN(similarity) as min_score, 
                    MAX(similarity) as max_score,
                    AVG(similarity) as avg_score
                FROM attendance_logs 
                WHERE pid = %s AND recognition_timestamp >= %s AND similarity IS NOT NULL
            z*Error fetching recognition scores for PID z since rQ   Nr   )rc   r   r   r   rK   r   r   s          r   !get_user_recognition_scores_since/AttendanceLog.get_user_recognition_scores_sinceu  s    ..0:I	[[D[1FE NN5
"34__&F<R
   ""

 #	 $$ 	>se7:,VXYZX[\]I  ""

 #		   ""

 #s/   >B D:DDD DD 8Ec                     [         R                  5       nU(       d  gSSSSS.n SSKJn  UR	                  SS9nSnUR                  U5        UR                  5       n[        S[        U5       S	35        S
nU  S3U S34n	UR                  X5        UR                  5       n
[        U
5      US'   U
(       as  U" [        5      nU
 H6  nUS   R                  5       R                  nX   R                  US   5        M8     U(       a$  [        S UR                  5        5       5      nXS'   [        SUS    35        [        SUS    35        U (       a  U(       a   [        R                  R!                  U S5      n[        R                  R!                  US5      nSnUnUU::  a8  UR#                  5       S:X  a  US-  nU[        R$                  " SS9-  nUU::  a  M8  UR&                  UR&                  -
  S-  UR(                  UR(                  -
  -   S-   nSnU H/  nSnUS:X  a  UU-  nM  US:X  a
  USU-  -  nM"  US;   d  M*  UU-  nM1     UUS'   US   S:  a  [/        US   US   -  S-  5      US'   [        SU 35        UUR1                  5       (       a!  UR3                  5         UR3                  5         $ $ ! [*        [,        4 a    SUS'    Nf = f! [4        R6                  R8                   aN  n[        S U 35         SnAUR1                  5       (       a!  WR3                  5         UR3                  5         ggSnAff = f! UR1                  5       (       a!  WR3                  5         UR3                  5         f f = f)!z
Calculates the quick view summary.
- Unique FTE is the average number of unique employees who check in per week.
- Required Visits is based on the total number of hired employees.
- Assumes a static 'Hybrid 1' (once per week) schedule.
Nr   )total_visits
unique_fterequired_visitsperformance)defaultdictTrY   zISELECT pid FROM hris_core.employee_information_tbl WHERE status = 'Hired'zDEBUG: Found z hired employees from HRIS.af  
                SELECT DISTINCT
                    al.pid,
                    DATE(al.recognition_timestamp) AS attendance_date
                FROM
                    attendance_logs al
                WHERE
                    al.recognition_timestamp >= %s AND al.recognition_timestamp <= %s
                    AND al.status = 'Check-in'
            ru   rw   r   attendance_daterc   c              3   8   #    U  H  n[        U5      v   M     g 7f)N)r@   ).0pidss     r   	<genexpr>7AttendanceLog.get_quick_view_summary.<locals>.<genexpr>  s     1]H\#d))H\s   r   z.DEBUG: Total Visits (unique daily check-ins): z$DEBUG: Sum of unique FTEs per week: %Y-%m-%dr|   )days   zHybrid 1zHybrid 2   )zHybrid 3zHybrid 4r   d   r   z%DEBUG: Final summary to be returned: z"Error getting quick view summary: )r   r   collectionsr   r   r   r   r   r@   setisocalendarweekaddsumvaluesr7   r8   weekday	timedeltayearmonthr;   r<   roundr!   r"   r   r   r   )r   r   r   summary_datar   r   hired_employees_queryhired_employeesactuals_queryr   check_in_recordsweekly_ftesrecordweek_numbertotal_weekly_unique_ftestartend	num_weekscurrent_day
num_monthstotal_required_visitsempsetupr   s                           r   get_quick_view_summary$AttendanceLog.get_quick_view_summary  s    ..0()qabcV	/[[D[1F %p!NN01$oo/OM#o"6!77RST	M $I.8*I0FGFNN=1%0+./?+@L(  )#..F"():";"G"G"I"N"NK,00? / .11]HZHZH\1].]+1H.B<P^C_B`ab8l9S8TUV h8$--66z:NE"++44XzJC !"I"'K%,&..0A5%NI#x'9'9q'AA &, #&((UZZ"72!=U[[AX!Y\]!]J -.). * J.1Y>1"j01a*nE1"&>>1Z?1  / 7LL!23
 -.2.3\.5QT`arTs5swz4z.{]+9,HI   ""

 # #I. 867L!238 $$ 	6qc:;  ""

 #		   ""

 #s\   D5K B J; A#J; J; 2K ;KK KK M4L=M =MM 8M=c                 f   [         R                  5       nU(       d  g UR                  SS9nSnUR                  X045        UR	                  5       nUUR                  5       (       a!  UR                  5         UR                  5         $ $ ! [        R                  R                   aN  n[        SU 35         SnAUR                  5       (       a!  WR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  WR                  5         UR                  5         f f = f)z
Retrieves the most recent, unique attendance logs by user and status.
This prevents showing multiple check-outs for the same person in the recent list.
NTrY   a  
                WITH RankedLogs AS (
                    SELECT
                        al.pid,
                        CONCAT(s.first_name, ' ', s.last_name) AS name,
                        al.recognition_timestamp,
                        al.status,
                        ROW_NUMBER() OVER(PARTITION BY al.pid, al.status ORDER BY al.recognition_timestamp DESC) as rn
                    FROM
                        attendance_logs al
                    LEFT JOIN
                        hris_core.employee_information_tbl s ON al.pid = s.pid
                )
                SELECT
                    pid,
                    name,
                    recognition_timestamp,
                    status
                FROM
                    RankedLogs
                WHERE
                    rn = 1
                ORDER BY
                    recognition_timestamp DESC
                LIMIT %s
            z'Error fetching recent attendance logs: r   )r   r   r   rK   r   r   s         r   get_recent_attendance_logs(AttendanceLog.get_recent_attendance_logs  s     ..0%	[[D[1FE4 NN5(+oo'G
   ""

 #	 $$ 	;A3?@  ""

 #		   ""

 #s)   4B	 	C5'C05C8 0C55C8 88D0c                 ~   [         R                  U UUS9nUc  gSnSnSnSnU(       d  SnOYU HS  nXHR                  SS5      -  nXXR                  SS5      -  nXhR                  SS5      -  nXxR                  SS5      -  nMU     [        R                  R	                  U S5      n	U	R                  S	5      UUUUS
./n
U
$ )z
Calculates a week-by-week summary of attendance metrics, filterable by team.
This function now calls the team attendance summary and aggregates the results
to ensure consistent calculations.
)r   r   r   Nr   totalVisits	uniqueFTEactualrequiredr   z%Y%U)week_identifierr   r   r   r   )r   get_team_attendance_summaryr6   r7   r8   r]   )r   r   r   team_summaryr   r   r   r   	team_datastart_dtaggregated_summarys              r   get_weekly_summary AttendanceLog.get_weekly_summary+  s     %@@! A 
  
H)	mQ ??mmK;;
--!44MM*a88	 * $$--j*E'008'# 
  "!rr   c                   ^ [         R                  5       nU(       d  g UR                  SS9mU4S jnU" XU5      nU" X4U5      n[        [	        [        UR                  5       5      [        UR                  5       5      -  5      5      n	/ n
U	 H  nUR                  U0 5      nUR                  U0 5      nUR                  SS5      nUR                  SS5      nU
R                  UUR                  SS5      UR                  S	S5      UUUR                  S
S5      X:  UR                  SS5      UR                  S	S5      UR                  SS5      UR                  SS5      UR                  S
S5      S.5        M     U
UR                  5       (       a!  TR                  5         UR                  5         $ $ ! [        R                  R                   aN  n[        SU 35         SnAUR                  5       (       a!  TR                  5         UR                  5         ggSnAff = f! UR                  5       (       a!  TR                  5         UR                  5         f f = f)z
Calculates a team-by-team summary of attendance, including comparison to a previous period,
with dynamic carry-over logic for required attendance.
NTrY   c                 
  >^ U (       a  U(       d  0 $ SnU  S3U S3/nTb  TS:w  a  US-  nUR                  T5        US-  nT/R                  U[        U5      5        T/R                  5        Vs0 s H  oUS   U_M
     nn0 n [        R                  R                  U S	5      nUR                  UR                  pUR                  S
S9n[        R                  " X5      S
   nUR                  US9nS nU" U5      nSnU/nTb  TS:w  a  US-  nUR                  T5        T/R                  U[        U5      5        T/R                  5       nU Vs/ s H  nUS   PM
     nn0 nU(       a  SR                  SR                  [        [        U5      5      5      nUR                  S5      UR                  S5      /nT/R                  U[        U5      5        T/R                  5        H8  nUS   nUU;  a  [!        5       UU'   UU   R#                  U" US   5      5        M:     0 n0 nU GH  nUR%                  SS5      nUR'                  USSSSSS.5        UR'                  USSSSSS.5        US   nUR%                  S5      nUR%                  S5      nU(       d  SnUR%                  U[!        5       5      n/ n US:X  a  / SQn O)US:X  a  S
S/n OUS;   a  S
/n OUS:X  a
  U
S;   a  S
/n O/ SQn Sn!U(       aW   [        R                  R                  US 5      R)                  5       n"U"R                  U	:X  a  U"R                  U
:X  a  U" U"5      n!U  H)  n#U#U" U5      ::  d  M  U#U!::  d  M  UU   U#==   S
-  ss'   M+     [-        [/        [!        U 5      U-
  5      5      n$[-        [/        U[!        U 5      -
  5      5      n%U$ HF  n&U% H=  n'U'U&:  d  M  UU   U&==   S
-  ss'   UU   U'==   S
-  ss'   U%R1                  U'5          MD     MH     GM     U H  nUU   U   UU   U   -   UU'   M     [6        R8                  " 5       n)U) Vs1 s H  oUS"   iM	     n*nT(       a#  [;        U4S# jU) 5       S5      n+U+(       a  U+S"   1n*SU;   d  SU;   a  U*R#                  S5        0 n,[-        [/        U*5      5       H  nUR%                  U0 5      n-UR%                  US5      n.U-R%                  S$S5      U-R%                  S%S5      U.U-R%                  S&S5      U.S:  a!  [=        U-R%                  S&S5      U.-  S'-  5      OSS(.U,U'   M     U,$ s  snf s  snf ! [*         a     GN	f = f! [2         a  n([5        S!U( 35         Sn(A(GNNSn(A(ff = fs  snf ))z>Helper function to fetch and process data for a single period.a  
                    SELECT
                        COALESCE(ug.group_name, 'Unassigned') AS team_name,
                        COUNT(al.id) AS total_visits_raw,
                        COUNT(DISTINCT al.pid, DATE(al.recognition_timestamp)) AS actual_unique_days,
                        COUNT(DISTINCT al.pid) AS unique_fte
                    FROM attendance_logs al
                    LEFT JOIN hris_core.employee_information_tbl s ON al.pid = s.pid
                    LEFT JOIN intra.tag_group tg ON s.pid = tg.user_id AND tg.workspace_default = 'Y'
                    LEFT JOIN intra.user_group ug ON tg.group_id = ug.GID AND ug.workspace_status = 1
                    WHERE al.status = 'Check-in' AND al.recognition_timestamp >= %s AND al.recognition_timestamp <= %s
                ru   rw   Nr'   z AND ug.GID = %sz GROUP BY team_name;	team_namer   r|   dayc                     U R                  SS9nUR                  5       S   nU R                  5       S   nX2:  a  U$ X2-
  S-   $ )Nr|   r   )rl   r   )datefirst_day_of_monthfirst_day_iso_weekgiven_date_iso_weeks       r   get_week_of_monthbAttendanceLog.get_team_attendance_summary.<locals>._get_data_for_period.<locals>.get_week_of_month  s\    -1\\a\-@* .@-K-K-Ma-P*.2.>.>.@.C+ /C $76 3 HAMMrr   a  
                        SELECT 
                            s.pid, 
                            s.hybrid_level, 
                            COALESCE(ug.group_name, 'Unassigned') AS team_name,
                            r.last_day
                        FROM hris_core.employee_information_tbl s
                        LEFT JOIN intra.tag_group tg ON s.pid = tg.user_id AND tg.workspace_default = 'Y'
                        LEFT JOIN intra.user_group ug ON tg.group_id = ug.GID AND ug.workspace_status = 1
                        LEFT JOIN hris_core.resignation_tbl r ON s.pid = r.pid AND r.status = 'Resigned'
                        WHERE s.status = 'Hired' AND STR_TO_DATE(s.date_joined, '%m/%d/%Y') <= %s
                    rc   zSELECT pid, DATE(recognition_timestamp) as attendance_date FROM attendance_logs WHERE status = 'Check-in' AND pid IN ({}) AND recognition_timestamp BETWEEN %s AND %s,z%Y-%m-%d 00:00:00z%Y-%m-%d 23:59:59r   
Unassignedr   )r|   r            hybrid_levellast_dayzHybrid Group 1zHybrid Group 2r  )zHybrid Group 3zHybrid Group 3-4zHybrid Group 4)r|   r     
   r  z%m/%d/%YzJWarning: Could not calculate hybrid requirements for team summary. Error: 
group_namec              3   z   >#    U  H0  n[        UR                  S 5      5      [        T5      :X  d  M,  Uv   M2     g7f)r   N)strr6   )r   tgids     r   r   ZAttendanceLog.get_team_attendance_summary.<locals>._get_data_for_period.<locals>.<genexpr>  s5     )p5ISQRQVQVWaQbMcgjkngoMo!!5Is   +;	;total_visits_rawr   actual_unique_daysr   )r   r   r   r   r   )r9   r   r   r   r7   r8   r   r   rl   calendar
monthrangeformatr   mapr  r]   r   r   r6   
setdefaultr   r;   sortedlistremove	Exceptionr   r   get_all_teamsnextr   )0r   r   r  r   r   teamactuals_by_teamrequired_mapr   r   r   month_start_datemonth_end_daymonth_end_dater   current_week_of_monthrequired_queryparams_requiredr   r   r   monthly_logs
logs_queryparams_logsrH   rc   team_baselinesteam_adjustmentsr   r   last_day_strattended_weeksrequired_weekslast_week_of_employmentlast_day_dateweek_nummissed_target_weeksmakeup_weeksmissed_weekmakeup_weekr   all_teams_from_modelall_team_namesfiltered_teamperiod_dataactualsr   r   s0     `                                            r   _get_data_for_periodGAttendanceLog.get_team_attendance_summary.<locals>._get_data_for_periodb  s2   CI! #G9-#i/@A?sby!%77MMM#&!77}eFm<GMGX"YGXt#4d#:GX"Y  "rl'0099%LH"*--%'/'7'7A'7'>$$,$7$7$DQ$GM%5%=%=-%=%PNN" ->h,G)&N (+eO3"9&*<<'..s3NN>53IJ&,oo&7O 3BB/3CJ/DB#%L &M  &T  &T  UX  U]  U]  ^a  be  gk  ^l  Um  &n
'7'@'@AT'UWeWnWn  pC  XD  'Ez53EF#)??#4C"%e*C",6CES8I(-112CCHYDZ2[\ $5 &(N')$.$'GGK$F	&11)Q!qTU=VW(33I!qAQRVW?XY!%j # 7'*wwz':  %$4E)5)9)9#su)E)+ $44n"&66!Q"&LL`a_bn"&665M;QefdgSa-<N 34/'%080A0A0J0J<Yc0d0i0i0k#0#5#5#=-BUBUY^B^>OP]>^$; )7H'+<^+LLQY]tQt .y 9( Cq H C )7 /5T#n:MP^:^5_.`+'-d>CDW3W.X'Y+>K/;#.#<$4Y$?$LPQ$Q$L$4Y$?$LPQ$Q$L$0$7$7$D$) 0< ,?Q  /b &4	2@2KLa2beuv  fA  BW  fX  3XY/ &4 (,'9'9';$AU!VAU|"4AU!V$()p5I)prv$wM$l8S7Tn?2ll6R"&&|4 !!'^(<!=I-11)R@G+//	1=H (/{{3Eq'I%,[[q%A$,")++.BA"Fiqtuiuugkk:NPQ.RU].]ad-d'e{|.K	*	 "> #"_ #Zf CX $. % $%, ! lfghfijkkl
 "Wsq   0T?CU UFU 7AU	U  U (A"U AU V U 	
UU UU 
U=$U88U=r   r   r   r   r   r   )namer   r   r   r   r   isDangerprevTotalVisitsprevUniqueFTEprevRequired
prevActualprevPerformancez'Error getting team attendance summary: )r   r   r   r  r  r   keysr6   r9   r!   r"   r   r   r   r   )r   r   r   prev_start_dateprev_end_dater   r;  current_data	prev_datar7  formatted_summaryr   currentprevr   r   r   r   s                    @r   r   )AttendanceLog.get_team_attendance_summaryV  s    ..0DQ	[[D[1Fg#T 0
hOL,_XVI $D\->->-@)AC	HXDY)Y$Z[N "+	&**9b9 }}Y3 Xq1";;z15!((%#*;;}a#@!([!!< ($#*;;}a#@ & 1'+xxq'A%)XXk1%=$(HHZ$;"&((8Q"7'+xxq'A*  ,, %   ""

 #	 $$ 	;A3?@  ""

 #		   ""

 #s*   E F6 6H"H"H% H""H% %8I )attendance_log.csvN)rN  )NN)NNr|   r
  FN)NNN)NNr   N)NNr|      FNN)r  )NNNNN)__name__
__module____qualname____firstlineno____doc__staticmethodr   r#   rM   rT   r`   rg   rp   r   r   r   r   r   r   r   r   r   r   r   r   __static_attributes__rM  rr   r   r   r   	   s   A   > B BH 4 4l % %N  6 : :( < <| ! !F A AF R Rh ! !F  6 % %N  < c cJ . .` (" ("T Y Yrr   r   )mysql.connectorr   r4   r0   r7   r  franai.services.configr   franai.models.team_modelr   r   rM  rr   r   <module>rZ     s&     
 	   ) )g grr   