
    Z5j<+                       d Z ddlmZ ddlmZmZ ddlmZmZmZ g dZ	ddgZ
g dZd	d
iZg dZddddZdZd#dZd$dZe G d d             Ze G d d             Zd%dZd&dZd'dZd(dZd
diZd)dZd*dZd+dZd,dZd-d Zd.d!Zy")/u  The board — what a pile of drag events adds up to.

Every drag is one append-only row in Board-Register.csv (see storage.BOARD_HEADER). Nothing in
here edits a row; the state of the board is derived from the rows every time, same rule as the
timesheet derives hours from taps. That is deliberate and it is the whole reason the board is worth
anything: a zone card marked done, with the men and the times already on it, IS the production
record. Nobody has to write it up afterwards, and nobody can quietly change it later.

Two altitudes, one shape:
  foreman  - names move between ZONES on his job
  admin    - names move between JOBS for tomorrow, written to Roster.csv

The diary reads the same rows back as sentences. See works_lines().
    )annotations)	dataclassfield)datedatetime	timedelta)zSET OUTPREPSHUTTERSTEELINSPECTPOURSTRIPCLEANROAMINGDAYWORKS)formedsteel	inspectedpouredstrippedcleanedr   r   )1h3htodaytomorrowz	sent homez	moved jobzoff the tools)homemovedoff)onr   r   r   c                j    dj                  | xs dj                               dd j                         S )zWThree words, as typed, tidied. Uppercase because it is read at arm's length in the sun.  N   )joinsplituppernames    /opt/lfcs-signon/app/board.py
clean_zoner*   *   s.    88TZR&&()#2.4466    c                ~    | xs dj                         }|j                  d      sy|dd j                  dd      d   S )zW't5:20260825-1512-matty and a bit' -> the id. '' if this row did not come off a Take 5.r"   zt5:   Nr!      r   )strip
startswithr%   )detailds     r)   is_t5r3   /   s?    	2A<<QR5;;sAq!!r+   c                      e Zd ZU ded<   dZded<   dZded<    ee      Zded<   dZ	ded	<   d
Z
ded<   d
Zded<    ee      Zded<   edd       Zedd       Zy)Zonestrr(   r"   kindstage)default_factoryliststages_doneestimateFbooldonefixedpeoplec                   | j                   t        v r[t        j                  | j                         t        t              dz
  k  r)t        t        j                  | j                         dz      S | j                   t        d   k(  rdS t        d   S )Nr.   r"   r   )r8   STAGESindexlenselfs    r)   
next_stagezZone.next_stageB   se    ::FLL$<s6{Q$N&,,tzz2Q677ZZ6":-r<6!9<r+   c                    | j                   r5| j                   | j                  k7  r| j                   dz   | j                  z   S | j                  S )N    — )r7   r(   rF   s    r)   titlez
Zone.titleH   s;    26))		TYY@Vtyy7"TYY.e\`\e\eer+   Nreturnr6   )__name__
__module____qualname____annotations__r7   r8   r   r:   r;   r<   r>   r?   r@   propertyrH   rK    r+   r)   r5   r5   7   s}    
ID#NE3Od3K3HcD$E4.FD.= =
 f fr+   r5   c                  h    e Zd ZU dZded<   ded<   ded<   ded<   dZded<   dZded	<   edd
       Zy)SpanzDOne bloke, on one zone, between two times. The pricework line, free.r6   zoner7   personstartr"   finishtaskc                p    | j                   r| j                  dz   | j                   z   S | j                  dz   S )Nu   –u
   – on now)rY   rX   rF   s    r)   timesz
Span.timesW   s/    37;;tzzE!DKK/]DJJQ]D]]r+   NrL   )	rN   rO   rP   __doc__rQ   rY   rZ   rR   r\   rS   r+   r)   rU   rU   M   s@    N
I
IKJFCD#N^ ^r+   rU   c                    | xs ddd S )Nr"         rS   )tss    r)   _hhmmrb   \   s    H"br+   c                   t         D ci c]  }|t        |d       }}i }| D ]  }t        |j                  dd            }|j                  d      xs dj	                         }|j                  d      xs dj	                         j                         }|j                  d      xs dj	                         }|dk(  rD|rB|j                  |t        |	             |xs ||   j                  ||   _        d
||   _        |dk(  rI||v rE|t        v r=|||   _
        |||   j                  vs||   j                  j                  |       -|dk(  r||v r|||   _        B|dk(  r||v rd||   _        W|t        v sa|se|dk(  r%|r#|j                  |t        |	             |||<   |j                  |d        |j!                         D ](  \  }}||v s||   j"                  j                  |       * ||fS c c}w )z(zones by name, where each man is). Rows in file order - the file IS the order.

    A man is on at most one zone: dragging him somewhere new takes him off the old one without
    anybody having to remember to. The register still holds both rows.
    T)r(   r?   rV   r"   rW   actionr1   createdr'   Fr8   r<   r>   r   N)ALWAYSr5   r*   getr/   lower
setdefaultr7   r>   rC   r8   r;   appendr<   PLACERSpopitemsr@   )	rowsnzoneswhererznrW   rd   r1   s	            r)   statert   `   s    DJJaa1D!99JEJE (fb)*%%/'R..0%%/'R..0668%%/'R..0Y2R2/#5uRy~~E"IN"E"INw2;6V3C$E"IOU2Y222b	%%,,V4z!bEk!'E"Iv"+!E"INw6~"  Tr]3 "f		&$'-(. kkm ,
;"I##F+, %<9 Ks   Hc                   i g dfd}| D ]  }|j                  d      xs dj                         j                         }|t        vr=|j                  d      xs dj                         }|sct	        |j                  dd            } |||       |dk(  st        |j                  dd            }|j                  d      xs dj                         }t        |      rd	|v r|j                  d	d
      d
   n|}	|||	f|<    j                         D ]P  \  }}
|
\  }}}	j                  t        |j                  |      xs t        |      j                  ||d|	             R S )zJEvery stint on the board today, closed off by whatever moved the man next.rW   c           
         j                  | d       }|rL|\  }}}j                  t        |j                  |      xs t	        |      j
                  | |||             y y )N)rl   rj   rU   rg   r5   r7   )	rW   atgotrs   startedrZ   open_atoutrp   s	         r)   closezspans.<locals>.close   s[    kk&$' #BJJtB2!:$r( @ @&'SUW[\] r+   rd   r"   	timestampr   rV   r1   r!   r.   )rW   r6   rw   r6   )rg   r/   rh   rk   rb   r*   r3   r%   rm   rj   rU   r5   r7   )rn   rp   r|   rr   rd   rW   ra   rs   r1   rZ   rx   ry   rz   r{   s    `          @@r)   spansr~      s`   /1GC^  -%%/'R..0668 %%/'R..0155b)*fbT>AEE&"-.BeeHo+224F.3Fmv6<<Q'*SYD!2tnGFO- }} ZGT

4UYYr]6d2h<<fgrSWXYZ Jr+   c                $   t        |       \  }}g }i }t        | |      D ]-  }|j                  |j                  g       j	                  |       / |j                         D ]  \  }}|j                  |      xs t        |      }|j                  r!|j                  |k7  r|j                  dz   |z   n|}	|D ]V  }|j                  rd|j                  z   dz   nd}
|j	                  |	dz   |j                  z   dz   |j                  z   |
z          X  | D ]{  }|j                  d      xs dj                         j                         }t        |j                  dd            }t        |j                  dd            }|j                  d	      xs dj                         }|j                  d
      xs dj                         }|j                  d      xs dj                         }|dk(  r,|j	                  |dz   |z   dz   |z   |rd|z   dz   ndz          |dk(  r&|j	                  |dz   |z   |rd|z   dz   ndz          0|dk(  r#|j	                  |dz   |z   |rd|z   ndz          X|dk(  s_|j	                  |dz   |z   dz   |z          ~ |S )zThe WORKS section of the diary, written by the board while the foreman was doing something else.

    'STEEL - 5M SEATS - Matty Bell, 07:04-11:15'. One line per stint, then what moved on each zone.
    rJ   z ()r"   z, rd   rV   r}   byrW   r1   r8   r!   r>   u    — finished r   z sent home r   z
 moved to )rt   r~   ri   rV   rj   rm   rg   r5   r7   rZ   rW   r\   r/   rh   r*   rb   )rn   rp   _linesby_zonesrs   sszheadrZ   rr   rd   whenwhorW   r1   s                    r)   works_linesr      sx   
 T{HE1E!G4 11662&--a01--/ LBIIbM%T"X()166R<qvv"$R 	LA*+&&4!&&=3&bDLL!((2T9AGGCdJK	LL  F%%/'R..0668fb)*QUU;+,uuT{ b'')%%/'R..0%%/'R..0WLLg.4t;SVtczC?O\^_`vLL..5Sc9IVXYZvLL-/$6f'F:JZ\]^wLL,.7#=DEF Lr+   
inspectionc                    t         j                  |      }|r*|| j                  vrdt        j                  ||      z   dz   S y)zJ'' = go ahead. Anything else is the words that go on the foreman's screen.zneeds z firstr"   )HOLDrg   r;   
HOLD_WORDS)rV   targetneeds      r)   
hold_blockr      s>    88FDD,,,*..t44x??r+   c                h    | t        d      z   }|j                         dk(  r|t        d      z  }|S )zQTomorrow, unless tomorrow is a Sunday. Saturdays are worked and always have been.r.   )days   )r   weekday)r   nxts     r)   next_working_dayr      s3    
)#
#C
{{}ya  Jr+   c                   dj                  |xs dj                               j                         }d}| D ]  }|j                  d      xs dj	                         |k(  s*dj                  |j                  d      xs dj                               j                         |k(  sn|j                  d      xs dj	                         } |S )z[Where this bloke is on that date. Last row wins - the file is a history, this is the state.r!   r"   r   rW   job)r$   r%   rh   rg   r/   )rn   dayrW   keyr   rr   s         r)   
roster_forr      s    
((FLb'')
*
0
0
2C
C /EE&MR&&(C/CHHaeeHo>SQS=Z=Z=\4]4c4c4eil4l55<%2,,.C/ Jr+   c                   i }g }| D ]  }|j                  d      xs dj                         |k7  r*dj                  |j                  d      xs dj                               }|s_||vr|j	                  |       |j                  d      xs dj                         ||<    i }|D ]&  }|j                  ||   g       j	                  |       ( |S )Nr   r"   r!   rW   r   )rg   r/   r$   r%   rj   ri   )rn   r   latestorderrr   rW   r{   s          r)   roster_by_jobr      s    FE 6EE&MR&&(C/155?0b779:LL %%,,"335v6 C :vf~r*11&9:Jr+   c                   | j                  d      j                         dg}d}|D ]v  }|j                  |d   g       }|sd}|j                  |d   dz   |d   z   j	                                |t        |t        j                        z  }|j                  d       x |s|d	   d
z   S dj                  |      j                         dz   S )zUThe WhatsApp message, tradie-typed. Copied out by hand - nothing here sends anything.z%a %d/%mr"   Fr   Tlabelr!   )r   r   z

Nobody rostered yet.
z

Any problems ring me.)
strftimer&   rg   rj   r/   sortedr6   rh   r$   rstrip)r   jobsby_jobr   rx   jnamess          r)   roster_messager      s    \\*%++-r2E
C 

1U8R(aj3&5188:;399--R Qx44499U""$'BBBr+   c                6    | j                  d      ||||||dS )Nseconds)timespec)r}   r   rV   rW   rd   r1   r   )	isoformat)nowr   rV   rW   rd   r1   r   s          r)   rowr     s*    	:3PT&L Lr+   N)r(   r6   rM   r6   )r1   r6   rM   r6   )ra   r6   rM   r6   )rn   
list[dict]rM   ztuple[dict, dict])rn   r   rp   dictrM   z
list[Span])rn   r   rM   z	list[str])rV   r5   r   r6   rM   r6   )r   r   rM   r   )rn   r   r   r6   rW   r6   rM   r6   )rn   r   r   r6   rM   r   )r   r   r   r:   r   r   rM   r6   )r   r   r   r6   rV   r6   rW   r6   rd   r6   r1   r6   r   r6   rM   r   )r]   
__future__r   dataclassesr   r   r   r   r   DECKrf   rC   r   	ESTIMATESCHIP_ACTIONSrk   r*   r3   r5   rU   rb   rt   r~   r   r   r   r   r   r   r   r   rS   r+   r)   <module>r      s    # ( . . T Z	  
K 	+-	 $k/R
(7
" f f f* ^ ^ ^"J>F <(
$C"Lr+   