
    4jH             	         d dl mZ d dlZd dlZd dlmZ d dlmZmZmZ d dl	m
Z
 d dlmZ d dlmZmZmZmZ d dlmZmZmZ d d	lmZ d d
lmZ ddlmZ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'm(Z(  ed      Z) e
e*      jV                  Z, ed      Z-e-j]                  d ee,dz        d        ee,dz        Z/ e0 e1 e2d e,dz  jg                         D                          Z4e4e/jj                  jl                  d<    ejn                         Z8 ejr                  dd      ju                  d      Z; ejx                   ejr                  dd            Z= ej|                  e8      Z?ej                  e/jj                  jl                  d<   ddZAddZBdd ZCddd"ZDdd#ZEdd$ZFddd%ZGdd&ZHdd'ZIdd(ZJe-j                  de)      dd*       ZLdd+ZMe-j                  d,e)      ddd-       ZNe-j                  d.      dd/       ZPe-j                  d0      dd1       ZQe-j                  d2      dd3       ZRe-j                  d4      dd5       ZSe-j                  d6      dd7       ZTe-j                  d8e)      dd9       ZUe-j                  d:      dd;       ZVe-j                  d<      dd=       ZWe-j                  d>e)      dd?       ZXe-j                  d>e)       ed@       ed@       ed@      f	 	 	 	 	 ddA       ZYe-j                  dBe)      ddC       ZZe-j                  dBe)      ddD       Z[e-j                  dEe)      dddF       Z\e-j                  dG       ed!       ed!       edH      f	 ddI       Z]e-j                  dJe)      ddK       Z^e-j                  dJe)      ddL       Z_e-j                  dMe)      dddN       Z`dddOZae-j                  dP      ddQ       Zbe-j                  dR      ddS       ZcddTZde-j                  dUe)      dddV       Zee-j                  dU      ddW       Zfe-j                  dXe)      dddY       Zge-j                  dZ      ddd[       Zhe-j                  d\e)      ddd]       Ziej                  Zk eldd^      D  cg c]	  } d_| z  d` c} ZmddaZnddbZoddcZpdddZqe-j                  dee)      ddf       Zre-j                  de      ddg       Zse-j                  dhe)      ddi       Zte-j                  dh      ddj       Zue-j                  dke)      ddl       Zve-j                  dm      ddn       ZwddoZxddpZye-j                  dqe)      dddr       Zze-j                  dq      dds       Z{e-j                  dt      ddu       Z|e-j                  dv      ddw       Z}e-j                  dxe)      dddy       Z~e-j                  dx      ddz       Ze-j                  d{      dd|       Zej                  fZdd}Ze-j                  d~e)      dd       Ze-j                  de)      ddd       Ze-j                  d      dd       Ze-j                  d      dd       Ze-j                  d      dd       ZddZddZddZddZddZddZddZddZe-j                  de)      ddd       Ze-j                  d      dd       Ze-j                  d      dd       ZddZe-j                  de)      dd       Ze-j                  d      dd       ZddZddZe-j                  de)      ddd       Ze-j                  d      dd       Zg dZeD ch c]  \  }}}|s
| c}}}ZddZddZe-j                  de)      ddd       ZddZe-j                  d      dd       Ze-j                  d      dd       Zyc c} w c c}}}w )    )annotationsN)quote)datedatetime	timedelta)Path)ZoneInfo)FastAPIFormHTTPExceptionRequest)HTMLResponseRedirectResponseResponse)StaticFiles)Jinja2Templates   )boardfleetpeoplestorage	timesheetvoice)build_incident_pdfbuild_signed_pdfbuild_take5_pdfbuild_tm_pdf
page_countqr_data_urlrender_page_pngzAustralia/SydneyzLFCS Sign-On)titlez/staticstatic)	directory)name	templatesc              #  P   K   | ]  }|j                         j                     y wN)statst_mtime).0ps     /opt/lfcs-signon/app/main.py	<genexpr>r-      s     NQqvvx((Ns   $&vPUBLIC_BASE_URLzhttp://localhost:8080/TIMESHEETS_ROOTzI:/My Drive/Timesheetstelc                R    t         j                  |       }|st        dd|        |S )N  zNo job folder starting with )storefind_jobr   )job_nor$   s     r,   _job_or_404r8   '   s-    >>&!DC#?x!HIIK    c                |    t         j                  | j                  j                  t        j
                  d            S )N )crewidentifycookiesgetr   COOKIErequests    r,   _whorC   6   s&    ==,,V]]B?@@r9   c                j    | j                  t        j                  |t        j                  dd       | S )Nr0   lax)max_agepathsamesite)
set_cookier   r@   COOKIE_MAX_AGE)responsetokens     r,   _bind_cookierM   :   s,    uf6K6KRU`efOr9   r;   c                    t        j                         }t        j                  t        j                  |      |j                         dd|       t        | |       |S )zUFirst time this phone says a name: mint a token, log the request, wait for a foreman.pendingself)r   	new_tokenr<   append_device
token_hashstriprM   )rK   r$   noterL   s       r,   _claimrV   @   sG    Ev((/y&RVW5!Lr9   c                    | j                   ryt        j                  |      }|r5|j                  d      xs dj	                         j                         dk(  ry| j                  ryt        j                  |      ryy)aS  '' = let him through. 'office' = he is switched off. 'pending' = this phone is not his yet.

    Binding only bites once a bloke has an approved phone or has been switched off. Until then the
    old name-memory keeps working, so shipping this does not lock out a site whose foreman has not
    yet been told there is anything to tap.
    officestatusr;   inactiverO   )rZ   r<   personr?   rT   lowerboundenforced_for)identr$   r+   s      r,   _gater`   H   sf     ~~DAaeeHo#**,224
B{{r9   c                    	 t         j                  |       \  }}|r|st        j	                  |      }||fS # t        $ r Y yw xY w)z\Who the crew rings on THIS job. Foreman.txt beside Crew.txt; phone falls back to people.csv.r;   r;   )r5   get_foreman	Exceptionr<   phone_of)r7   r$   phones      r,   _foreman_contactrg   [   sN    ''/e Ed#;	  s   7 	AAc                ^    t        |      \  }}t        j                  | d||||||dd      S )Nzblocked.html)r7   job_namewhyr$   foreman_nameforeman_phone  status_code)rg   r%   TemplateResponse)rB   r7   ri   rj   r$   f_namef_phones          r,   _blockedrs   f   sE    &v.OFG%%g~hsD@  &  r9   c                |    t        |       }|j                  r||j                  dfS ||xs dj                         dfS )zYCommon opening move for every worker page: who is this, and does he still get a name box?Tr;   F)rC   r]   r$   rT   )rB   r7   typedr_   s       r,   
_crew_pagerv   n   s=    ME{{ejj$&&5;B%%'..r9   c           	         t        |       }t        j                         r+|j                  s|t        j                  | d|||dd      fS |dfS )u   Same rule as the foreman screen: open until the first foreman phone is bound, then his only.

    Returns (identity, response). A response means stop — hand it straight back to FastAPI.
    foreman_only.htmlr7   ri   r_   rm   rn   N)rC   r<   boss_bound_anywhereis_bossr%   rp   rB   r7   ri   r_   s       r,   
_boss_onlyr}   v   sa    
 ME!%--i00:M(UPDQT 1 V V 	V$;r9   c                   t        t        j                  |             }|D ch c]  }t        j                  |       }}t
        j                         D ]  }|j                  d      xs dj                         }|s)t        j                  |      |vsA|j                  d      xs dj                         j                         dk7  sv|j                  |       |j                  t        j                  |              |S c c}w )zZWho a foreman can tap onto a docket: this job's crew first, then anyone else still active.r$   r;   rY   activerZ   )listr5   get_crewr   normr<   r?   rT   r\   appendadd)r7   namesnseenr+   s        r,   	_pickabler      s    '(E$)*qFKKN*D*[[] %UU6] b'')Qt+x1LH0S0S0U0[0[0]ak0kLLOHHV[[^$	%
 L +s   D)response_classc                0    t         j                  | di       S )Nz	home.html)r%   rp   rA   s    r,   homer      s    %%g{B??r9   c           	        i }t         j                  |       D ]I  }|j                  d      xs dj                         }|s)|j	                  |g       j                  |       K g }t        j                        }|j                         D ]j  \  }}t        fdt        j                  |||      D        d      }	|	s3|	j                  s|	j                  s|	j                  sX|j                  ||	f       l t        |d       S )zEveryone with a tap on this job on this day, and what the day adds up to for each.

    Runs the register through the same build_week as the timesheet, per bloke, so the foreman's
    screen and his sheet can never disagree about what a tap means.
    r$   r;   c              3  B   K   | ]  }|j                   k(  s|  y wr'   )r   )r*   dwhens     r,   r-   z_job_day.<locals>.<genexpr>   s     X!SWAX   Nc                (    | d   j                         S )Nr   )r\   )xs    r,   <lambda>z_job_day.<locals>.<lambda>   s    QqTZZ\ r9   key)r5   list_attendancer?   rT   
setdefaultr   r   
week_startitemsnext
build_weekstartfinishadjustedsorted)
r7   r   nowby_namerr   outmondayevsdays
    `        r,   _job_dayr      s     &(G""6* 0UU6] b'')q"%,,Q/0 C!!$'F--/ !3Xy33CEXZ^_CIIs||JJ3x ! #122r9   z/j/{job_no}c                   t        |      }t        |       }t        j                         r)|j                  st
        j                  | d|||dd      S t        j                  t              }	 t        j                  |j                               }t        j                  |      }i }t        j!                  |      D ]C  }	|j#                  |	j%                  dd      g       j'                  |	j%                  dd             E t        j)                  |      }
g }|D ]  }|j%                  |j*                  g       }t-               g }}|D ],  }|s||vs|j/                  |       |j'                  |       . |j'                  |t0         d| d	|j2                   t5        t0         d| d	|j2                         d
| d	|j2                   dd| d	|j2                   ||
D cg c]	  }||vs| c}d        t0         d| }t0         d| }t0         d| }t        j7                  |      D 	cg c]  }	|	j%                  d      r|	 }}	t9        |||      }|D ch c]  \  }}|j;                          }}}|D cg c]  \  }}|j<                  s||f }}}|D cg c]  \  }}|j<                  r||f }}}|
D cg c]  }|j;                         |vs| }}t?        t        jA                         jC                               }tE        t        jG                         d       }t        jI                         }|D ],  }	tG        jJ                  |	j%                  dd            |v |	d<   . |jM                         } tO        |      }!|!D 	cg c]  }	|	j%                  d      | k(  s|	 c}	|!D 	cg c]2  }	|	j%                  d      | k7  s|	j%                  d      xs ddk7  s1|	4 c}	z   }"t0         d| }#t0         d| }$t
        j                  | di d|d|d|d|dt5        |      d |d!|d"t5        |      d#|d$t5        |      d%|#d&t5        |#      d'|$d(t5        |$      d)|d*||j                         k(  d+|tQ        d,-      z
  jM                         i d.|tQ        d,-      z   jM                         d/|d0|d1|d2|D 	cg c]  }	|	j%                  d      xs dd2k(  s|	 c}	d3|D 	cg c]  }	|	j%                  d      xs dd4k(  s|	 c}	d5d6 d7|d8tF        jR                  d9tT        jV                  d:|d;|
d<|"d=tY        |      d>t[               d?t\        j^                  d@dA| dBdC|       S # t        $ r |j                         }Y w xY wc c}w c c}	w c c}}w c c}}w c c}}w c c}w c c}	w c c}	w c c}	w c c}	w )DzWThe job on one screen: who's on, whose phone is waiting, the crew, and the day's times.rx   ry   rm   rn   docr;   r$   /sign/r0   /doc/.pdfz/qr/)r   urlqrpdfqr_fullsignedmissing/take5//report//on/r   c                H    | j                  d      xs dj                         S Nr$   r;   r?   r\   r   s    r,   r   zforeman.<locals>.<lambda>   s    !%%-2E21L1L1N r9   r   r]   r   rY   r   /materials//photo/zforeman.htmlr7   ri   r   	take5_urltake5_qr
open_tasks
report_url	report_qron_urlon_qrmaterials_urlmaterials_qr	photo_urlphoto_qrr   is_todayprev_dr   daysnext_don_now
signed_offnot_seenrO   knocked_backrevokediNrosterroleslunchesr_   job_crewdockets	materialsdefectslabels	board_url/board/	diary_url/diary/)0r8   rC   r<   rz   r{   r%   rp   r   r   TZr   fromisoformatrT   
ValueErrorr5   	list_docslist_registerr   r?   r   r   filenamesetr   BASEslotr   
list_take5r   r\   r   r   latest_by_tokenvaluesr   r   approved_namesr   	isoformat_tm_rowsr   ROLESr   LUNCH_CHOICES_open_materials_open_defectsr   MATERIAL_STATUS)%rB   r7   r   ri   r_   r   r   docsr   r   r   r   r   r   r   uniqr   cr   r   r   r   day_rows_
seen_todayr   onoffr   devicesr   approvedday_isotm_rowsr   r   r   s%                                        r,   foremanr      s    6"HME !%--))'3F(UIDQT * V 	V ,,r
C!!!''), ??6"D#%F  ( J!%%r*B/66quuVR7HIJ~~f%HE J

3<<,UBd 	,AQd]T[[^	, 	SD6xq
)KS^bfaggmntmuuvwzww  wA  `B  TC$VHAchhZt<4PVxWXY\YaYaXbIcos-5!G$!!GI 	JJ &x(I6&*JvT&"F"--f5MQUU8_!MJM c*H(011!'')1J1%	2TQ1a&	2B	2&
7daahhAq6
7C
7#Caqwwy
'BCHC4'')0023GDKKM'NOF""$H @[[vr!23x?'
@
 nnGvG!>QQUU6]g%=q>!fQQUU6]g%=155?CXVX]eBeqfgGfKx0M&x(I%%g~ @&@$h@07@Y@ *K	,B@DPR\@ 	j@ #.{:/F@ 	&	@ ";v#6	@
 	@
 )7M8R@ 	Y@ !+K	,B@ 	@ !$#((*"4@ 	4)++668@ ;CTI[\L]E]DhDhDj@ 	"@ #C@ *4X@ 	wO!155?+@bY*NAO@ 	GTqh0E2)/STUWUXY@ 	&@ "6<<@ 2;I<S<S@ 	@ #H@ 	7@ ()@@ CL]_@ 	'))@" 	wvh'#@" *5x6H#@  ]  xxz$ "H N 2	2
7C ?f PTs   .#V #	V2-V24V7V7#V<WW(W=W
W"WW1W;WW.WW6WW" W"V/.V/z/device/{job_no}/claimc                  K   t        |       | j                          d{   }t        |j                  dd            j	                         }t        |j                  dd            j	                         xs d| }|st        dd      |j                  d      sd| }d	|v rd
nd	}t        | | dt        |       d      }t        |       }|j                  st        ||d|        |S 7 Эw)z]'That's me' on a phone with no token yet. Mints one, logs a pending request, sets the cookie.Nr$   r;   r   r     Pick your name firstr0   ?&zname=/  rn   job rU   )r8   formstrr?   rT   r   
startswithr   r   rC   thashrV   )rB   r7   r  r$   nxtseprespr_   s           r,   device_claimr     s      Dtxx#$**,D
dhhvr"
#
)
)
+
>fXCC!788>>#VHo#CseC5eDk];MDME;;tT$vh0K  s   C4C2CC4z/j/{job_no}/devicec                  K   t        |       t        |       }t        j                         r|j                  st        dd      | j                          d{   }t        |j                  dd            j                         }t        |j                  dd            j                         }t        |j                  dd            j                         j                         }|r|dvrt        d	d
      |j                  xs d}|dk(  rJt        j                  ||d|d|        t        j                  |      s5t        j                  |d|       nt        j                  ||d|d|        t        d| dd      S 7 ,w)zYAPPROVE binds this token to this bloke. NOT HIM kills it. Both are new rows, never edits.rm   Foreman onlyNr	  r;   r$   action)approverejectr   zWhich phone, and yes or no?r   r  r   r  worker)rolebyr   u   not him — job /j/z#phonesr  rn   )r8   rC   r<   rz   r{   r   r  r  r?   rT   r\   r$   rR   r[   upsert_personr   )rB   r7   r_   r  r	  r$   r  r  s           r,   device_decider    sN     ME!%--C00D"%&,,.Etxx#$**,D(B'(..0668FF"77C!>??		 yB5$
B$vhH{{4 t(r:5$	29I&7RSc&1sCC  s   AFFD,Fz/j/{job_no}/crewc           
     <  K   t        |       t        |       }t        j                         r|j                  st        dd      | j                          d {   }t        |j                  dd            j                         }|st        dd      t        j                  |t        |j                  dd            j                         t        |j                  d	d            j                         |j                  xs d
       t        d| dd      S 7 w)Nrm   r  r$   r;   r   zName is requiredr  r  rf   r   )r  rf   r  r  #crewr  rn   )r8   rC   r<   rz   r{   r   r  r  r?   rT   r  r$   r   )rB   r7   r_   r  r$   s        r,   crew_addr  (  s     ME!%--C00Dtxx#$**,DC!344t#dhhvx&@"A"G"G"I '2!67==?EJJD[R[  ]c&/SAA  s   ADDCDz/j/{job_no}/crew/togglec                6  K   t        |       t        |       }t        j                         r|j                  st        dd      | j                          d{   }t        |j                  dd            j                         }t        j                  |      }|st        dd      |j                  d      xs d	j                         j                         d
k7  }t        j                  ||rd
nd	|j                  xs d       t        d| dd      S 7 w)zYOne tap. Inactive kills every one of his phones and every route answers 'See the office.'rm   r  Nr$   r;   r4   zNot on the crew listrY   r   rZ   r   r  r  r  rn   )r8   rC   r<   rz   r{   r   r  r  r?   rT   r[   r\   
set_statusr$   r   )rB   r7   r_   r  r$   r+   
now_actives          r,   crew_toggler  7  s      ME!%--C00Dtxx#$**,DDAC!788%%/-X446<<>*LJOOD
*%**BYPYZc&/SAA  s   ADDB?Dz/j/{job_no}/adjustc                  K   t        |      }t        |       }t        j                         r|j                  st        dd      | j                          d{   }t        |j                  dd            j                         t        |j                  dd            j                         }	 t        j                  t        |j                  dd            j                               }r|st        dd
      t        j                  t              }t!        fdt#        |||      D        d      }|r|j$                  nd|r|j&                  nd|r|j(                  ndd}	|j*                  xs d}
d}dD ]  }t        |j                  |d            j                         }|s/|j-                  d      |dddd|j-                         ||	|   |||
d}t.        j1                  ||       t2        j5                  |       |dz  } |st        dd      	 t7        j8                  |      }t7        j:                  t2        j=                        ||      }t2        j?                  |t7        j@                  ||             tI        d| d|j-                          dd      S 7 P# t        $ r t        dd	      w xY w# tB        $ r tE        jF                          Y ]w xY ww)u^   Correct a man's day. The tap he made stays exactly where it is — this is a row on top of it.rm   r  Nr$   r;   reasonr   r   z
Which day?u@   Name and a reason are both required — the reason is the recordc              3  4   K   | ]  \  }}|k(  s|  y wr'    )r*   r   r   r$   s      r,   r-   zadjust.<locals>.<genexpr>Z  s     JAT	1Js   )r   r   lunchr   r   secondstimespecadjust	timestampjobr$   eventr$  rU   sourcer   fieldoldnewr!  r  r   u6   Nothing to change — fill in a start, finish or lunchr  z?d=z#timesr  rn   )%r8   rC   r<   rz   r{   r   r  r  r?   rT   r   r   r   r   r   r   r   r   
start_textfinish_text
lunch_textr$   r   r5   append_attendance
crew_filesappend_eventr   r   r   list_events
write_weekrender_xlsxrd   	traceback	print_excr   )rB   r7   ri   r_   r  r!  r   r   beforeoldsr  wrotefldvalrowr   r   r$   s                    @r,   r(  r(  H  s     6"HME!%--C00Dtxx#$**,D(B'(..0F/!!#dhhub&9":"@"@"BC vC!cdd
,,r
CJ&$!<JDQF*0V&&bZ`FDVDVfh*0V&&b:D		 yBE+ 
$((3#$**,MM9M=hX\ 2rYnn&T#Ysr+ 	,c*

 C!YZZ%%d+##J$:$:4$@&#NdFI,A,A$PT,UV c&T^^-=,>fESVWWK  
  /C../<  sQ   AK(J)AK(1<J, -D.K(A+K #K(,KK(K%"K($K%%K(z/qr/{job_no}/{kind}c                   t        |      }t         d| dft         d| dft         d| dft         d| dft         d	| d
fd}|v r	|   \  }}nZt        fdt        j	                  |      D        d      }|st        dd      t         d| d|j                   |j                  }}t        j                  | d||||t        |      d      S )zYTap a QR, get a white page and the biggest code the phone can draw. Sun beats a small QR.r   zSign on / sign offr   zTake 5r   zReport a hazard / near missr   zShort of something?r   z
Site photo)r   take5reportr   photoc              3  B   K   | ]  }|j                   k(  s|  y wr'   )r   )r*   r   kinds     r,   r-   zqr_full.<locals>.<genexpr>  s     I!!&&D.AIr   Nr4   zNothing to show a QR forr   r0   zqr.html)r7   ri   r!   r   r   )r8   r   r   r5   r   r   r   r   r%   rp   r   )rB   r7   rG  ri   fixedr   r!   r   s     `     r,   r   r   w  s    6"HfD)+?@wvh/:&13PQ"V;vh79NOwvh/>	@E
 u}4[
UIuv6I4P%?@@vVF81SXXJ7U%%gyhsR]^aRb;d e er9   z/doc/{job_no}/{slot}.pdfc                    t        |        t        j                  | |      }|st        dd      |\  }}t	        |ddd|j
                   di      S )Nr4   Document not foundapplication/pdfContent-Dispositioninline; filename=""
media_typeheaders)r8   r5   get_docr   r   r   )r7   r   gotr   datas        r,   doc_pdfrU    s_    
--
%CC!566ICD%626HVW4XY[ [r9   z!/doc/{job_no}/{slot}/page/{n}.pngc                    t        |        t        j                  | |      }|st        dd      t	        t        |d   |      dddi      S )zXPage rendered as PNG so phones scroll it like a web page (iframe PDFs are flaky on iOS).r4   rJ  r   z	image/pngCache-Controlzpublic, max-age=300rO  )r8   r5   rR  r   r   r    )r7   r   r   rS  s       r,   doc_page_pngrX    sT     
--
%CC!566OCFA.;,.CDF Fr9   z/sign/{job_no}/{slot}c                   t        |      }t        |       }|j                  rt        | ||d|j                        S t
        j                  ||      }|st        dd      |\  }}t        j                  | d|||t
        j                  |      d| d| dt        t        dt        |      dz               |j                  r|j                  nd	|j                  d
      S )NrX   r4   z*Document not found. Check the Docs folder.z	sign.htmlr   r0   r   r   r;   )r7   ri   r   r<   pdf_urlpagesr$   locked)r8   rC   rZ   rs   r$   r5   rR  r   r%   rp   r   r   ranger   r]   )rB   r7   r   ri   r_   rS  r   rT  s           r,   	sign_pager^    s    6"HME~~8UZZHH
--
%CC!MNNIC%%g{v[clo'eF81TF$4OuQ
4 01 456${{ekk=K  r9   .c                   t        |      }t        j                  ||      }|st        dd      |\  }}	|j	                         }t        |       }
|
j                  r|
j                  }|rt        |
|      nd}|rt        | ||||      S |r|dk7  s|j                  d      st        dd      t        j                  t              }| j                  j                  dd      }t!        |	| d	| |j"                  |j$                  ||||
      }t'        j(                  |||      }t        j+                  |||      }t        j-                  ||j/                  d      ||j"                  |j$                  |||d d d       t1        d| d| dt3        |       dt3        |j5                  d             d      }|
j6                  st9        ||d|        |S )Nr4   rJ  r;   yesdata:image/pngr   z1Name, confirmation and signature are all required
user-agent )r+  doc_namerevr$   r   sig_data_url
user_agentr%  r&     )r*  r+  r   re  r$   signed_filerg  z/done/r0   ?name=&t=%d/%m/%Y %H:%Mr  rn   r  r  )r8   r5   rR  r   rT   rC   r]   r$   r`   rs   r  r   r   r   rQ  r?   r   r   re  r   signed_filename
put_signedappend_registerr   r   r   strftimer	  rV   )rB   r7   r   r$   	confirmed	signatureri   rS  r   originalr_   rj   r   uar   fnamewherer  s                     r,   sign_submitrw    s    6"H
--
%CC!566MC::<DME{{zz $%t
"C
3==9%Y-A-ABR-SC!TUU
,,r
C			\2	.Bhvhaz,BS\\_b_f_f#'c	VXZF##Cs3EVUF3E	&]]I]6vcllwwU"Tc(# 
 fVHAdV6%+c%PSP\P\]mPnJoIpq(+-D
 ;;tT$vh0Kr9   z/take5/{job_no}c                   t        |      }t        |       }t        j                  | d||t        j                  |      t        t        t        j                  |                  |j                  r|j                  nd|j                  d      S )zRWorker's own phone. Name, task in his words, tick hazards, sign. Under 30 seconds.z
take5.htmlr;   )r7   ri   r<   hazardsr$   r\  )r8   rC   r%   rp   r5   r   r   	enumerateget_hazardsr]   r$   r|   s       r,   
take5_pager|    sp     6"HME%%g|hv8N	%"3"3F";<=#kk

rU[[>  r9   c                  K   t        |      }| j                          d {   }t        |j                  dd            j	                         }t        |j                  dd            j	                         }t        |j                  dd            j	                         }t        |j                  dd            }|j                  d      }t        |       }	|	j                  r|	j                  }|rt        |	|      }
|
rt        | |||
|      S |r|r|j                  d      st        dd	      t        j                  |      }g }|D ]   }	 |j                  |t!        |                " t'        j(                  t*              }| j,                  j                  d
d      }|j/                  d      dz   t1        j2                  |      d d z   }t5        |||||||||	      }t1        j6                  t1        j8                  ddd      ||      }t        j;                  |||       t        j=                  |||j?                  d      |||djA                  d |D              djA                  d |D              |||d d ddddd       tC        d| dtE        |       dtE        |j/                  d             dtE        |d d        d      S 7 # t"        t$        f$ r Y w xY ww) Nr$   r;   taskotherrr  hzra  r   z)Name, task and signature are all requiredrb  %Y%m%d-%H%M%S-   )	r+  r$   r~  r   ry  r  rf  rg  take5_idrC  z	Take5.pdfr%  r&  z ; c              3  &   K   | ]	  \  }}|  y wr'   r#  )r*   hr   s      r,   r-   ztake5_submit.<locals>.<genexpr>
  s     3DAqa3   c              3  ,   K   | ]  \  }}|s	|  y wr'   r#  )r*   r   r   s      r,   r-   ztake5_submit.<locals>.<genexpr>
  s     KfRVRSUVdeAKfs   
rh  )idr   r+  r$   r~  ry  controlsr  ri  rg  r   qtyunitfinished_byr   z/done?name=rk  rl  z&task=P   r  rn   )#r8   r  r  r?   rT   getlistrC   r]   r$   r`   rs   r  r   r5   r{  r   intr   
IndexErrorr   r   r   rQ  rp  r   slot_ofr   rm  Doc	put_take5append_take5r   joinr   r   )rB   r7   ri   r  r$   r~  r  rr  pickedr_   rj   all_hzchosenir   rt  t5_idr   safes                      r,   take5_submitr    s    6"HDtxx#$**,Dtxx#$**,D"%&,,.EDHH["-.I\\$FME{{zzE4 GVXsDAAt9#7#78H#IC!LMMv&FF 	MM&Q.)
 ,,r
C			\2	.BLL)C/'//$2G2LLE
hT3PV %I"W\^C""7;;wR#H$PSTD	OOFD#&	vcmmYm?X\fj::3F33KfZ`KfAft2ds8RB	   gfX[tSs||\lOmInHoouv{  }A  BE  CE  }F  wG  vH  I(+- -G  ( J' 		s5   K(KD*K(K*E&K(K%!K($K%%K(z/take5/{job_no}/donec           	     P    t        |       t        j                  | d||||d      S )Nztake5_done.html)r7   r$   r   r~  )r8   r%   rp   )rB   r7   r$   tr~  s        r,   
take5_doner    s,    %%g/@V]aklvzB{||r9   z!/take5/{job_no}/{take5_id}/finishr   c           	     |   t        |      }t        | ||      \  }}|r|S |j                  xs |}t        j                  t
              }	t        j                  |||	j                  d      |j                         |j                         |j                         d      }
|
st        dd      t        d| dd	      S )
u9  Foreman taps Done on the open-tasks list. qty/unit optional — the desk turns start/finish/qty into rates.

    Foreman-only: closing a task off is the desk saying the work happened, and the qty on it is the
    number a rate gets built from. It was always meant to be his tap, and take-5 ids are guessable.
    r%  r&  )r   r  r  r  r4   zTake-5 record not foundr  z#tasksr  rn   )r8   r}   r$   r   r   r   r5   finish_take5r   rT   r   r   )rB   r7   r  r  r  r  ri   r_   blockr   oks              r,   take5_finishr    s     6"Hgvx8LE5		rB
,,r
C			FH---3CIIKQUQ[Q[Q]npnvnvnx/ 
B C!:;;c&0cBBr9   z/report/{job_no}c                    t        |      }t        |       }t        j                  | d||t        j                  |      t        j                  |j                  r|j                  nd|j                  d      S )zgOne form, three kinds. Words + photo. Under a minute. If someone is hurt: first aid + phone call first.zreport.htmlr;   )r7   ri   r<   kindsr$   r\  )
r8   rC   r%   rp   r5   r   r   INCIDENT_KINDSr]   r$   r|   s       r,   report_pager  1  sa     6"HME%%g}hv8NY`YoYo#kk

rU[[?  r9   c                J  K   t        |      }| j                          d {   }t        |j                  dd            j	                         }t        |j                  dd            j	                         }t        |j                  dd            j	                         }t        |j                  dd            j	                         }t        |j                  dd            j	                         }t        |j                  dd            j	                         }	t        |j                  dd      xs d      }
t        |       }|j                  r|j                  }|rt        ||      }|rt        | ||||      S |t        j                  vs|r|st        d	d
      |j                  d      }d }|2t        |dd      r%|j                          d {   }|rt        |      }t!        j"                  t$              }| j&                  j                  dd      }|j)                  d      dz   |z   }|dd| dt        j*                  |      d d  }d}|r|dz   }t,        j/                  |||       t1        |t        j                  |   |||||	|||
||      }|dz   }t,        j/                  |||       t,        j3                  |||j5                  d      |||||||	|||d d ddd       t7        d| d| dt9        |j)                  d             d      S 7 7 Lw) NrG  r;   r$   whatrv  whor  rr  r   z)Type, name and what happened are requiredrE  r   rb  r  r  z%Y-%m-%d_%H%Mr      .jpg)r+  
kind_labelr$   r  rv  r  r  r   
photo_jpegrf  rg  	report_idr   r%  r&  rh  )r  r*  r+  rG  r$   r  rv  r  r  
photo_filepdf_filerg  followuptoolbox_dater   z/done?kind=rk  rl  r  rn   )r8   r  r  r?   rT   rC   r]   r$   r`   rs   r   r  r   getattrread_to_jpegr   r   r   rQ  rp  r  r5   put_incident_filer   append_incidentr   r   r   )rB   r7   ri   r  rG  r$   r  rv  r  r  rr  r_   rj   rE  photo_bytesrawr   rt  ridstemr  r   r  s                          r,   report_submitr  <  s    6"HDtxx#$**,Dtxx#$**,Dtxx#$**,D"%&,,.E
dhhub!
"
(
(
*C(B'(..0FDHH["-34IME{{zzE4 GVXsDAA7)))TC!LMMHHWEKWUJ;JJL "3-K
,,r
C			\2	.B
,,
'#
-
4C- $q)>s)C(DEDJF]

K@
g6L6LT6RY]dhpu!$V#+dm(*c;C f}H	FHc2	&y A&Z^hluSFR\jr#hB# 
 hvhk$s5VfIgChBijx{||S  ( !s#   L#LF2L#L E	L# L#z/report/{job_no}/donec           
         t        |       t        j                  | d||t        j                  j                  |d      |d      S )Nzreport_done.htmlr;   )r7   rG  r  r   )r8   r%   rp   r   r  r?   )rB   r7   rG  r  s       r,   report_doner  k  sJ    %%g/A$g6L6L6P6PQUWY6ZdeDg h hr9   c                .   ddl m} ddlm}m} 	 |j                   ||             }|j                  |      j                  d      }|j                  ||f        |       }|j                  |ddd       |j                         S # t        $ r | cY S w xY w)	zWPhone photos are 3-8 MB HEIC/JPEG. Downsize + re-encode so the PDF and Drive stay sane.r   )BytesIO)ImageImageOpsRGBJPEGR   T)formatqualityoptimize)ior  PILr  r  openexif_transposeconvert	thumbnailsavegetvaluerd   )r  max_pxr  r  r  imgr   s          r,   r  r  r  s    #jj&%%c*2259vv&'iVR$?||~ 
s   A5B BBz/incident/{job_no}/{filename}c                   t        |      }t        | ||      \  }}|r|S t        t        j                  dd       t
        j                  fz   }t        j                  |||      }|t        dd      t        |dddi      S )	a  The photo off a hazard/near-miss report, for the diary. Foreman only.

    An incident photo can have somebody's injury in it, or somebody else's mistake. It shows on the
    diary because that is where it belongs in evidence, and the diary is already foreman-only.
    Nr4   Photo not found
image/jpegrW  private, max-age=300rO  )
r8   r}   tupler5   signon_partsr   	INCIDENTSget_job_filer   r   )rB   r7   r   ri   r_   r  partsrT  s           r,   incident_photor    s     6"Hgvx8LE5%$$Sb)*g.?.?-AAEfeX6D|C!233D\OMc;deer9   z/prestart/{job_no}c                d   t        |        t        j                  |       D cg c]=  }d|j                  j	                         v sd|j                  j	                         v s<|? }}|st        dd      ddlfd}t        ||d	      d   }t        d
|  d|j                   d      S c c}w )zcStable link for the WhatsApp pin: always opens the newest prestart in Docs/ (they are dated files).z	pre-startprestartr4   z4No prestart up yet for this job. Ask the supervisor.r   Nc                    j                  d| j                        }|r2|j                  d      |j                  d      |j                  d      fS dd| j                  fS )Nz(\d{2})-(\d{2})-(\d{4})      r   r;   )searchr   group)r   mres     r,   r   zprestart_latest.<locals>.key  sO    II0!**=78
AGGAJ
3Rr2qzz>RRr9   T)r   reverser   r0   i.  rn   )
r8   r5   r   r   r\   r   r  r   r   r   )r7   r   r   r   newestr  s        @r,   prestart_latestr    s     v.x!+AQAQAS2SWaefeoeoeueuewWwAxDxC!WXXS Dc403FfVHAfkk];MM ys   =B-"B-c                   	 t        j                  t        j                  | j	                                     S # t
        $ r= t        j                  t        j                  t              j                               cY S w xY w)uQ   ?w=YYYY-MM-DD picks a week. Anything else — including nothing — is this week.)	r   r   r   r   rT   r   r   r   r   )ws    r,   _mondayr    s[    =##D$6$6qwwy$ABB =##HLL$4$9$9$;<<=s   58 AA>=A>z/on/{job_no}c                   t        |      }t        | ||      \  }}}t        j                  t              }|rt
        j                  |      ng }	t        j                  |	|      }
|r8t        j                  |	t        j                  |j                               |      ng }t        d |D        d      }t        |      \  }}|rt        ||      nd}t        j!                  | di d|d|d|dt"        j%                  |      d	|
d
|
rt        j&                  |
      ndd|
r|
j)                         nddt        j&                  |      d|d|r|j*                  ndd|r(t        j,                  t        j.                  |            nddt        j0                  dt        j2                  d|d|d|d||t5        |      d      }|r|j6                  st9        ||d|        |S )zaThe worker's own phone. Signed off -> one button. Signed on -> lunch is already 0:30, one button.c              3  :   K   | ]  }|j                   s|  y wr'   )r   )r*   r   s     r,   r-   zsignon_page.<locals>.<genexpr>  s     0QZZ!0s   Nr;   zon.htmlr7   ri   r$   r<   since
since_text	since_isonow_textflashtoday_hours
week_hoursr   r   default_lunchr\  waitrk   rl   )viatomorrow_jobr  r  )r8   rv   r   r   r   r5  r7  r   
open_sincer   r   r   r   rg   r`   r%   rp   r5   r   fmt_ampmr   
hours_textnumr  r   DEFAULT_LUNCH_tomorrow_jobr	  rV   )rB   r7   r$   r  r  ri   r_   r\  r   eventsr  r   todayrq   rr   r  r  s                    r,   signon_pager    s&    6"H$Wfd;E4
,,r
C-1Z##D)rF  -ERV9	(<(<SXXZ(H#N\^D0T0$7E&v.OFG!%52D%%gy 
;&
;$h
;06
;>DennU[F\
;
;$5i&8&8&?b
; 	%U__&R
; 	I&&s+	
; .5e	
;
 	5u''b
;
 ;Guy	V_VjVjkoVpHq  @A
; 	9**
; -<Y=T=T
; 	&
; !$
; )7
; APQX
; M$$7
; 
D EKKtT$vh0Kr9   c           	       K   t        |      }| j                          d {   }t        |j                  dd            j	                         }t        |j                  dd            j	                         j                         }t        |j                  dt        j                              j	                         }t        |j                  dd            j	                         }t        |       }|j                  r|j                  }|r|dvrt        dd      t        ||      }	|	rt        | |||	|      S |t        j                  vrt        j                  }t        j                   t"              }
t        j$                  t&        j)                  |      |
      }|d	k(  r|rt+        d
| dt-        |       dd      S |dk(  r|st+        d
| dt-        |       dd      S |
j/                  d      ||||dk(  r|nd|dd}t0        j3                  ||       t&        j5                  ||       |}|dk(  rzt        j6                  |
j9                               }	 t        j:                  t&        j)                  |      ||
      }t&        j=                  ||t        j>                  |||             t+        d| dt-        |       d| d      S 7 # t@        $ r tC        jD                          d}Y Cw xY ww)Nr$   r;   r  r$  rU   )r   r   r   z!Name and on/off are both requiredr   r   rj  z&flash=already-onr  rn   r   z&flash=already-offr%  r&  r  )r*  r+  r$   r,  r$  rU   r-  zoff-nosheetz/week/z&flash=)#r8   r  r  r?   rT   r\   r   r  rC   r]   r$   r   r`   rs   r   r   r   r   r  r5  r7  r   r   r   r5   r4  r6  r   r   r   r8  r9  rd   r:  r;  )rB   r7   ri   r  r$   r  r$  rU   r_   rj   r   r  rA  r  r   r   s                   r,   signon_submitr    s    6"HDtxx#$**,D(B'(..0668F)"9"9:;AACEtxx#$**,DME{{zz6.C!DEE
t
C
3==I+++''
,,r
C  !7!7!=sCE~%$vhfU4[MAR Sadeeu$vhfU4[MAS Tbeffy9(TXci#u_E"dhXC	FC(D#&E%%chhj1	"''
(>(>t(DfcRD!!$	0E0EdFTX0YZ
 fVHF5;-wugN\_``Q  H  	"!!E	"s5   K9KH9K9AK 2 K9K63K95K66K9z/week/{job_no}c                   t        |      }t        | ||      \  }}}t        j                  t              }t        |      }	|rt        j                  |      ng }
t        j                  |
|	|      }t        |      \  }}t        j                  | di d|d|d|dt        j                  |      d|d|	dt        j                  |	      d	t        j                   t        j"                  |            d
|	t        j$                  |j'                               k(  d|	t)        d      z
  j+                         d|	t)        d      z   j+                         d|	j+                         d|dt        j,                  |
|      dud|d|d|dt/        |      i      }|r|j0                  st3        ||d|        |S )u_   My week — the real LFCS timesheet, filling itself in. His own week only, never anyone else's.z	week.htmlr7   ri   r$   r<   r   r   fridaytotal	this_weekprev_w   r   next_wr  r  r   Nr\  rk   rl   r  r  r  )r8   rv   r   r   r   r  r5  r7  r   r   rg   r%   rp   r5   r   week_endingr   r  r   r   r   r   r  r  r	  rV   )rB   r7   r$   r  r  ri   r_   r\  r   r   r  r   rq   rr   r  s                  r,   	week_pager    s    6"H$Wfd;E4
,,r
CQZF-1Z##D)rF4D&v.OFG%%g{ =&=$h=06=>DennU[F\===(0)2G2G2O= 	y33D9:= 	Vy33CHHJ??	=
 	6I1--88:= 	6I1--88:= 	V= ")%= 	)&&vs34?= 	&= )&= 3B7= 	d+= D EKKtT$vh0Kr9   z/week/{job_no}/xlsxc           
     \   t        |       |j                         }|st        dd      t        |       }|j                  rM|j
                  sAt        j                  |      t        j                  |j                        k7  rt        dd      |j                  s!t        j                  |      rt        dd      t        |      }t        j                  t        j                  |      |      }t        j                   |||      }t#        |dddt        j$                  ||       d	i
      S )u  The same sheet the office gets, on his phone. His own week only — never another man's.

    A worker must not see another worker's hours, and until now the name was just a query
    parameter anyone could retype. Three states, because the site is mid-rollout:

      bound worker  - his own name or nothing
      foreman/admin - anyone, same as the foreman screen he already has
      unbound       - allowed, because Rocky is solo-trialling on a phone that has never claimed
                      a name and locking him out would kill the trial. But NOT for a bloke who
                      already has an approved phone: once binding is live for a man, his sheet
                      comes off his phone or it does not come at all.
    r   z&Open My week and pick your name first.rm   zThat is not your timesheet.zOpen My week on your own phone.zAapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheetrL  zattachment; filename="rN  rO  )r8   rT   r   rC   r]   r{   r   r   r$   r<   r^   r  r   r   r5  r7  r9  r   week_filename)rB   r7   r$   r  r_   r   r   rT  s           r,   	week_xlsxr    s     ::<DC!IJJME{{5==V[[->&++ejjBY-YC!>??;;4,,T2C!BCCQZF
 6 6t <fED  vt4DD%h26LYMdMdeikqMrLsst4uvx xr9   z/done/{job_no}/{slot}c           	         t        |       t        j                  ||      }|r|d   nt        j                  ||d      }t
        j                  | d||||d      S )Nr   r;   z	done.html)r7   r   r$   r   )r8   r5   rR  r   r  r%   rp   )rB   r7   r   r$   r  rS  r   s          r,   doner  6  sU    
--
%C#a&W[[tR8C%%g{vVYcgqr<sttr9      g      ?gc                T    t         j                  | t        t        j                        S r'   )r5   read_job_csvTMr   TM_REGISTERr7   s    r,   r   r   M  s    fb'*=*=>>r9   c                @    t        fdt        |       D        d       S )Nc              3  T   K   | ]  }|j                  d       xs dk(  s| ! ywr  r;   Nr?   r*   r   	docket_ids     r,   r-   z_tm_find.<locals>.<genexpr>R  s%     Qqt1By0PQ   (()r   r   )r7   r"  s    `r,   _tm_findr$  Q  s    QHV,QSWXXr9   c                F   g }| j                  d      xs dj                  d      D ]U  }|j                         }|s|j                  d      \  }}}	 |j	                  |j                         t        |      f       W |S # t        $ r |j	                  |df       Y xw xY w)zR'Dave Nguyen 4.5; Matty Bell 6' back into pairs. Plain text in the CSV on purpose.hoursr;   ;rc          )r?   splitrT   
rpartitionr   floatr   )rA  r   partr$   r   hrss         r,   _tm_menr.  U  s    
C!'R..s3 $zz|s+a	$JJ

eCj12$ J  	$JJc{#	$s   *BB B c                   t        j                  t              }|j                  d      ||dd|d|ddd|dd |d	}t        j                  | |       t        j                  ||       	 t        j                  t        j                  |            }	t        j                  t        j                  |      |	|      }
t        j                  ||	t        j                  ||	|
             y# t         $ r t#        j$                          Y yw xY w)
u  He was on a signed docket that day, so Day Works on his timesheet says Y.

    Written as an event beside his taps rather than stamped onto a rendered sheet, so any later
    rebuild picks it up on its own. It never touches his hours — the Y/N column only.
    r%  r&  dayworksr;   r   YNd   r)  )r   r   r   r   r5   r4  r5  r6  r   r   r   r   r   r7  r8  r9  rd   r:  r;  )r7   ri   r$   r   r"  r  rj   r   rA  r   r   s              r,   _mark_dayworksr3  d  s     ,,r
Cy9(TXY)
2cSQURUY^`bC 
FC(D#&%%d&8&8&=>##J$:$:4$@&#NdFI,A,A$PT,UV s   *A>C) )D	D	z/tm/{job_no}/newc                    t        |      }t        | ||      \  }}|r|S t        j                  | d||t	        |      t
        t        j                  t              j                         |d      S )Nztm_new.html)r7   ri   r<   r&  r  r_   )
r8   r}   r%   rp   r   TM_HOURSr   r   r   r   )rB   r7   ri   r_   r  s        r,   tm_newr6  y  sg    6"Hgvx8LE5%%g}h	&8IHLL$4$9$9$;e?  r9   c                Z  K   t        |      }t        | ||      \  }}|r|S | j                          d {   }t        |j	                  dd            j                         }t        |j	                  dd            j                         }|j                  d      D cg c]5  }t        |      j                         st        |      j                         7 }	}|r|	st        dd      g }
|	D ]c  }	 t        t        |j	                  d|z   d            j                         xs d      }|dk  rt        dd
|z         |
j                  ||f       e t        j                  t              }|j                         j                         dt!        fdt#        |      D              dz   z  }dz   |z   }t$        j'                  |t(        t*        j,                  t*        j.                  i d|d|j                  d      d|dd|d|ddj1                  d |
D              ddj1                  d |
D              dt!        d |
D              dd|d|j2                  xs dddd dd!dd"dd#d$       t5        d%| d&| d'd()      S 7 [c c}w # t        $ r d	}Y zw xY ww)*Ndescriptionr;   plantmenr   z<A docket needs the work described and at least one man on itzhours|r   r(  zNo hours on z%02dc              3  T   K   | ]  }|j                  d       xs dk(  sd ! yw)r   r;   r   Nr   )r*   r   r   s     r,   r-   ztm_create.<locals>.<genexpr>  s&     Taf8KPS7STr#  r   r  r  r*  r%  r&  r+  r   seq; c              3  &   K   | ]	  \  }}|  y wr'   r#  )r*   r  r   s      r,   r-   ztm_create.<locals>.<genexpr>  s     -tq!-r  r&  c              3  2   K   | ]  \  }}| d |d  yw)rc  r  Nr#  )r*   r  r  s      r,   r-   ztm_create.<locals>.<genexpr>  s      :DAqaS!A<:s   hours_totalc              3  &   K   | ]	  \  }}|  y wr'   r#  )r*   r   r  s      r,   r-   ztm_create.<locals>.<genexpr>  s     2DAqa2r  r  	raised_byr   	signed_bycompany	signed_atr  rY   draft/tm/r0   z/signr  rn   )r8   r}   r  r  r?   rT   r  r   r+  r   r   r   r   r   r   r   sumr   r5   append_job_csvr  r   r  	TM_HEADERr  r$   r   )rB   r7   ri   r_   r  r  r8  r9  r  r:  pairsr  r   r<  r"  r   s                  @r,   	tm_createrL    s    6"Hgvx8LE5Ddhh}b1288:K"%&,,.E#'<<#6
Ia#a&,,.3q6<<>
IC
IcC!_``%'E 	c$((8a<45;;=BCA 6^a%788aV ,,r
C
((*


 C
CT8F#3TTWXX
YCc	CI	W%8%8':K:K NiN$cmmYm&GNINPVNX^`cNsN!;N 	tyy-u--N 	:E::	N
 	#2E2215N 	N $UZZ%<9N 	RN #BN )4RN :DRN JRSZN  d6(!I;e<#NN;   J  	A	sM   3J+JA)J+ J?JJ+49J-E%J+J+J($J+'J((J+z/tm/{job_no}/{docket_id}/signc           
     ,   t        |      }t        | ||      \  }}|r|S t        |      }t        fd|D        d      }|st	        dd      g t               }	}|D ]  }
|
j                  d      xs dj                         |
j                  d      xs dj                         }}|sL|j                         |	vs_|	j                  |j                                |j                  ||f        t        j                  | d|||t        |      |d	      S )
zPHand the phone over. The super's name and company get typed once, then he signs.c              3  T   K   | ]  }|j                  d       xs dk(  s| ! ywr  r   r!  s     r,   r-   ztm_sign_page.<locals>.<genexpr>  %     DaAEE$K$52)#CDr#  Nr4   No such docketrC  r;   rD  ztm_sign.html)r7   ri   rA  r:  reps)r8   r}   r   r   r   r   r?   rT   r\   r   r   r%   rp   r.  )rB   r7   r"  ri   r_   r  rowsrA  rQ  r   r   r  cos     `          r,   tm_sign_pagerT    s    6"Hgvx8LE5FD
D4Dd
KCC!122SU$D #55%+224quuY7G7M26T6T6VR399;d*HHSYY[!KKb	"	#
 %%g~hs73<Y]@  r9   c                :  K   t        |      }t        | ||      \  }}|r|S t        |      }t        fd|D        d       }|st	        dd      |j                  d      xs ddk(  rt        d| d d	d
      S | j                          d {   }t        |j                  dd            j                         }	t        |j                  dd            j                         }
t        |j                  dd            }|	r|j                  d      st	        dd      t        j                  t              }t        |      }	 t        j                   |j                  dd            }d| d|d    d|d    }t%        | d| |t        j&                  ||j)                               |j                  dd      ||j                  dd      |j                  dd      |	|
||| j*                  j                  dd            }|dz   }t,        j/                  |t0        ||       |j3                  |	|
|j5                  d      |dd       t,        j7                  |t0        t8        j:                  t8        j<                  |       |j>                  xs |j                  dd      xs d }|D ]6  \  }}tA        ||||j                  dd      ||j                  dd             8 t        d| d d	d
      S 7 h# t"        $ r |j                         }Y w xY ww)!Nc              3  T   K   | ]  }|j                  d       xs dk(  s| ! ywr  r   r!  s     r,   r-   ztm_sign.<locals>.<genexpr>  rO  r#  r4   rP  rY   r;   r   rG  r0   z/doner  rn   rC  rD  rr  ra  r   z@The name of whoever is signing and a signature are both requiredr   zTM-r  r<  rc  r8  r9  rB  rb  )r+  	docket_nor   r8  r:  r9  rB  rC  rD  rE  rf  rg  r   r%  r&  )rC  rD  rE  r  rY   r   )!r8   r}   r   r   r   r?   r   r  r  rT   r  r   r   r   r.  r   r   r   r   combinetimetzrQ  r5   put_job_filer  updater   write_job_csvr   r  rJ  r$   r3  )rB   r7   r"  ri   r_   r  rR  rA  r  rC  rD  rr  r   r:  workedrW  r   ru  r  r$   _hs     `                  r,   tm_signr_    s    6"Hgvx8LE5FD
D4Dd
KCC!122RH,$vha	{% @cRRDDHH["-.446I$((9b)*002GDHH["-.II001ABC!cdd
,,r
C
#,C##CGGFB$78 fXQs6{m1SZL9I
fXQxj1Y$,,VSZZ\BPSPWPWXegiPjcgggr&:cggk[]F^!*GsYb")//"5"5lB"G	IC
 E	vr5#.JJY7`iIj!X7 8	G$7$79J9JDQ		<sww{B/	<9B obvxswwvr/BIrSVSZSZ[hjlSmnod6(!I;e<#NN9    s8   BLK8B4L%K; +FL;LLLLz/tm/{job_no}/{docket_id}/donec           
         t        |      }t        | ||      \  }}|r|S t        ||      }|st        dd      t        j                  | d|||t        |      d      S )Nr4   rP  ztm_done.html)r7   ri   rA  r:  )r8   r}   r$  r   r%   rp   r.  )rB   r7   r"  ri   r_   r  rA  s          r,   tm_donera    sr     6"Hgvx8LE5
69
%CC!122%%g~hs73<@Q R Rr9   z/tm/{job_no}/{docket_id}.pdfc                    t        |      }t        | ||      \  }}|r|S t        ||      }|r|j                  d      st	        dd      t
        j                  |t        |d         }|t	        dd      t        |ddd|d   z   dz   i	      S )
Nr  r4   z7That docket has not been signed yet, so there is no PDFz&Docket PDF missing from the job folderrK  rL  rM  rN  rO  )	r8   r}   r$  r?   r   r5   r  r  r   )rB   r7   r"  ri   r_   r  rA  rT  s           r,   tm_pdfrc    s    6"Hgvx8LE5
69
%Ccggj)C!Z[[fb#j/:D|C!IJJD%624H3z?4Z]`4`ac cr9   c                h    t         j                  | t         j                  t        j                        S r'   )r5   r  r  r   MATERIALS_REGISTERr  s    r,   
_materialsrf    s#    fe&8&8':T:TUUr9   c                p    t        |       D cg c]  }|j                  d      xs ddk(  s| c}S c c}w )NrY   r  )rf  r?   )r7   r   s     r,   r   r     s/    !&)S!aeeHo.GF-RASSSs   33z/materials/{job_no}c                *   t        |      }t        | ||      \  }}}|rt        ||      nd}g }|rZt        j                  |      }	t        |      D 
cg c]-  }
t        j                  |
j                  dd            |	k(  s,|
/ c}
dd  }t        |      \  }}t        j                  | d|||||t        j                  |      t        t        |            |t        j                  ||d      }|r|j                   st#        ||d|        |S c c}
w )Nr;   r$   izmaterials.html)r7   ri   r$   r\  r  r<   miner  r   rk   rl   r  r  )r8   rv   r`   r   r   rf  r?   rg   r%   rp   r5   r   r   reversedr   r   r	  rV   )rB   r7   r$   r  ri   r_   r\  r  ri  r   r   rq   rr   r  s                 r,   materials_pagerk    s   6"H$Wfd;E4!%52DDKK%f-UaQUU62=N1OST1TUVXVYZ&v.OFG%%g/?hX\v&Xd^0Du))6T[B D
 EKKtT$vh0K Vs   -DDc                &  K   t        |      }| j                          d {   }t        |j                  dd            j	                         }t        |j                  dd            j	                         }t        |       }|j                  r|j                  }|rt        ||      }|rt        | ||||      S |r|st        dd      t        j                  t              }|j                  d      }	d}
|j                  d      }|t        |dd      r||j!                          d {   }|rb|	d	z   t#        j$                  |      d d
 z   dz   }
t&        j)                  |t&        j*                  t,        j.                  fz   |
t1        |             t&        j3                  |t&        j*                  t,        j4                  t,        j6                  |	|j9                  d      ||||
dddd	       t;        d| dt=        |       dd      S 7 7 w)Nr$   r;   itemr   z5Your name and what you are short of are both requiredr  rE  r   r   r  r  r%  r&  r  )	r  r*  r+  r$   rm  rE  rY   r  rU   r   rj  z&flash=sentr  rn   )r8   r  r  r?   rT   rC   r]   r$   r`   rs   r   r   r   r   rp  r  r  r   	safe_namer5   rZ  r  r   MATERIALS_DIRr  rI  re  MATERIALS_HEADERr   r   r   )rB   r7   ri   r  r$   rm  r_   rj   r   midr  rE  r  s                r,   materials_submitrr  .  s    6"HDtxx#$**,Dtxx#$**,DME{{zzE4 GVXsDAAtC!XYY
,,r
C
,,
'CJHHWEWUJ;JJL sY%8%8%>s%CCfLJvu'9'9W=R=R<T'TV`bjknbop	!3!3W5O5OQXQiQiy A&Z^zV2rl  k&d}KP^abb5  $ !s#   HHDH)H*C#HHz$/materials/{job_no}/photo/{filename}c                    t        |        t        j                  | t        j                  t        j
                  fz   |      }|t        dd      t        |dddi      S Nr4   r  r  rW  r  rO  )r8   r5   r  r  r   ro  r   r   )r7   r   rT  s      r,   materials_photoru  N  s[    fe&8&8G<Q<Q;S&SU]^D|C!233D\OMc;deer9   z/j/{job_no}/materialc                $  K   t        |      }t        | ||      \  }}|r|S | j                          d{   }t        |j	                  dd            j                         }t        |j	                  dd            j                         j                         }|t        j                  vrt        dd      t        |      }d}	|D ]a  }
|
j	                  d      xs d|k(  s||
d<   |j                  xs d	|
d
<   t        j                  t              j                  d      |
d<   d}	c |	st        dd      t         j#                  |t         j$                  t        j&                  t        j(                  |       t+        d| dd      S 7 Xw)uY   Three taps and no fourth. 'Order it' marks it ordered — the foreman rings the supplier.Nr  r;   r  r   zGot it, order it or not neededFrY   r   r  r%  r&  rU   Tr4   zNo such requestr  z
#materialsr  rn   )r8   r}   r  r  r?   rT   r\   r   r   r   rf  r$   r   r   r   r   r5   r\  r  re  rp  r   )rB   r7   ri   r_   r  r  rq  r  rR  hitr   s              r,   material_deciderx  W  sf     6"Hgvx8LE5D
dhhtR 
!
'
'
)C(B'(..0668FW,,,C!ABBfD
C EE$K2#% AhKjj-IAdG R(22I2FAfIC C!233	 2 2G4N4NPWPhPhjnoc&4#FF!  s   3FFB,F#B+Fz/photo/{job_no}c                   t        |      }t        | ||      \  }}}|rt        ||      nd}t        j	                  | d|||||t
        j                  |      ||d      }	|r|j                  st        |	|d|        |	S )Nr;   z
photo.html)r7   ri   r$   r\  r  r<   savedr   r  r  )	r8   rv   r`   r%   rp   r5   r   r	  rV   )
rB   r7   r$   rz  r   ri   r_   r\  r  r  s
             r,   
photo_pager{  x  s    6"H$Wfd;E4!%52D%%g|hX\v&s> D EKKtT$vh0Kr9   c                t  K   t        |      }| j                          d {   }t        |j                  dd            j	                         }t        |       }|j                  r|j                  }|rt        ||      }|rt        | ||||      S |st        dd      |j                  d      }|%t        |dd      r|j                          d {   nd}|st        dd      t        j                  t              }	|	j!                  d	      }
t#        j$                  |      xs d
}t&        j(                  |
fz   }|	dd| d}t*        j-                  |||      	|	dd| d}t*        j/                  |||t1        |             t3        d| dt5        |       d|
 dt5        |       d      S 7 7 w)Nr$   r;   r   r   rE  r   r9   z!No photo came through. Try again.z%Y-%m-%dsitez%H-%Mrc  r  z%H-%M-%Sr   rj  z&day=z&saved=r  rn   )r8   r  r  r?   rT   rC   r]   r$   r`   rs   r   r  r  r   r   r   rp  r   rn  r   DIARY_PARTSr5   r  rZ  r  r   r   )rB   r7   ri   r  r$   r_   rj   rE  r  r   r   r  r  ru  s                 r,   photo_submitr    s    6"HDtxx#$**,DME{{zzE4 GVXsDAAC!788HHWE % 1geZQS6T



Z]CC!DEE
,,r
C
,,z
"C


d
#
-vC3&(E5k3%t$E&%/;x.#d+	vueXc];gfXVE$K=cU'RWX]R^Q_`nqrr1   s#   F8F3B0F8F6C!F86F8z /photo/{job_no}/{day}/{filename}c                    t        |        t        j                  | t        j                  |fz   |      }|t        dd      t        |dddi      S rt  )r8   r5   r  r   r~  r   r   )r7   r   r   rT  s       r,   r  r    sS    fg&9&9SF&BHMD|C!233D\OMc;deer9   c                     t         j                  t        j                  t              D  cg c]  } | j                  d      xs ddk(  r|  c} S c c} w )NsubdirrY   r;   r  )r5   read_company_csvr   DEFECTS_REGISTER	FLEET_SUBr?   r   s    r,   r   r     sL    --g.F.Fy-Y 2!h%2&0  2 2 2s   !Az/plantc                h   i }t               D ]:  }|j                  |j                  dd      d      dz   ||j                  dd      <   < t        j                  | ddt        j
                  j                         D cg c]#  \  }}t        |||j                  |d            % c}}i      S c c}}w )Nregor;   r   r   zplant_index.htmlvehicles)r  r   )r   r?   r%   rp   r   VEHICLESr   dict)rB   countsr   kr.   s        r,   plant_indexr    s    F_ I$*JJquuVR/@!$Dq$HquuVR !I%%g/A5>>K_K_Kab41aT!!VZZ1-=>bDd e ebs   =(B.z/plant/{rego}c                   t        j                  |      }|st        dd      t        |       }t        j                         D cg c]Y  }|j                  d      xs dj                         j                         dk7  r#|j                  d      r|j                  dd      [ }}t        j                  | d|t        j                  |      t        |t        j                  	      |j                  r|j                  nd|j                  |t!               D cg c]  }|j                  d
      |d
   k(  s| c}d      S c c}w c c}w )Nr4   'That rego is not on the LFCS fleet listrY   r   rZ   r$   r;   z
plant.htmlr   r  )r.   checksr<   r$   r\  r  r   )r   vehicler   rC   r<   r   r?   rT   r\   r%   rp   
checks_forr   r  r]   r$   r   )rB   r  r  r.   r_   r+   r   r   s           r,   
plant_pager    s   dAC!JKKME)- `A%%/-X446<<>*LQRQVQVW]Q^ eeFB `F `%%g|%**40&SYY:W#kk

rU[[SX,M!!%%-1V92LAM>  `
 Ns   AE E3Ec                  K   t        j                  |      }|st        dd      | j                          d {   }t	        |       }|j
                  r|j                  n(t        |j                  dd            j                         }t        |j                  dd            j                         }|st        dd      t        j                  |      }dg }	}|D ]`  \  }
}}t        |j                  d	|
z   d            j                         j                         }|d
v r|dz  }|dk(  sP|	j                  |       b |t        |      k  rt        dd      |	r|st        dd      t        j                  t               }|j#                  d      }d}|j                  d      }|at%        |dd      rT|j'                          d {   }|r:|dz   |d   z   dz   }t(        j+                  |t-        |      t.        |d   fz          ||j1                  d      |d   |d   ||	rdnddj3                  |	      |||	rdndddd}t(        j5                  t6        j8                  t6        j:                  |t.        |d   fz          |	r9t(        j5                  t6        j<                  t6        j:                  |t.               t?        d|d    d|	rdndz   d !      S 7 7 w)"Nr4   r  r$   r;   rU   r   r   r   zc|)r  nor   r  z:Every line needs an OK or a NO before it counts as a checkuD   Say what is wrong with it — that note is the whole point of the NOr  rE  r   r   r  r  r  r%  r&  descdefectr  r=  r  )r  r*  r  r  r$   resultfailsrU   rE  rY   resolved_byresolved_atz/plant/z?flash=r  rn   ) r   r  r   r  rC   r]   r$   r  r?   rT   r  r\   r   lenr   r   r   rp  r  r  r5   put_company_filer  r  r   r  append_company_csvr   PLANT_REGISTERPLANT_HEADERr  r   )rB   r  r.   r  r_   r$   rU   r  answeredr  r   label_hintr@  r   pidr  rE  r  rA  s                       r,   plant_submitr    s    dAC!JKKDME5::#dhhvr.B*C*I*I*KDtxx#$**,DC!788d#FeH#  UE$((4#:r*+11399;,MH$;LL  #f+C!]^^TC!ghh
,,r
C
,,
'CJHHWEWUJ;JJL sQvY.7J"":x}YRSTZR[Q]E]"^3==)=#DaPViiUPTIIe$dZ$V"RPRTC 
W33W5I5I3$-6$<  > 	  !9!97;O;OQT]f ggai[8HSWXfijjO  2 !s*   7K!KC1K!,BK!K	DK!K!z/plant/{rego}/photo/{filename}c                    t        j                  |       }|st        dd      t        j	                  |t
        |d   fz         }|t        dd      t        |dddi	      S )
Nr4   r  r  r  r  r  rW  r  rO  )r   r  r   r5   get_company_filer  r   )r  r   r.   rT  s       r,   plant_photor    si    dAC!JKK!!(9&	|3K!LD|C!233D\OMc;deer9   z/j/{job_no}/plant/resolvec                  
K   t        |      }t        | ||      \  }}|r|S | j                          d{   }t        |j	                  dd            j                         t        j                  t        |j	                  dd                  }|j                  xs d
t        j                  t              j                  d      d
fd}t        j                  t        j                   t"        	      } ||      st%        d
d      t        j'                  t        j                   t        j(                  |t"        	       |t        j*                  v rrt        j                  t        j,                  t"        |fz   	      }	 ||	      r=t        j'                  t        j,                  t        j(                  |	t"        |fz   	       t/        d| dd      S 7 w)zKFixed. Clears it off every foreman screen at once, and says who cleared it.Nr  r;   r  r   r%  r&  c                z    d}| D ]2  }|j                  d      xs dk(  s|j                  dd       d}4 |S )NFr  r;   resolved)rY   r  r  T)r?   r[  )rR  rw  r   r  r  stamps      r,   closezplant_resolve.<locals>.close  sL     	Ad!rc)JrRWXY	 
r9   r  r4   zNo such defectr  z#defectsr  rn   )rR  
list[dict]returnbool)r8   r}   r  r  r?   rT   r   r   r$   r   r   r   r   r5   r  r   r  r  r   write_company_csvr  r  r  r   )rB   r7   ri   r_   r  r  r  r  indexhistr  r  r  s             @@@r,   plant_resolver    s     6"Hgvx8LE5D
dhhtR 
!
'
'
)C::c$((62./0D		 yBLL&&	&:E ""7#;#;I"NE<C!122	G44g6J6JEZcdu~~%%g&<&<YRVQXEX%Y;##G$:$:G<P<PRV+4w+> $ @c&2DD/  s   3G#G F(G#c                h    t         j                  | t         j                  t        j                        S r'   )r5   r  r  r   BOARD_REGISTERr  s    r,   _board_rowsr  :  s#    fe&8&8':P:PQQr9   c                    t         j                  | t         j                  t        j                  t        j
                  |       y r'   )r5   rI  r  r   r  BOARD_HEADER)r7   rA  s     r,   _board_appendr  >  s+    	!3!3W5K5KWMaMacfgr9   c                    t        |       D cg c])  }|j                  d      xs dj                  |      s(|+ c}S c c}w Nr*  r;   )r  r?   r  )r7   r   r   s      r,   _today_rowsr  B  s7    "6*Y!quu[/A/GR.S.STW.XAYYYs   )??c                    g }t        |       D ]_  }t        j                  |      }|r5|j                  d      xs dj	                         j                         dk(  rO|j                  |       a |S )zTWho can be dragged: this job's crew list first, then anyone else still on the books.rY   r   rZ   )r   r<   r[   r?   rT   r\   r   )r7   r   r   r+   s       r,   _board_crewr  F  sf    
Cv KKN!%%/-X446<<>*L

1	
 Jr9   c                 v    	 t         j                         S # t        $ r t        j                          g cY S w xY w)zXThe jobs with a Sign-On folder. That is the live list and there is no second copy of it.)r5   	list_jobsrd   r:  r;  r#  r9   r,   
_live_jobsr  Q  s4       	s    88c                 H    t         j                  t        j                        S r'   )r5   r  r   ROSTERr#  r9   r,   _roster_rowsr  Z  s    !!'..11r9   c                    t         j                  t        j                  t        j                  | j                         |||t        j                  t              j                  d      |d       y )Nr%  r&  )r   r[   r+  r  r*  r-  )	r5   r  r   r  ROSTER_HEADERr   r   r   r   )r   r[   job_keyr  r-  s        r,   _roster_writer  ^  sO    	W^^W-B-B6'\\"%///CvE r9   c                   t               }|D ];  }t        j                  |j                  dd            }|s+|j	                  |       = g }t
        j                  |       D ]a  }|j                  d      xs dj                  |      r|j                  d      r9|j                  d      xs d|v rQ|j                  |       c |S )u  Take 5s the crew filed today that are not on the board yet.

    A Take 5 already says who and what — the foreman should never have to retype it to put the man
    somewhere. He drags the card onto a zone, or waves it off. Either way it stops nagging.
    detailr;   r   r   r  )	r   r   is_t5r?   r   r5   r   r  r   )r7   r   rR  handledr   rS  r   r  s           r,   _open_t5_cardsr  e  s     eG kk!%%"-.KK Cf% g$"005xEE$K2')

1 Jr9   z/board/{job_no}c                @   t        |      }t        | ||      \  }}|r|S t        j                  t              }	 t        j                  |j                               }|j                         }	t        ||	      }
t        j                  |
      \  }}t        |      }|j                         D cg c]  }|j                  r| c}t        j                   D cg c]  }||   	 c}z   }t#        |      D cg c]	  }||vs| }}i }|
D ]d  }|j%                  d      xs ddv s|j%                  d      |j%                  d      xs df||j%                  d      xs dj                         <   f t&        j)                  | di d|d|d	|d
|d|d||j                         k(  d|	d|t+        d      z
  j                         d|t+        d      z   j                         d|d|d|dt        j,                  dt        j.                  dt        j0                  dt        j2                  dt5        ||	|
      t7               D cg c]  }|d   |k7  s| c}d|z   d      S # t        $ r |j                         }Y +w xY wc c}w c c}w c c}w c c}w )zKThe job as a board. Zones down the screen, the crew in the yard at the top.r  r;   )r   movedr  r[   z
board.htmlr7   ri   r_   msgr   r   r   r   r   r   r   zonesyardgonedeckstages	estimateschip_actionst5_cardsr   r   )jobsr   )r8   r}   r   r   r   r   r   rT   r   r   r  r   stater   r   rH  ALWAYSr  r?   r%   rp   r   DECKSTAGES	ESTIMATESCHIP_ACTIONSr  r  )rB   r7   r  r   ri   r_   r  r   r   r   rR  r  rv  placedzr   orderedr  r  r   js                        r,   
board_pager  z  s    6"Hgvx8LE5
,,r
C!!!''), ..
Cvs#D;;t$LE5ZF,,.8Qq8ell;[E!H;[[G"6*>!avoA>D>D ]EE(O!r&7756UU8_aeeHoF[Y[4\D!%%/'R..01] %%g| 
>&
>$h
>07
>@Es
>
> $#((*"4
>6;S
> 	4)++668
> ;CTI[\L]E]DhDhDj
> 		
> !$	
> )/	
>
 	


>
 %ell
>
 5@
> 	**
> 	N635
> 'L?qAeH,>?'
> 
 
  xxz 9;[> @s;   #I, .J JJ6	J JJJ,J	J	z/board/{job_no}/zonec                ~  K   t        |      }t        | ||      \  }}|r|S | j                          d{   }t        |j	                  dd            j                         j                         }t        j                  t        |j	                  dd                  }t        |j	                  dd            j                         }|j                  xs d}	t        j                  t              }
|
j                         j                         }|st        dd      |d	k(  r8t!        |t        j"                  |
||dd
|j%                         dd |	             nP|dk(  r|t        j&                  vrt        dd      t        j(                  t+        ||            \  }}|j	                  |      xs t        j,                  |      }t        j.                  ||      }|r%t1        d|z   dz   t3        |dz   |z         z   d      S t!        |t        j"                  |
||dd||	             n|dk(  rD|t        j4                  vrt        dd      t!        |t        j"                  |
||dd||	             n7|dk(  r&t!        |t        j"                  |
||dd||	             nt        dd      t1        d|z   d      S 7 w)zJOpen a zone, push it along a stage, put a time on it, or call it finished.Nr  r;   zoner  r   r   uB   Three words for the work area — 'wall', '5m seats', 'bay 3 deck'createcreatedr  stagezNot a stage on the ladderr   z?msg=rc  r  rn   estimatez1h, 3h, today or tomorrowr  zcreate, stage, estimate or done)r8   r}   r  r  r?   rT   r\   r   
clean_zoner$   r   r   r   r   r   r   r  rA  upperr  r  r  Zone
hold_blockr   r   r  )rB   r7   ri   r_   r  r  r  r  r  r  r   r   r  r   r  stops                   r,   
board_zoner    s]     6"Hgvx8LE5D(B'(..0668FC 456D(B'(..0F		 yB
,,r
C
((*


 CC!efffeiiVT2y&,,.Y\Z\J]_abc	7	%%@AA;;{6378qIIdO/uzz$/6*#I$6$@5PSVZIZC[$[ilmmfeiiVT2wPRST	:	(%@AAfeiiVT2z6SUVW	6	feiiVT2vvrRSC!BCCI.C@@=  s   3J=J:JJ=z/board/{job_no}/movec                V  K   t        |      }t        | ||      \  }}|r|S | j                          d{   }t        |j	                  dd            j                         }t        j                  t        |j	                  dd                  }t        |j	                  dd            j                         j                         }t        |j	                  dd            j                         }	t        |j	                  dd            j                         }
|st        d	d
      |dvrt        d	d      |dk(  r|st        d	d      |j                  xs d}t        j                  t              }|
rd|
z   dz   |	z   j                         }	|dk(  r3|	r1	 t        t        j                  |j!                               ||	|d       t)        |t        j*                  |||dk(  r|nd|||	|             t-        d|z   d      S 7 # t"        $ r t%        j&                          Y ^w xY ww)z^A name landed somewhere. One row, and the man comes off wherever he was without being told to.Nr[   r;   r  r  r   r  t5r   Which bloke?)r   r   r   r  	dismissedz!on, off, home, moved or dismissedzDrop him on a work arear   zt5:rc  r  r   r   r  rn   )r8   r}   r  r  r?   rT   r   r  r\   r   r$   r   r   r   r  next_working_dayr   rd   r:  r;  r  rA  r   )rB   r7   ri   r_   r  r  r[   r  r  r  r  r  r   s                r,   
board_mover    s     6"Hgvx8LE5D(B'(..0FC 456D(D)*00288:F(B'(..0F	TXXdB	 	&	&	(BC00@@C!DEE~dC!:;;		 yB
,,r
C	"*s"V+224V	"%00<ffbRYZ &%))C4RQWY_agiklmI.C@@1  *  	"!	"s4   3H)HE H)0H =H)H&#H)%H&&H)c                   i }| D ]  }	 t         j                  |d         }|D ]i  }|j                  d      xs d}|j                  |      s*|j                  d      xs dj                         }|sP||vs|||   d   kD  s`||d   f||<   k  |j                         D ci c]  \  }}||d    c}}S # t        $ r t        j                          Y w xY wc c}}w )zYLast job each bloke actually tapped on today. The board's starting position, not a guess.r   r*  r;   r$   r   r   )	r5   r   rd   r:  r;  r?   r  rT   r   )	r  r   r   r  rR  r   tsr   r.   s	            r,   _where_todayr    s    ')D )	((52D  	)A%%$*B==%v$"++-AatmrDGAJqx.Q	)) !%

-1AqtG--  	!	 .s   B8$C8CC/boardc                \   t        |       }t        j                         r)|j                  st        j                  | ddd|dd      S t        j                  t              }t               }t        j                  |j                               }t               }t        j                  ||j                               }|j!                         D ch c]  }|D ]  }|  }	}}t        j                  ||j                         j                               }
|
j#                         D ci c]  \  }}|D ]  }||  }}}}t%        ||j                         j                               }t        j'                         D cg c]I  }|j)                  d      xs dj+                         j-                         d	k7  r|j)                  d
      r|K }}|D ci c]  }|d   g 
 }}g }t/        |d       D ]  }|d
   j+                         }d}|j#                         D ]  \  }}||v s|} |s&|j)                  |d      xs |j)                  |d      }||j)                  d      xs d||	v d}||v r||   j1                  |       |j1                  |        |j#                         D ci c]  \  }}||D cg c]  }|d
   	 c} }}}}t        j                  | d||||t        j2                  |||      |t5        |	      d      S c c}}w c c}}}w c c}w c c}w c c}w c c}}}w )zVEvery live job as a column. Drag a name across and that is where he is in the morning.rx   r;   z	The boardry   rm   rn   rY   r   rZ   r$   r   c                H    | j                  d      xs dj                         S r   r   r   s    r,   r   zadmin_board.<locals>.<lambda>  s    f0C/J/J/L r9   r   r  r  )r$   r  r   zboard_admin.html)r  columnsr  tomorrowmessager_   explicit)rC   r<   rz   r{   r%   rp   r   r   r   r  r   r  r   r  roster_by_jobr   r   r   r  r   r?   rT   r\   r   r   roster_messager  )rB   r_   r   r  r   rR  set_forr   r   r  today_rosterr  
from_today	from_tapsr+   people_rowsr  r  r  rv  chipr.   r   by_jobs                           r,   admin_boardr    s    ME!%--))'3FkEICPS * U 	U ,,r
C<D%%chhj1H>D!!$(:(:(<=G&~~/?e?A??H?
 &&tSXXZ-A-A-CDL'3'9'9';KK81eUK!Q$K!KJKT388:#7#7#9:I"kkm euuX2(99;AACzQVWV[V[\bVc  eK e%)*qx|*G*DK%LM fIOO 	HAuEz	 NN1b)AY]]1b-AEAEE&M$=XqH}UGEN!!$'KK 5<MMODDDAqaQ'!F)''DFD%%g/A$H''$?%MD  9 @ Le*  (Ds1   L)L?ALL,L'9L"L'"L'z/board/movec                  K   t        |       }t        j                         r|j                  st	        dd      | j                          d{   }t        |j                  dd            j                         }t        |j                  dd            j                         }|st	        dd      t               D ch c]  }|d	   	 }}|r||vrt	        dd
      t        t        j                  t        j                  t              j!                               |||j"                  xs dd       t%        dd      S 7 c c}w w)u]   One name, one job, tomorrow. Sunday is skipped — Saturdays are worked and always have been.rm   r  Nr[   r;   r+  r   r  r   Not a live jobrX   r   r  r  rn   )rC   r<   rz   r{   r   r  r  r?   rT   r  r  r   r  r   r   r   r   r$   r   )rB   r_   r  r[   r  r  keyss          r,   
admin_mover  4  s     ME!%--C00D(B'(..0F$((5"%&,,.GC00(l+AeH+D+7$&C!122%((b)9)>)>)@A67**('3H#66  
 ,s&   AEE A0E>E
A7EEc                B    t               D ]  }|d   | k(  s|d   c S  | S )Nr   r  )r  )r  r  s     r,   
_job_labelr  N  s0    \ U8wW: Nr9   c                8   | sy	 t        j                  t               t        j                  t	        j
                  t              j                               j                         |       }|rt        |      S dS # t        $ r t        j                          Y yw xY w)zY'Tomorrow: HORNSBY' on his own screens. Blank if nobody has said, and blank says nothing.r;   )r   
roster_forr  r  r   r   r   r   r   rd   r:  r;  r  )r$   r   s     r,   r  r  U  s~    |~u/E/EhllSUFVF[F[F]/^/h/h/jlpq ":c?)r)  s   A%A9 9BBz/todayc                   t        |       }t               }t        j                  t              }|j                         j                         }d|j                  rT|sRt        j                  t               ||j                        r't        fd|D              rt        dz   dz   d      S t        j                  | d||||j                  r|j                  nd|j                  rt!        |j                        d      S dd      S )	uf   Rostered — straight through. Not rostered — one screen of big buttons, and his answer is a record.r;   c              3  .   K   | ]  }|d    k(    ywr   Nr#  )r*   r  heres     r,   r-   ztoday_page.<locals>.<genexpr>k  s     7Q%D(7   r   
?via=todayr  rn   z
today.html)r  r_   fixr$   r  )rC   r  r   r   r   r   r   r]   r   r  r  r$   anyr   r%   rp   r  )rB   pickr  r_   r  r   r   r  s          @r,   
today_pager  a  s     ME<D
,,r
C
((*


 CD{{4UZZ@C7$77#FTML$@cRR%%g|uS#kk

r5:[[ejj1>   GI>  r9   c                   K   t        |       }| j                          d{   }t        |j                  dd            j	                         t        |j                  dd            j	                         }t        fdt               D              st        dd      |j                  rLt        t        j                  t              j                         |j                  |j                  |rdnd	       t        d
z   dz   d      S 7 w)zU'Where are you today?' answered. Written down, because the answer is itself a record.Nr+  r;   r  c              3  .   K   | ]  }|d    k(    ywr  r#  )r*   r  r  s     r,   r-   ztoday_pick.<locals>.<genexpr>{  s     9qqx7"9r  r   r  	correctedrP   r   r  r  rn   )rC   r  r  r?   rT   r  r  r   r]   r  r   r   r   r   r$   r   )rB   r_   r  r  r  s       @r,   
today_pickr"  t  s      MED$((5"%&,,.G
dhhub!
"
(
(
*C9JL99C!122{{hll2&++-uzz7EJJ%(kf	6FW,|;MM  s   DDC*D))summaryz
1. SummaryT)weatherz
2. WeatherT)labourz3. Labour on siteF)r9  z4. Plant on siteF)worksz5. Work performedF)progressz6. ProgressF)safetyz	7. SafetyF)r   z8. MaterialsF)r0  z9. DayworksF)photosz10. Photos takenF)issuesz
11. IssuesT)r&  z12. Man hoursF)notesz	13. NotesT)next_dayz14. Next day planTc                h    t         j                  | t         j                  t        j                        S r'   )r5   r  r  r   DIARY_NOTESr  s    r,   _diary_notesr/    s#    fe&8&8':M:MNNr9   c                h   g }t         j                  D ]h  }	 t        j                  t        j
                  t        |fz         }||D cg c])  }|j                  d      xs dj                  |       s(|+ c}z  }j t        |d       S # t        $ r t        j                          Y w xY wc c}w )zREvery vehicle checked today. Eight small files locally; once a day, on one screen.r  r*  r;   c                &    | j                  dd      S r  r   r   s    r,   r   z_plant_today.<locals>.<lambda>  s    QUU;%; r9   r   )r   r  r5   r  r   r  r  rd   r:  r;  r?   r  r   )r   r   r  rR  r   s        r,   _plant_todayr2    s    
C O	))'*@*@VZU\I\)]D 	4NaAEE+$6$<"#H#H#MNNO #;<<	  	!	 Os   -B	)B/3B/B,+B,z/diary/{job_no}c                	   t        |      }t        | ||      \  }}|r|S t        j                  t              }	 t        j                  |j                               }	|	j                         }
t        ||
      }t        j                  |      \  }}t        ||	|      }t        j                  |      }|D ch c]  \  }}|j!                          }}}i }t#        |      D ]i  }|j%                  d      xs dj'                  |
      s(|j)                  |j%                  d      xs dj                         g       j+                  |       k t        j-                  |      D cg c])  }|j%                  d      xs dj'                  |
      s(|+ }}t        j/                  |      D cg c])  }|j%                  d      xs dj'                  |
      s(|+ }}t        j1                  |      D cg c])  }|j%                  d      xs dj'                  |
      s(|+ }}t3        |      D cg c])  }|j%                  d      xs dj'                  |
      s(|+ }}t5        |      D cg c]  }|j%                  d      xs d|
k(  s| }}g }	 t7        t        j9                  |t:        j<                  |
fz               }tD        jG                  | di d|d|d	|d
|	d|
d|	|j                         k(  d|d|d|	tI        d      z
  j                         d|	tI        d      z   j                         dtJ        d|dtM        jN                         dt        jP                  |      d|jS                         D cg c]5  }|jT                  s%|jV                  s|jX                  s|jZ                  s4|7 c}d|d|D cg c]  }|j!                         |vs| c}||||t:        j\                  |||
t_        |
      ta               d
      S # t        $ r |j                         }	Y w xY wc c}}w c c}w c c}w c c}w c c}w c c}w # t>        $ r tA        jB                          Y w xY wc c}w c c}w )Nr*  r;   sectionr   r   z
diary.htmlr7   ri   r_   r   r   r   r  secr   r   r   r   sectionsr+  voice_onr&  r  r   r   )
r  take5s	incidentsr   r   r   r)  	photo_dayr9  r   )1r8   r}   r   r   r   r   r   rT   r   r   r  r   r  r   r5   r   r\   r/  r?   r  r   r   list_incidentsr   r   rf  r   r   list_job_filesr   r~  rd   r:  r;  r%   rp   r   DIARY_SECTIONSr   	availableworks_linesr   r  r  r  r   r   r2  r   )rB   r7   r   r  r5  ri   r_   r  r   r   r   browsr  _wherer   r   r   r   r   r+  r   r9  r8  r  r   r   r)  r  r   s                                r,   
diary_pagerB    sD   6"Hgvx8LE5
,,r
C!!!''), ..
C$EKK&ME6c*H~~f%H"*+$!QAGGI+D+#%E&! MEE+$"005aeeI.4";;=rBII!LM "008gqQUU;=O=USU<a<abe<fgIg))&1\AaeeGn6J5V5VWZ5[a\F\ ..v6ea155;M;SQS:_:_`c:deHe&v.]q1553E3K2W2WX[2\]I]"6*KQquuV}/Bs.JqKGKF,,VW5H5HC65QRS %%g| >&>$h>07>@F>NSUX>DCHHJ&>(-s>493> 	4)++668> ;CTI[\L]E]DhDhDj> 	N	> %,U	> 5?@Q	>
 	""5)> 	U\\^[qww!**RSRZRZ![> 	H> )h*X!'')SWBW1*X> Y'*A*Af3c"}>  5  xxz , h\e]K   \*Xs}   #P 8P9%)P?P?,)QQ3)Q	Q	0)QQ-QQ1Q 5Q<:Q<	R!RP65P6Q98Q9c                    t         j                  | t         j                  t        j                  t        j
                  t        j                  t              j                  d      |||d       y )Nr%  r&  )r*  r4  textr  )
r5   rI  r  r   r.  DIARY_NOTES_HEADERr   r   r   r   )r7   r4  rD  r  s       r,   _sayrF    sQ    	!3!3W5H5H'JdJd\\"%///CDg r9   z/diary/{job_no}/voice/{section}c           
     N  K   ddl m} t        |      }t        | ||      \  }}|r |dddd      S |t        vrt        dd	      | j                          d
{   }|j                  d      }|$t        |d      r|j                          d
{   nd}	t        |dd      xs d}
	 t        j                  |	|
      }t5        ||||j6                  xs d        |d|d      S 7 7 W# t        j                  $ rm}t        dt        j                   t"              j%                  d      ||t'        |	      |
|j(                  fz          |d|j*                  d      cY d
}~S d
}~wt,        $ r0 t/        j0                           |dt        j2                  d      cY S w xY ww)u  Hold the mic, say it, let go. Deepgram turns it into the line that goes in the report.

    Answers JSON with HTTP 200 either way — a fetch that throws leaves the foreman looking at a
    spinner with no idea what went wrong, which is the exact failure this app exists to stop.
    r   )JSONResponseFzForeman only.)r  sayrm   rn   r4   #Nothing to say against that sectionNaudior  r9   content_typer;   z
audio/webmz:[diary voice] %s job=%s section=%s bytes=%d ctype=%s :: %sr%  r&  r   T)r  rD  )fastapi.responsesrH  r8   r}   SAYABLEr   r  r?   hasattrr  r  r   
transcribe
VoiceErrorprintr   r   r   r   r  r  rI  rd   r:  r;  	CANT_HEARrF  r$   )rB   r7   r4  rH  ri   r_   r  r  upr  ctypesaides                r,   diary_voicerX    s     /6"Hgvx8LE55AsSSgC!FGGD	'	B^F0C	//CB+;|E	CU+ 	$

 7i8tT233  
  9Jb!++Y+?RUVYRZ\acdckcklm 	n5788 C5ABBCsa   AF%C'6F%C)F%*C+  (F%)F%+F">A"E& F"!F%&9F"F%!F""F%z/diary/{job_no}/note/{section}c                v  K   t        |      }t        | ||      \  }}|r|S |t        vrt        dd      | j	                          d{   }t        |j                  dd            j                         }|st        dd      t        ||||j                  xs d       t        d	|z   d
z   |z   d      S 7 mw)zUTyped, not said. The fallback for a dead mic, a locked-down phone, or a quiet office.r4   rJ  NrD  r;   r   zNothing typedr   r   #r  rn   )r8   r}   rN  r   r  r  r?   rT   rF  r$   r   )rB   r7   r4  ri   r_   r  r  rD  s           r,   
diary_noter[  	  s      6"Hgvx8LE5gC!FGGDtxx#$**,DC11$

 7i8I.4w>CPP  s   AB9	B7
A.B9)r7   r  r  r  )rB   r   r  people.Identity)rL   r  )r;   )r$   r  rU   r  r  r  )r_   r\  r$   r  r  r  )r7   r  r  ztuple[str, str])
rB   r   r7   r  ri   r  rj   r  r$   r  )rB   r   r7   r  ru   r  )rB   r   r7   r  ri   r  )r7   r  r  z	list[str])rB   r   )r7   r  r   r   r   r   r  zlist[tuple[str, timesheet.Day]])rB   r   r7   r  r   r  )rB   r   r7   r  )rB   r   r7   r  rG  r  )r7   r  r   r  )r7   r  r   r  r   r  )rB   r   r7   r  r   r  )rB   r   r7   r  r   r  r$   r  rq  r  rr  r  )r;   r;   r;   )
rB   r   r7   r  r$   r  r  r  r~  r  )rB   r   r7   r  r  r  r  r  r  r  r  r  rb   )rB   r   r7   r  rG  r  r  r  )i@  )r  bytesr  r  r  r]  )rB   r   r7   r  r   r  )r7   r  )r  r  r  r   )
rB   r   r7   r  r$   r  r  r  r  r  )
rB   r   r7   r  r$   r  r  r  r  r  )rB   r   r7   r  r$   r  r  r  )
rB   r   r7   r  r   r  r$   r  r  r  )r7   r  r  r  )r7   r  r"  r  r  zdict | None)rA  r  r  zlist[tuple[str, float]])r7   r  ri   r  r$   r  r   r  r"  r  r  r  rj   r  r  None)rB   r   r7   r  r"  r  )rB   r   r7   r  r$   r  r  r  )r7   r  r   r  )
rB   r   r7   r  r$   r  rz  r  r   r  )r7   r  r   r  r   r  )r  r  )rB   r   r  r  r  r  )rB   r   r  r  )r  r  r   r  )r7   r  rA  r  r  r^  )r7   r  r   r  r  r  )r   r   r[   r  r  r  r  r  r-  r  r  r^  )r7   r  r   r  rR  r  r  r  )rB   r   r7   r  r  r  r   r  )r  r  r   r  r  r  )r  r  r  r  )r$   r  r  r  )rB   r   r  r  r  r  )r   r  r  r  )
rB   r   r7   r  r   r  r  r  r5  r  )
r7   r  r4  r  rD  r  r  r  r  r^  )rB   r   r7   r  r4  r  )
__future__r   osr:  urllib.parser   r   r   r   pathlibr   zoneinfor	   fastapir
   r   r   r   rM  r   r   r   fastapi.staticfilesr   fastapi.templatingr   r;   r   r   r   r   r   r   r   r   r   r   r   r   r   r    r   __file__parentHEREappmountr%   r  r  maxiterdirSTATIC_Venvglobalsfrom_envr5   getenvrstripr   	CrewFilesr5  Peopler<   tel_hrefr8   rC   rM   rV   r`   rg   rs   rv   r}   r   r?   r   r   r   postr  r  r  r  r(  r   rU  rX  r^  rw  r|  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  TM_PARTSr  r]  r5  r   r$  r.  r3  r6  rL  rT  r_  ra  rc  rf  r   rk  rr  ru  rx  r{  r  r  	FLEET_DIRr  r   r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r"  r=  rN  r/  r2  rB  rF  rX  r[  )r  r  _lrI  s   0000r,   <module>r{     s	   " 	   . .   9 9 F F + . = =0 0 0  !H~N# 		)[4(?;(	 Kd[&89	 s3N4(?2K2K2MNNOP%	  c ryy"$;<CCCH Y  +<>V!WX
v}}U%	  e A&/		 \*@ +@3( |4M 5Ml 
"# $$ 
D  D, 
B B 
#$B %B  
+X  +X\ 	|<e =e& 	#$[ %[ 	,-F .F 	 > ?  
!,? IS	TXY\T]##25#NQ# @#R 	<8 9 
L9&- :&-R 	=} >}
 
-.JNr(`deg`h	?CC /C0 	L9 : 
\:+} ;+}\ 	 >h ?h 	()f *f" 	N N*= 5 6: .*a *aZ 	,7 84 	x  x: 	 >u ?u   %*!RL1qsQwqkN1?Y* 	L9 : 
"O "OJ 	(F G, 
)*'O +'OT 	(FR GR 	'(c )c*VT 	|< =& 
 c !c> 	/0f 1f 
 !G "G@ 	<8
 9
 
s s: 	+,f -f  	2
 ,/e 0e 6 7 /+k +k\ 	)*f +f 
%&E 'EVRhZ2* 	<8! 9!H 
 !$A "$AN 
 !A "AR.& ,/, 0,^ -7 72	* ,/ 0$ (N N.   .
5
5B1
5O
= 	<8. 9.b 
+,4 -4> 
*+Q ,QA 2d 6s   _._3_3