From 707e18c625b6ef74934d5e34e8d2b9d1a6a75142 Mon Sep 17 00:00:00 2001 From: Docker Config Backup Date: Tue, 22 Sep 2026 09:28:48 +0200 Subject: [PATCH] =?UTF-8?q?fix:=20correct=20name=20to=20K=C3=B3p=C3=A1?= =?UTF-8?q?=C4=8Dek=20Ond=C5=99ej;=20O=20(otcovsk=C3=A1)=20looks=20like=20?= =?UTF-8?q?D,=20counts=20like=20N?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The new worker's surname was misheard: Kropáček → Kópáček everywhere (default data, both Excel templates, export rosters). The person id tkb-kropacek is kept. The server now normalises the name in stored files at startup and in every incoming save, so clients that still hold the old name cannot write it back. "O" (otcovská dovolená) is now rendered in the same yellow as "D" in the app and the month Excel, labelled "Otcovská dovolená", and for the FPD balance a working-day O is credited like N (a normal worked day) both in the web FPD check and in the month Excel's FPD column, which previously counted N and O as zero and disagreed with the web. Co-Authored-By: Claude Fable 5.1 --- web/dochazka_template.xlsx | Bin 9247 -> 9248 bytes web/export_dochazka.py | 4 ++-- web/export_full_excel.py | 18 ++++++++++++------ web/export_harmonogram.py | 4 ++-- web/public/full_template.xlsx | Bin 25485 -> 25491 bytes web/server.js | 27 +++++++++++++++++++++++---- web/src/FpdCheck.tsx | 6 +++--- web/src/cellColors.ts | 2 +- web/src/data.json | 2 +- 9 files changed, 44 insertions(+), 19 deletions(-) diff --git a/web/dochazka_template.xlsx b/web/dochazka_template.xlsx index 166b1c0d30f81a33e3a891c7e1706aa0e46eb989..3a4766ae41f2705d778189a10aaaebfc9822d4b9 100644 GIT binary patch delta 843 zcmbR5vA}~jz?+#xgn@y9gCWJ+Y$Go#BQucREXt_O1ZFrhpJE3y1h|#?!3;Agc1BL1 znpoq4-}dp7-J})kPv=P)inM*N<;vd1%fqa=R8U~0qsd;D0A`(C#mChp+2dE_y0xZr z@C%e)j@*| z9Ho!)d2eVA+9kRuqi^kp1u}KT^+pyuHN_8!KCTpPU8ay`G3jLtcfh^_H#^qtdl0jw zdIg`m#;3Sny_YmhB6z1?z4N12r&&$)hLxV~x<73XO6K1*+QlofdS=9%YdfqW9(VuE zm$8<)>OcAN<|WhiWSIpD+P<6fFw<>Wlab!vYYPr}7&#UuZ#a~n{v>NAN+yI4OhvGNWCNbvO>K)$6C=`D6@K=xL`xK6^ zJHaUW)l$T?q(Swh=Zf_{mcK0IUi$1Vh-lTmzPs=whm4%slt-H?v@q8w^RMYVs-&hOa^=m@)aL zq8TWWP8L$K0@MCV7GSzd$r(&vP;x~|yK>5wV9_XLX~rXy%aj$syqQ3r)a0$o^75cm i-v8~XStKI^LpUn~gD^0kz(50|x05fLJszoj z;CaSqlUbz7x_0*x!9C$D=X`dZi7S`i|JQr>uk5AYj+SeB@Et2!YZVx@)|Dk>m1Ow$ zxfw?9!lMK?_G!7bhF$2Kmaw?{-Rf;y`&t50tplIk`D4?UJF9WYwpI1d7aW>zovTv% z@amo8WqA!ovl%TkA62a_6Z1Y5>Jqd!V4d*Rdu}NUe{5%s*;kXXZBgFsPkFyBPVAg} z*`!A{L}!M~qIGxvZm65RE%|!xarSriYj`&-(%54EDs)EFqMJU(BER$gvuFosd^3)m zxS%(wUG;{e=3TBpljC6(0et&yCF|$hna2IF>*Jm-r(gkNnUf{!ST*7w#7wX-z z4Qp2x`Kj>NEmK5lP21_LygzQ!948Cq$W9jvuX8TgrJo~tm#yonk4{;3jO?0^NB^1k z$@aZke)45xkoP^4*(*Ba%Flf;Q4V&LoL-k5kf<_q!4AWShue*dwuTrS*1TSL>a1M7 zW8rlx;U(_Hec5fiOWs_um;Rq~vg4UTfMDs8PwuO}B*jk#TM-&-#_0 zeBi6v;^+HrtZmM2>uSxuad`g*i#v(C>lske=;n*E!H`6%F0TS%_$hRP8Ix}*nt{^j zWML&MFdd*|0j9f^oWb-(C0C@RE3a$`7L8VxW;{H(Tv-9kn+4=aPTr<0FAqxO{okIN eMKUrlgtIa*2m`YT3^Xu0O#Y&*#&${(Bmw~4Nnrf| diff --git a/web/export_dochazka.py b/web/export_dochazka.py index 2ff5fcf..67f33c6 100644 --- a/web/export_dochazka.py +++ b/web/export_dochazka.py @@ -38,7 +38,7 @@ TEMPLATE_NAMES = [ 'Vörös Pavel', 'Janouš Petr', 'Dvořák Václav', - 'Kropáček Ondřej', + 'Kópáček Ondřej', 'Toman Milan', 'Hanzlík Marek', 'Vondrák Pavel', @@ -52,7 +52,7 @@ PERSON_DATA = { 'Žemlička Miroslav': {'auto': 'AUS', 'km_tkb': 40, 'km_sat': 0}, 'Franek Lukáš': {'auto': 'AUS', 'km_tkb': 40, 'km_sat': 0}, 'Dvořák Václav': {'auto': 'AUS', 'km_tkb': 0, 'km_sat': 0}, - 'Kropáček Ondřej': {'auto': 'AUS', 'km_tkb': 0, 'km_sat': 0}, # TODO confirm auto/km + 'Kópáček Ondřej': {'auto': 'AUS', 'km_tkb': 0, 'km_sat': 0}, # TODO confirm auto/km 'Toman Milan': {'auto': 'AUS', 'km_tkb': 0, 'km_sat': 0}, 'Kohl David': {'auto': 'AUS', 'km_tkb': 0, 'km_sat': 0}, 'Milisavljevič Jovica':{'auto': 'AUS', 'km_tkb': 0, 'km_sat': 0}, diff --git a/web/export_full_excel.py b/web/export_full_excel.py index a790f89..a0fabc5 100644 --- a/web/export_full_excel.py +++ b/web/export_full_excel.py @@ -26,7 +26,7 @@ CELL_COLORS = { 'A': 'FFE082', 'B': 'B0BEC5', 'D': 'FFFF00', 'D/2': 'FFF9C4', 'N': 'FF4444', 'U': '92D050', - 'O': 'FFC000', 'x': 'E0E0E0', + 'O': 'FFFF00', 'x': 'E0E0E0', # O = otcovská: same look as D } # Czech weekday names indexed by Python's weekday() (Monday=0) @@ -36,7 +36,7 @@ CZECH_DAYS = ['Pondělí', 'Úterý', 'Středa', 'Čtvrtek', 'Pátek', 'Sobota', TKB_ROWS = { 'Pauzer Libor': 7, 'Vörös Pavel': 8, 'Janouš Petr': 9, 'Franek Lukáš': 10, 'Svoboda Daniel': 11, 'Dvořák Václav': 12, - 'Kropáček Ondřej': 13, + 'Kópáček Ondřej': 13, 'Vondrák Pavel': 14, 'Čeleda Olda': 15, 'Hanzlík Marek': 16, 'Kohl David': 17, 'Dittrich Vladimír': 18, 'Toman Milan': 19, 'Zábranský Petr': 20, 'Žemlička Miroslav': 21, 'Teslík Hynek': 22, @@ -434,7 +434,7 @@ def main(): continue worked = 0.0 vacation = 0.0 # D = 8h, D/2 = 4h — reduces person's FPD target - def collect(v): + def collect(v, is_workday): nonlocal worked, vacation if not v: return @@ -442,6 +442,11 @@ def main(): vacation += 8 elif v == 'D/2': vacation += 4 + elif v in ('N', 'O'): + # sick / paternity leave on a working day is credited as a normal + # worked day, so it neither helps nor hurts the balance (as in FpdCheck.tsx) + if is_workday: + worked += 8 else: worked += hours_for(v) for d in schedule['dayIndex']: @@ -450,13 +455,14 @@ def main(): cd = person['data'].get(str(d['idx'])) if not cd: continue + is_workday = not d.get('weekend') and (d['month'], d['day']) not in holidays is_split = bool(cd.get('dayColor') or cd.get('nightColor') or cd.get('dayValue') or cd.get('nightValue')) if is_split: - collect(cd.get('dayValue')) - collect(cd.get('nightValue')) + collect(cd.get('dayValue'), is_workday) + collect(cd.get('nightValue'), is_workday) else: - collect(cd.get('v')) + collect(cd.get('v'), is_workday) person_fpd = month_fpd - vacation diff = worked - person_fpd dst = ws.cell(row, 72) diff --git a/web/export_harmonogram.py b/web/export_harmonogram.py index 0b6bc3e..a389963 100644 --- a/web/export_harmonogram.py +++ b/web/export_harmonogram.py @@ -42,8 +42,8 @@ HALF_TIME_NAMES = {'Dittrich Vladimír'} ROSTER = [ ('Dvořák Václav (VN)', 'TKB', 1247, 'Dvořák Václav'), - # Kropáček Ondřej — part-time student, not in CIS (no personal number); add here - # if he joins full time: ('Kropáček Ondřej', 'TKB', , 'Kropáček Ondřej'), + # Kópáček Ondřej — part-time student, not in CIS (no personal number); add here + # if he joins full time: ('Kópáček Ondřej', 'TKB', , 'Kópáček Ondřej'), ('Vondrák Pavel (NN)', 'TKB', 454, 'Vondrák Pavel'), ('Čeleda Olda (NN)', 'TKB', 463, 'Čeleda Olda'), ('Hanzlík Marek (VN)', 'TKB', 1366, 'Hanzlík Marek'), diff --git a/web/public/full_template.xlsx b/web/public/full_template.xlsx index ccea9d1ff986ae1633690452af5a21a1344c4ee6..427b91dc8a1fd36229c5321f8c83b723d328c282 100644 GIT binary patch delta 7826 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 { if (!data || (!data.people && !data.stations) || !data.dayIndex) { return res.status(400).json({ error: 'Invalid schedule data (need people/stations and dayIndex)' }) } + normalizePeople(data) const now = new Date().toISOString() const fileObj = { id: crypto.randomUUID(), @@ -419,6 +436,7 @@ app.put('/api/files/:id', (req, res) => { if ((!data.people && !data.stations) || !data.dayIndex) { return res.status(400).json({ error: 'Invalid schedule data (need people/stations and dayIndex)' }) } + normalizePeople(data) file.data = data } file.modifiedAt = new Date().toISOString() @@ -443,6 +461,7 @@ app.post('/api/files/:id/publish', (req, res) => { if ((!data.people && !data.stations) || !data.dayIndex) { return res.status(400).json({ error: 'Invalid schedule data (need people/stations and dayIndex)' }) } + normalizePeople(data) file.data = data file.modifiedAt = now } diff --git a/web/src/FpdCheck.tsx b/web/src/FpdCheck.tsx index 8e4e032..61681f1 100644 --- a/web/src/FpdCheck.tsx +++ b/web/src/FpdCheck.tsx @@ -68,9 +68,9 @@ export function computeFpd( // D vacation on a working day reduces the FPD target. if (v === 'D') { if (isWorkDay) vacationHours += dailyHours } else if (v === 'D/2') { if (isWorkDay) vacationHours += dailyHours / 2 } - // N sick on a working day is credited as a normal worked day (daily hours), - // so sick leave neither helps nor hurts the FPD balance. - else if (v === 'N') { if (isWorkDay) workedHours += dailyHours } + // N (sick) and O (otcovská dovolená) on a working day are credited as a normal + // worked day (daily hours), so they neither help nor hurt the FPD balance. + else if (v === 'N' || v === 'O') { if (isWorkDay) workedHours += dailyHours } else workedHours += getHoursForValue(v) } if (isSplit) { diff --git a/web/src/cellColors.ts b/web/src/cellColors.ts index f81b740..146d04a 100644 --- a/web/src/cellColors.ts +++ b/web/src/cellColors.ts @@ -17,7 +17,7 @@ const CELL_STYLES: Record = { 'D/2': { bg: '#FFF9C4', text: '#333', label: 'Půl den dovolená' }, 'N': { bg: '#FF4444', text: '#fff', label: 'Nemocenská' }, 'U': { bg: '#92D050', text: '#333', label: 'Uzavěra' }, - 'O': { bg: '#FFC000', text: '#333', label: 'Otčovská' }, + 'O': { bg: '#FFFF00', text: '#333', label: 'Otcovská dovolená' }, // looks like D, counts like N 'x': { bg: '#E0E0E0', text: '#999', label: 'Bez zkušeností VN' }, } diff --git a/web/src/data.json b/web/src/data.json index 1d4198e..3862ff8 100644 --- a/web/src/data.json +++ b/web/src/data.json @@ -2965,7 +2965,7 @@ }, { "id": "tkb-kropacek", - "name": "Kropáček Ondřej", + "name": "Kópáček Ondřej", "group": "TKB", "data": {} },