diff --git a/service/data-hub/business-engine/.gitignore b/service/data-hub/business-engine/.gitignore index 5a9f2b6..a46b128 100644 --- a/service/data-hub/business-engine/.gitignore +++ b/service/data-hub/business-engine/.gitignore @@ -1,3 +1,5 @@ +daten.csv + tmp/ # Binaries for programs and plugins diff --git a/service/data-hub/business-engine/daten.csv b/service/data-hub/business-engine/daten.csv deleted file mode 100644 index 4121494..0000000 --- a/service/data-hub/business-engine/daten.csv +++ /dev/null @@ -1,73 +0,0 @@ -,,,Vertrag,Vertrag,Vertrag,Vertrag,Vertrag,Vertrag,Vertrag,Vertrag,"Stunden innerhalb der Soll-Stunden","Stunden innerhalb der Soll-Stunden","Stunden innerhalb der Soll-Stunden","Stunden innerhalb der Soll-Stunden","Stunden innerhalb der Soll-Stunden","Stunden innerhalb der Soll-Stunden",Ist-/Soll-Stunden,Ist-/Soll-Stunden,Ist-/Soll-Stunden,Ist-/Soll-Stunden,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Berechnung,Salden,Salden,Salden,Salden,Salden,Salden,Salden,Salden,Salden,Auszahlen,Auszahlen,Auszahlen,Auszahlen,Auszahlen,Auszahlen,Auszahlen,Auszahlen,Auszahlen,Auszahlen,Auszahlen -,,,,,,,,,,,"Gearbeitete Stunden","Gearbeitete Stunden","Urlaub nehmen","Urlaub nehmen",Krankheitsstunden,Krankheitsstunden,Gesamt,Gesamt,Vertrag,Vertrag,Plus/Min,Mehrstunden,Überstunden,"Zuschlag P-Schein","Krank ohne AU","Krank ohne AU","Nachtzuschlag 25 (25%)","Nachtzuschlag 25 (25%)","Nachtzuschlag 40 (40%)","Nachtzuschlag 40 (40%)","Sonntagszuschlag (50%)","Sonntagszuschlag (50%)","Feiertagszuschlag (125%)","Feiertagszuschlag (125%)","Verpfl.-pauschale (14%)","Samstagzuschlag (15%)","Samstagzuschlag (15%)",Zeitausgleich,Zeitausgleich,Zeitausgleich,Zeitausgleich,Zeitausgleich,Urlaub,Urlaub,Urlaub,Urlaub,Mehrstunden,"Überstunden auszahlen",Fahrtkosten,Verpflegungspauschale,"Zuschlag P-Schein",25%,40%,50%,125%,14%,15% -Persnr.,Nachname,Vorname,Art,P-Schein,"Recht auf Zuschläge?",Start,Tage,Stunden,Max,"Urlaubstage pro Jahr",Tage,Stunden,Tage,Stunden,Tage,Stunden,Tage,Stunden,Tage,Stunden,Stunden,Stunden,Stunden,anzahl,Tage,Stunden,Tage,Stunden,Tage,Stunden,Tage,Stunden,Tage,Stunden,Tage,Tage,Stunden,Start,+/-,Änderungen,Auszahlen,Jetzt,Start,Abbau,Korrektur,Jetzt,Stunden,Stunden,km,Tage,Anzahl,Stunden,Stunden,Stunden,Stunden,Stunden,Stunden -169,Safari,"Abdul Latif ",Fest,Ja,Ja,2025-09-01,5.00,40.00,0.00,20,20,180.4167,5,40,0,0,25,220.41666666667,21.667,173.333,47.08366666667,0.00033333332999064,47.08333333334,20,0,0,0,0,0,0,0,0,2,16.166666666667,16,2,17.35,0.334,47.08366666667,47.08366666667,47.08366666667,0.334,19,5,0,14,0.00033333332999064,47.08333333334,0.00,20,20,0,0,0,16.166666666667,18.9,17.35 -93,"Moshtagh Askari",Adel,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,25,218.4167,0,0,0,0,25,218.41666666667,21.667,173.333,45.08366666667,0.00033333332999064,45.08333333334,25,0,0,0,0,0,0,0,0,2,18.65,20,3,24.95,0.007,45.08366666667,45.08366666667,45.08366666667,0.0069999999999979,31,0,0,31,0.00033333332999064,45.08333333334,0.00,25,25,0,0,0,18.65,14.816666666667,24.95 -18,Mihailescu,"Adrian Lucian",Fest,Ja,Ja,2025-09-01,5.00,40.00,0.00,20,21,177.5667,0,0,0,0,21,177.56666666667,21.667,173.333,4.23366666667,0.00033333332999064,4.23333333334,21,0,0,0,0,0,0,0,0,1,8.6333333333333,15,3,24.116666666667,0,4.23366666667,4.23366666667,4.23366666667,0,20,0,0,20,0.00033333332999064,4.23333333334,0.00,18,21,0,0,0,8.6333333333333,11.1,24.116666666667 -,"Esmaeili Dashtbayaz",Amin,Fest,Nein,Ja,2025-04-01,5.00,40.00,0.00,,20,171.2667,0,0,0,0,20,171.26666666667,21.667,173.333,-2.06633333333,0,0,,0,0,0,0,0,0,0,0,0,0,18,2,16.083333333333,0,-2.06633333333,-2.06633333333,0,-2.06633333333,-3,0,15,12,0,0,0.00,20,0,0,0,0,0,11.183333333333,16.083333333333 -,Ahmadpour,Amirhossein,Fest,Ja,Ja,2025-09-01,5.00,40.00,0.00,24,21,193.6333,2,16,0,0,23,209.63333333333,21.667,173.333,36.30033333333,0.00033333332999064,36.3,21,0,0,0,0,0,0,1,8.4666666666667,1,8.7833333333333,19,0,0,0,36.30033333333,36.30033333333,36.30033333333,0,-2,2,13,9,0.00033333332999064,36.3,0.00,21,21,0,0,8.4666666666667,8.7833333333333,24.383333333333,0 -188,"Malani Karizi",Arasch,Fest,Nein,Ja,2025-09-01,5.00,40.00,0.00,20,24,211.9833,0,0,0,0,24,211.98333333333,21.667,173.333,38.65033333333,0.00033333332999064,38.65,,0,0,6,2.6,0,0,0,0,1,8.25,20,3,24.7,-147.647,38.65033333333,38.65033333333,0,-108.99666666667,5,0,0,5,0,0,0.00,24,0,2.6,0,0,8.25,16.433333333333,24.7 -113,Ziaudin,Atiq,Fest,Ja,Ja,2025-02-24,5.00,40.00,0.00,20,23,194.3167,0,0,0,0,23,194.31666666667,21.667,173.333,20.98366666667,0.00033333332999064,20.98333333334,23,0,0,0,0,0,0,0,0,1,6.4333333333333,20,2,15.05,14.047,20.98366666667,20.98366666667,20.98366666667,14.047,9,0,0,9,0.00033333332999064,20.98333333334,0.00,21,23,0,0,0,6.4333333333333,12.833333333333,15.05 -,Rahmati,Behnam,Fest,Ja,Ja,2025-04-01,5.00,40.00,0.00,,20,176.05,0,0,0,0,20,176.05,21.667,173.333,2.717,0.00033333332999064,2.71666666667,20,1,8.5,0,0,0,0,0,0,0,0,20,0,0,0,2.717,2.717,2.717,0,-2,0,15,13,0.00033333332999064,2.71666666667,0.00,20,20,0,0,0,0,16.05,0 -,Altner,"Christian Van Manh",Fest,Ja,Ja,2025-10-01,5.00,40.00,0.00,20,22,184.0833,0,0,0,0,22,184.08333333333,21.667,173.333,10.75033333333,0.00033333332999064,10.75,22,0,0,1,0.2,0,0,0,0,1,7.9333333333333,20,1,8.0166666666667,0,10.75033333333,10.75033333333,10.75033333333,0,0,0,2,2,0.00033333332999064,10.75,0.00,21,22,0.2,0,0,7.9333333333333,7.9333333333333,8.0166666666667 -,Aba,Cuan,Fest,Nein,Ja,2025-08-01,5.00,40.00,0.00,,8,50.25,6,39,0,0,14,89.25,21.667,173.333,-84.083,0,0,,0,0,0,0,0,0,0,0,0,0,0,0,0,-144.25,-84.083,-84.083,0,-228.333,0,6,10,4,0,0,0.00,,0,0,0,0,0,0,0 -,Haghighivand,Danial,Fest,Nein,Ja,2025-04-01,5.00,40.00,0.00,,19,166.0333,2,16,0,0,21,182.03333333333,21.667,173.333,8.70033333333,0.00033333332999064,8.7,,0,0,0,0,0,0,0,0,0,0,19,0,0,0,8.70033333333,8.70033333333,8.70033333333,0,-10,2,15,3,0.00033333332999064,8.7,0.00,19,0,0,0,0,0,14.033333333333,0 -,Mohammadi,Danial,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,21,182.8667,0,0,0,0,21,182.86666666667,21.667,173.333,9.53366666667,0.00033333332999064,9.53333333334,21,0,0,0,0,0,0,0,0,1,8.3333333333333,18,2,16.616666666667,0,9.53366666667,9.53366666667,9.53366666667,0,7,0,0,7,0.00033333332999064,9.53333333334,0.00,20,21,0,0,0,8.3333333333333,13.916666666667,16.616666666667 -,Shahrasebi,Danial,Fest,,,2021-05-01,0.00,0.00,0.00,,,,0,0,0,0,0,0,0,0,0,0,0,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,5,0,0,,,0,0,0,0,0,0,0 -,Emkani,Daniel,Fest,Nein,Ja,2025-07-15,3.00,25.00,0.00,,14,118.45,0,0,0,0,14,118.45,13,108.333,10.117,10.117,0,,0,0,0,0,0,0,0,0,1,8.6833333333333,0,2,13.3,0,10.117,10.117,10.117,0,0,0,7,7,10.117,0,0.00,12,0,0,0,0,8.6833333333333,0,13.3 -,Lolies,Danny,Fest,Ja,Ja,2025-03-01,5.00,40.00,0.00,,19,158.9,0,0,1,8.5,20,167.4,21.667,173.333,-5.933,0,0,19,3,24,0,0,0,0,0,0,1,5.55,15,2,17.05,0,-5.933,-5.933,0,-5.933,10,0,0,10,0,0,0.00,17,19,0,0,0,5.55,11.05,17.05 -,Hastedt,David,Fest,Nein,Ja,2025-01-27,4.00,32.00,0.00,20,14,112.3167,0,0,4,32,18,144.31666666667,17.333,138.667,5.64966666667,5.64966666667,0,,0,0,0,0,0,0,0,0,0,0,11,0,0,0,5.64966666667,5.64966666667,5.64966666667,0,2,0,0,2,5.64966666667,0,0.00,11,0,0,0,0,0,7.4166666666667,0 -2,Shahrasebi,David,Fest,Ja,Ja,2022-10-01,5.00,40.00,0.00,20,,0,0,0,0,0,0,0,21.667,173.333,0,0,0,,1,8.5,0,0,0,0,0,0,0,0,0,0,0,151.34,0,0,0,151.34,2,0,0,2,0,0,,,0,0,0,0,0,0,0 -,Golmohammadi,"Davood ",Fest,Ja,Ja,2025-08-01,5.00,40.00,0.00,20,20,182.2167,0,0,0,0,20,182.21666666667,21.667,173.333,8.88366666667,0.00033333332999064,8.88333333334,20,1,8,0,0,0,0,0,0,0,0,20,0,0,0,8.88366666667,8.88366666667,8.88366666667,0,-6,0,8,2,0.00033333332999064,8.88333333334,0.00,20,20,0,0,0,0,22.216666666667,0 -202,Pouzesh,Esmail,Fest,Ja,Ja,2025-09-01,5.00,40.00,0.00,20,24,202.0833,0,0,0,0,24,202.08333333333,21.667,173.333,28.75033333333,0.00033333332999064,28.75,24,0,0,21,70.416666666667,9,20.6,1,9.5,4,17.816666666667,0,0,0,0,28.75033333333,28.75033333333,28.75033333333,0,12,0,0,12,0.00033333332999064,28.75,0.00,24,24,70.416666666667,20.6,9.5,17.816666666667,0,0 -187,"Sajaei Khouzestani",Farid,Fest,Ja,Ja,2025-04-07,5.00,40.00,0.00,20,22,197.4333,0,0,0,0,22,197.43333333333,21.667,173.333,24.10033333333,0.00033333332999064,24.1,22,0,0,0,0,0,0,0,0,2,17.316666666667,18,2,16.366666666667,0,24.10033333333,24.10033333333,24.10033333333,0,19,0,0,19,0.00033333332999064,24.1,0.00,22,22,0,0,0,17.316666666667,19.75,16.366666666667 -191,"Faridani Rad",Farzad,Fest,Ja,Ja,2025-02-01,5.00,40.00,0.00,20,21,174.0833,0,0,2,16,23,190.08333333333,21.667,173.333,16.75033333333,0.00033333332999064,16.75,21,0,0,14,44.5,2,5.6666666666667,0,0,3,16.15,5,0,0,0,16.75033333333,16.75033333333,16.75033333333,0,0,0,0,0,0.00033333332999064,16.75,0.00,21,21,44.5,5.6666666666667,0,16.15,1.7666666666667,0 -,Movafagh,"Farzad ",Fest,Ja,Ja,2025-02-03,5.00,40.00,0.00,20,23,202.6167,0,0,1,8,24,210.61666666667,21.667,173.333,37.28366666667,0.00033333332999064,37.28333333334,23,0,0,0,0,0,0,0,0,0,0,20,3,24.55,0,37.28366666667,37.28366666667,37.28366666667,0,17,0,0,17,0.00033333332999064,37.28333333334,0.00,23,23,0,0,0,0,18.066666666667,24.55 -89,Hashimazada,Firuz,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,18,155.35,0,0,3,24,21,179.35,21.667,173.333,6.017,0.00033333332999064,6.01666666667,18,1,8,0,0,0,0,0,0,1,8.5333333333333,17,0,0,0,6.017,6.017,6.017,0,8,0,0,8,0.00033333332999064,6.01666666667,0.00,18,18,0,0,0,8.5333333333333,10.816666666667,0 -,Saeedpour,Fouad,Fest,Ja,Ja,2025-09-01,5.00,40.00,0.00,,23,203.2833,0,0,0,0,23,203.28333333333,21.667,173.333,29.95033333333,0.00033333332999064,29.95,23,0,0,2,4.25,0,0,3,26.8,1,9,16,3,25.25,0,29.95033333333,29.95033333333,29.95033333333,0,26,0,0,26,0.00033333332999064,29.95,0.00,23,23,4.25,0,26.8,9,9.9833333333333,25.25 -55,Khodayaran,Hossein,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,13,105.3,10,80,0,0,23,185.3,21.667,173.333,11.967,0.00033333332999064,11.96666666667,13,0,0,11,31,2,5.6666666666667,0,0,2,8.1333333333333,0,0,0,0,11.967,11.967,11.967,0,16,10,0,6,0.00033333332999064,11.96666666667,0.00,12,13,31,5.6666666666667,0,8.1333333333333,0,0 -206,Rasulkhani,Hossein,Fest,Ja,Ja,2025-03-06,5.00,40.00,0.00,20,23,194.8667,0,0,0,0,23,194.86666666667,21.667,173.333,21.53366666667,0.00033333332999064,21.53333333334,23,0,0,4,10.433333333333,0,0,1,9.25,1,9,13,4,32.366666666667,0,21.53366666667,21.53366666667,21.53366666667,0,29,0,0,29,0.00033333332999064,21.53333333334,0.00,23,23,10.433333333333,0,9.25,9,7.8166666666667,32.366666666667 -,"Mohamed Salah","Hussin Noureldin",Fest,Ja,Ja,2025-06-06,5.00,40.00,0.00,20,22,186.5833,0,0,0,0,22,186.58333333333,21.667,173.333,13.25033333333,0.00033333332999064,13.25,22,0,0,0,0,0,0,0,0,1,8.5166666666667,18,3,24.55,0,13.25033333333,13.25033333333,13.25033333333,0,-11,0,11,0,0.00033333332999064,13.25,0.00,21,22,0,0,0,8.5166666666667,9.5166666666667,24.55 -50,"Rohany Oskoee",Iman,Fest,Nein,Ja,2025-01-01,5.00,40.00,0.00,20,22,190.3833,0,0,0,0,22,190.38333333333,21.667,173.333,17.05033333333,0.00033333332999064,17.05,,0,0,0,0,0,0,0,0,1,8.7333333333333,20,1,8.0333333333333,0,17.05033333333,17.05033333333,17.05033333333,0,36,0,0,36,0.00033333332999064,17.05,0.00,22,0,0,0,0,8.7333333333333,13.616666666667,8.0333333333333 -7,Salehi,Iman,Fest,Ja,Ja,2025-02-01,5.00,40.00,0.00,20,26,220.1,0,0,0,0,26,220.1,21.667,173.333,46.767,0.00033333332999064,46.76666666667,26,0,0,21,68.766666666667,7,13.483333333333,2,18.2,2,16.383333333333,0,1,8.0166666666667,-14.233,46.767,46.767,32.534,7.105427357601E-15,0,0,0,0,0.00033333332999064,32.53366666667,0.00,26,26,68.766666666667,13.483333333333,18.2,16.383333333333,0,8.0166666666667 -,Krüger,Julian,Fest,Ja,Ja,2025-01-15,5.00,40.00,0.00,20,23,197.35,0,0,0,0,23,197.35,21.667,173.333,24.017,0.00033333332999064,24.01666666667,23,0,0,0,0,0,0,0,0,2,14.283333333333,0,2,15.116666666667,0,24.017,24.017,24.017,0,-30,0,38,8,0.00033333332999064,24.01666666667,0.00,19,23,0,0,0,14.283333333333,0,15.116666666667 -,Hazrati,Kamyar,Fest,,Ja,2025-02-24,5.00,40.00,0.00,20,21,182.75,0,0,0,0,21,182.75,21.667,173.333,9.417,0.00033333332999064,9.41666666667,,0,0,0,0,0,0,0,0,0,0,19,2,16.616666666667,0,9.417,9.417,9.417,0,10,0,0,10,0.00033333332999064,9.41666666667,0.00,20,0,0,0,0,0,14.133333333333,16.616666666667 -,Saei,Kasra,Fest,Nein,Ja,2025-08-01,5.00,40.00,0.00,,6,37.2667,10,80,0,0,16,117.26666666667,21.667,173.333,-56.06633333333,0,0,,0,0,0,0,0,0,0,0,0,0,0,0,0,-130.782,-56.06633333333,-56.06633333333,0,-186.84833333333,0,10,10,0,0,0,0.00,,0,0,0,0,0,0,0 -182,Kalantari,Kaveh,Fest,Ja,Ja,2025-03-01,5.00,40.00,0.00,20,18,159.05,5,40,0,0,23,199.05,21.667,173.333,25.717,0.00033333332999064,25.71666666667,18,0,0,2,4.25,0,0,1,10.25,1,9.9,14,2,16.916666666667,0,25.717,25.717,25.717,0,22,5,0,17,0.00033333332999064,25.71666666667,0.00,18,18,4.25,0,10.25,9.9,5.7333333333333,16.916666666667 -,Sahem,Khalid,Fest,Ja,Ja,2025-06-16,5.00,40.00,0.00,20,24,204.35,0,0,0,0,24,204.35,21.667,173.333,31.017,0.00033333332999064,31.01666666667,24,0,0,0,0,0,0,0,0,2,16.833333333333,19,3,26.033333333333,0,31.017,31.017,31.017,0,15,0,0,15,0.00033333332999064,31.01666666667,0.00,24,24,0,0,0,16.833333333333,9.4833333333333,26.033333333333 -194,Saffarnajib,Majid,Fest,Ja,Ja,2025-04-01,3.00,21.00,0.00,16,16,133.3667,0,0,0,0,16,133.36666666667,13,91,42.36666666667,42.36666666667,0,16,0,0,0,0,0,0,0,0,0,0,16,0,0,0,42.36666666667,42.36666666667,42.36666666667,0,0,0,16,16,42.36666666667,0,0.00,16,16,0,0,0,0,5.3666666666667,0 -177,Juyande,Masoud,Fest,Nein,Ja,2025-01-01,5.00,40.00,0.00,20,22,182.9,0,0,0,0,22,182.9,21.667,173.333,9.567,0.00033333332999064,9.56666666667,,0,0,21,68.1,10,23.783333333333,0,0,2,8.5166666666667,0,0,0,0.009,9.567,9.567,9.567,0.0090000000000003,-7,0,0,-7,0.00033333332999064,9.56666666667,0.00,22,0,68.1,23.783333333333,0,8.5166666666667,0,0 -53,Eggerstedt,Matthias,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,22,190.1333,0,0,0,0,22,190.13333333333,21.667,173.333,16.80033333333,0.00033333332999064,16.8,22,0,0,0,0,0,0,0,0,1,8.6333333333333,20,0,0,0,16.80033333333,16.80033333333,16.80033333333,0,8,0,2,10,0.00033333332999064,16.8,0.00,21,22,0,0,0,8.6333333333333,15.233333333333,0 -,Arabnia,Mehdi,Fest,Ja,Ja,2025-05-05,5.00,40.00,0.00,,22,194.3833,0,0,0,0,22,194.38333333333,21.667,173.333,21.05033333333,0.00033333332999064,21.05,22,0,0,0,0,0,0,0,0,0,0,20,2,15.783333333333,0,21.05033333333,21.05033333333,21.05033333333,0,-5,0,12,7,0.00033333332999064,21.05,0.00,21,22,0,0,0,0,18.6,15.783333333333 -,"Jalali Wagener",Mehdi,Fest,Ja,Ja,2025-02-01,5.00,40.00,0.00,,24,204.4833,0,0,0,0,24,204.48333333333,21.667,173.333,31.15033333333,0.00033333332999064,31.15,24,0,0,0,0,0,0,0,0,1,8.5333333333333,21,2,16.35,0,31.15033333333,31.15033333333,31.15033333333,0,-2,0,1,-1,0.00033333332999064,31.15,0.00,24,24,0,0,0,8.5333333333333,11.6,16.35 -,Taghadosi,Mehdi,Fest,Ja,Ja,2025-08-08,5.00,40.00,0.00,,22,188.9333,0,0,0,0,22,188.93333333333,21.667,173.333,15.60033333333,0.00033333332999064,15.6,22,0,0,0,0,0,0,0,0,1,6.3,19,2,16.6,0,15.60033333333,15.60033333333,15.60033333333,0,10,0,0,10,0.00033333332999064,15.6,0.00,21,22,0,0,0,6.3,14.033333333333,16.6 -,Mazidi,Mehrdad,Fest,Ja,Ja,2025-07-01,5.00,40.00,0.00,20,21,183.1667,0,0,0,0,21,183.16666666667,21.667,173.333,9.83366666667,0.00033333332999064,9.83333333334,21,0,0,0,0,0,0,0,0,1,8.1166666666667,18,2,17.033333333333,0,9.83366666667,9.83366666667,9.83366666667,0,0,0,10,10,0.00033333332999064,9.83333333334,0.00,21,21,0,0,0,8.1166666666667,14.016666666667,17.033333333333 -165,Koell,"Melanie Nadine",Fest,Nein,Ja,2025-01-01,5.00,40.00,0.00,20,,0,0,0,4,32,4,32,21.667,173.333,-141.333,0,0,,0,0,0,0,0,0,0,0,0,0,0,0,0,-165.263,-141.333,-141.333,0,-306.596,12,0,0,12,0,0,,,0,0,0,0,0,0,0 -119,Pourhossein,Milad,Fest,Ja,Ja,2025-09-01,5.00,40.00,0.00,20,15,125.6167,7,56,0,0,22,181.61666666667,21.667,173.333,8.28366666667,0.00033333332999064,8.28333333334,15,0,0,0,0,0,0,0,0,1,7.9333333333333,12,2,16.6,-57.848,8.28366666667,8.28366666667,0,-49.56433333333,-6,7,23,10,0,0,0.00,14,15,0,0,0,7.9333333333333,5.0833333333333,16.6 -144,Maleki,Mohammad,Fest,Ja,Ja,2025-09-01,3.00,24.00,0.00,20,5,41.1167,0,0,0,0,5,41.116666666667,13,104,-62.883333333333,0,0,5,2,16,0,0,0,0,0,0,0,0,3,0,0,-250.962,-62.883333333333,-62.883333333333,0,-313.84533333333,-1,0,0,-1,0,0,0.00,3,5,0,0,0,0,1.4,0 -217,"Rasul Khani",Mohammad,Fest,Ja,Ja,2025-03-03,5.00,40.00,0.00,20,24,209.4833,0,0,0,0,24,209.48333333333,21.667,173.333,36.15033333333,0.00033333332999064,36.15,24,0,0,1,2.25,0,0,2,17.45,1,8.25,20,1,8.0166666666667,0,36.15033333333,36.15033333333,36.15033333333,0,20,0,0,20,0.00033333332999064,36.15,0.00,24,24,2.25,0,17.45,8.25,13.516666666667,8.0166666666667 -96,Sabahi,Mohammad,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,18,152.5833,1,8,4,32,23,192.58333333333,21.667,173.333,19.25033333333,0.00033333332999064,19.25,18,0,0,0,0,0,0,0,0,2,16.583333333333,16,0,0,0,19.25033333333,19.25033333333,19.25033333333,0,10,1,0,9,0.00033333332999064,19.25,0.00,18,18,0,0,0,16.583333333333,8,0 -78,Tajikzadeh,Mohammad,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,18,152.3167,5,40,0,0,23,192.31666666667,21.667,173.333,18.98366666667,0.00033333332999064,18.98333333334,18,0,0,0,0,0,0,0,0,1,8.25,16,1,8.0833333333333,0,18.98366666667,18.98366666667,18.98366666667,0,7,5,0,2,0.00033333332999064,18.98333333334,0.00,18,18,0,0,0,8.25,7.9833333333333,8.0833333333333 -,Atrafi,"Mohammad Nasir",Fest,Ja,Ja,2025-10-01,5.00,4.00,0.00,20,19,162.9667,0,0,0,0,19,162.96666666667,21.667,17.333,145.63366666667,145.63366666667,0,19,0,0,0,0,0,0,0,0,0,0,16,3,22.5,0,145.63366666667,145.63366666667,145.63366666667,0,0,0,5,5,145.63366666667,0,0.00,17,19,0,0,0,0,12.466666666667,22.5 -,Amiri,"Mohammad Samir",Fest,Ja,Ja,2025-09-01,5.00,40.00,0.00,20,22,190.15,0,0,3,24,25,214.15,21.667,173.333,40.817,0.00033333332999064,40.81666666667,22,0,0,5,17.25,5,12.633333333333,1,10.166666666667,0,0,0,2,12.316666666667,0,40.817,40.817,40.817,0,11,0,0,11,0.00033333332999064,40.81666666667,0.00,20,22,17.25,12.633333333333,10.166666666667,0,0,12.316666666667 -,"El Moustaiqid",Najlae,Fest,,Ja,2025-09-01,5.00,40.00,0.00,,20,151.7,1,8,0,0,21,159.7,21.667,173.333,-13.633,0,0,,0,0,0,0,0,0,0,0,0,0,0,0,0,-1140.63,-13.633,-13.633,0,-1154.263,-5,1,15,9,0,0,0.00,,0,0,0,0,0,0,0 -,Jasarevic,Noel,Fest,Nein,Ja,2025-09-15,5.00,40.00,0.00,,14,116.6333,7,56,0,0,21,172.63333333333,21.667,173.333,-0.69966666667,0,0,,0,0,0,0,0,0,0,0,0,0,0,0,0,0,-0.69966666667,-0.69966666667,0,-0.69966666667,0,7,6,-1,0,0,0.00,12,0,0,0,0,0,0,0 -,"Sharh Ghaboos",Peyman,Fest,Ja,Ja,2025-03-01,5.00,40.00,0.00,,24,212.6333,0,0,0,0,24,212.63333333333,21.667,173.333,39.30033333333,0.00033333332999064,39.3,24,0,0,6,2.6,0,0,0,0,1,8.25,21,2,16.683333333333,0,39.30033333333,39.30033333333,39.30033333333,0,20,0,0,20,0.00033333332999064,39.3,0.00,24,24,2.6,0,0,8.25,17.1,16.683333333333 -227,Feilbach,"Raoul Nikolai ",Fest,Nein,Ja,2025-09-01,5.00,40.00,0.00,20,24,215.8833,0,0,0,0,24,215.88333333333,21.667,173.333,42.55033333333,0.00033333332999064,42.55,,0,0,16,55.5,16,40.75,1,8.7,4,17.483333333333,0,0,0,0.007,42.55033333333,42.55033333333,42.55033333333,0.0069999999999979,-14,0,20,6,0.00033333332999064,42.55,0.00,24,0,55.5,40.75,8.7,17.483333333333,0,0 -,Hatami,Reza,Fest,Ja,Ja,2025-09-15,5.00,40.00,0.00,20,20,173.9667,0,0,0,0,20,173.96666666667,21.667,173.333,0.63366666667,0.00033333332999064,0.63333333334,20,0,0,0,0,0,0,0,0,0,0,18,2,16.6,0,0.63366666667,0.63366666667,0.63366666666999,9.9920072216264E-15,0,0,6,6,0.00033333332999064,0.63333333334,0.00,20,20,0,0,0,0,13.366666666667,16.6 -137,Pourhossein,Reza,Fest,Ja,Ja,2025-04-01,5.00,40.00,0.00,20,21,181.55,0,0,0,0,21,181.55,21.667,173.333,8.217,0.00033333332999064,8.21666666667,21,0,0,12,36.533333333333,7,15.016666666667,0,0,2,16.316666666667,7,1,8.0166666666667,0,8.217,8.217,8.217,0,29,0,0,29,0.00033333332999064,8.21666666667,0.00,20,21,36.533333333333,15.016666666667,0,16.316666666667,4.1666666666667,8.0166666666667 -225,"Hosseini Jahed",Sajad,Fest,Ja,Ja,2025-03-03,5.00,40.00,0.00,20,21,193.3833,2,16,0,0,23,209.38333333333,21.667,173.333,36.05033333333,0.00033333332999064,36.05,21,0,0,0,0,0,0,1,8.4666666666667,1,8.7833333333333,18,0,0,0,36.05033333333,36.05033333333,36.05033333333,0,39,2,-17,20,0.00033333332999064,36.05,0.00,20,21,0,0,8.4666666666667,8.7833333333333,24.3,0 -,Saki,Sara,Fest,Ja,Ja,2025-02-01,5.00,40.00,0.00,,14,117.6333,10,80,0,0,24,197.63333333333,21.667,173.333,24.30033333333,0.00033333332999064,24.3,14,0,0,11,35.05,0,0,1,8.7,2,16.383333333333,0,0,0,0,24.30033333333,24.30033333333,24.30033333333,0,23,10,-2,11,0.00033333332999064,24.3,0.00,14,14,35.05,0,8.7,16.383333333333,0,0 -,"Perez Y Waldt",Sebastian,Fest,Nein,Ja,2024-09-23,5.00,40.00,0.00,,22,181.9,0,0,0,0,22,181.9,21.667,173.333,8.567,0.00033333332999064,8.56666666667,,0,0,4,14.1,0,0,0,0,1,8.0166666666667,11,3,24.666666666667,-756.446,8.567,8.567,0,-747.879,14,0,0,14,0,0,0.00,17,0,14.1,0,0,8.0166666666667,6.5166666666667,24.666666666667 -38,Hosseini,"Seyed Hamid",Fest,Ja,Ja,2025-03-10,5.00,40.00,0.00,20,18,153.4167,0,0,5,40,23,193.41666666667,21.667,173.333,20.08366666667,0.00033333332999064,20.08333333334,18,0,0,0,0,0,0,0,0,2,16.5,15,1,8.0833333333333,0,20.08366666667,20.08366666667,20.08366666667,0,26,0,0,26,0.00033333332999064,20.08333333334,0.00,18,18,0,0,0,16.5,8.8333333333333,8.0833333333333 -,Jabbari,Shahram,Fest,Nein,Ja,2025-04-01,5.00,40.00,0.00,,20,175.2167,0,0,0,0,20,175.21666666667,21.667,173.333,1.88366666667,0.00033333332999064,1.88333333334,,0,0,0,0,0,0,0,0,0,0,18,2,16.95,0,1.88366666667,1.88366666667,1.88366666667,0,-5,0,0,-5,0.00033333332999064,1.88333333334,0.00,20,0,0,0,0,0,14.266666666667,16.95 -124,Imanian,Shahriyar,Fest,Ja,Ja,2025-03-10,5.00,40.00,0.00,20,12,104.2833,12,96,0,0,24,200.28333333333,21.667,173.333,26.95033333333,0.00033333332999064,26.95,12,0,0,1,0.083333333333333,0,0,1,8.35,0,0,10,1,8.1666666666667,0,26.95033333333,26.95033333333,26.95033333333,0,36,12,0,24,0.00033333332999064,26.95,0.00,12,12,0.083333333333333,0,8.35,0,7.6833333333333,8.1666666666667 -164,Tokhi,Shokrollah,Fest,Ja,Ja,2025-03-04,5.00,40.00,0.00,20,18,152.6,5,40,0,0,23,192.6,21.667,173.333,19.267,0.00033333332999064,19.26666666667,18,0,0,14,47.75,9,21.483333333333,0,0,2,9.3,2,1,8.6333333333333,0,19.267,19.267,19.267,0,14,5,0,9,0.00033333332999064,19.26666666667,0.00,18,18,47.75,21.483333333333,0,9.3,0.93333333333333,8.6333333333333 -210,Rahimzadeh,Siamak,Fest,Ja,Ja,2025-03-01,5.00,40.00,0.00,20,23,197.5,0,0,0,0,23,197.5,21.667,173.333,24.167,0.00033333332999064,24.16666666667,23,0,0,0,0,0,0,0,0,2,16.25,18,3,25.016666666667,0.027,24.167,24.167,24.167,0.027000000000001,39,0,0,39,0.00033333332999064,24.16666666667,0.00,23,23,0,0,0,16.25,12.233333333333,25.016666666667 -,Florescu,Silviu-Cezar,Fest,Nein,Ja,2025-10-01,5.00,40.00,0.00,,20,173.5333,0,0,0,0,20,173.53333333333,21.667,173.333,0.20033333333001,0.00033333332999064,0.20000000000002,,0,0,2,0.28333333333333,0,0,0,0,0,0,19,1,8.35,0,0.20033333333001,0.20033333333001,0.20033333333001,0,9,0,0,9,0.00033333332999064,0.20000000000002,0.00,20,0,0.28333333333333,0,0,0,12.9,8.35 -,Vafaei,Soheil,Fest,Ja,Ja,2025-04-01,5.00,40.00,0.00,,18,155.4833,3,24,1,8,22,187.48333333333,21.667,173.333,14.15033333333,0.00033333332999064,14.15,18,0,0,0,0,0,0,0,0,0,0,17,1,8.0166666666667,0,14.15033333333,14.15033333333,14.15033333333,0,-10,3,0,-13,0.00033333332999064,14.15,0.00,18,18,0,0,0,0,11.466666666667,8.0166666666667 -,Toraman,"Tolga Can",Fest,Nein,Ja,2025-09-15,5.00,40.00,0.00,20,22,183.1333,0,0,0,0,22,183.13333333333,21.667,173.333,9.80033333333,0.00033333332999064,9.8,,0,0,0,0,0,0,1,9.5,0,0,17,2,16.3,0,9.80033333333,9.80033333333,9.80033333333,0,0,0,0,0,0.00033333332999064,9.8,0.00,20,0,0,0,9.5,0,6.3666666666667,16.3 -14,Haugg,Uwe,Fest,Ja,Ja,2025-01-01,4.00,32.00,0.00,18,6,50.6167,8,64,4,32,18,146.61666666667,17.333,138.667,7.94966666667,7.94966666667,0,6,0,0,0,0,0,0,0,0,0,0,5,1,6.9666666666667,-0.2,7.94966666667,7.94966666667,7.74966666667,0,-10,8,0,-18,7.74966666667,0,0.00,5,6,0,0,0,0,3.65,6.9666666666667 -231,Shokripour,Vahid,Fest,Ja,Ja,2025-01-01,5.00,40.00,0.00,20,24,208.1167,0,0,0,0,24,208.11666666667,21.667,173.333,34.78366666667,0.00033333332999064,34.78333333334,24,0,0,0,0,0,0,1,9.5,2,16.166666666667,18,3,25.333333333333,0,34.78366666667,34.78366666667,34.78366666667,0,35,0,0,35,0.00033333332999064,34.78333333334,0.00,24,24,0,0,9.5,16.166666666667,13.116666666667,25.333333333333 -226,Konak,Zidar,Fest,Nein,Ja,2025-05-01,5.00,40.00,0.00,20,22,183.65,0,0,0,0,22,183.65,21.667,173.333,10.317,0.00033333332999064,10.31666666667,,0,0,0,0,0,0,2,18.5,1,7,0,2,16.433333333333,0,10.317,10.317,10.317,0,16,0,0,16,0.00033333332999064,10.31666666667,0.00,15,0,0,0,18.5,7,0,16.433333333333 -,,,,,,,,,,,1293,11086.0499,101,799,32,256.5,1426,12141.55,1438.687,11344.646,970.23699999999,,,,9,73,175,515.91666666667,67,159.08333333333,20,181.8,66,479.58333333333,841,91,738.55,,970.23699999999,970.23699999999,1267.0006666666,-2939.2536666667,,101,241,709,211.53366666651,1055.4670000001,0,1209,,515.91666666667,159.08333333333,181.8,479.58333333333,607.15,738.55 diff --git a/service/data-hub/business-engine/db/migrations/db.sql b/service/data-hub/business-engine/db/migrations/db.sql index 0d910c4..62c08d5 100644 --- a/service/data-hub/business-engine/db/migrations/db.sql +++ b/service/data-hub/business-engine/db/migrations/db.sql @@ -211,7 +211,8 @@ CREATE TABLE public."DyflexisEmployee" ( "contractHoursWeek" double precision NOT NULL, "contractSalaryHour" double precision NOT NULL, "contractTypeName" text, - "internalId" uuid DEFAULT gen_random_uuid() NOT NULL + "internalId" uuid DEFAULT gen_random_uuid() NOT NULL, + "contractDaysWeek" integer DEFAULT 0 NOT NULL ); @@ -591,6 +592,23 @@ CREATE TABLE public."Tour" ( ); +-- +-- Name: TourFile; Type: TABLE; Schema: public; Owner: - +-- + +CREATE TABLE public."TourFile" ( + id uuid DEFAULT gen_random_uuid() NOT NULL, + "tourId" text NOT NULL, + "ticketId" text NOT NULL, + "storagePath" text NOT NULL, + "originalFilename" text NOT NULL, + "mimeType" text NOT NULL, + "fileSizeBytes" integer NOT NULL, + "dlUploadStatus" text DEFAULT 'pending'::text NOT NULL, + "createdAt" timestamp(3) without time zone DEFAULT CURRENT_TIMESTAMP +); + + -- -- Name: TourSource; Type: TABLE; Schema: public; Owner: - -- @@ -1025,6 +1043,14 @@ ALTER TABLE ONLY public."Ticket" ADD CONSTRAINT "Ticket_pkey" PRIMARY KEY (id); +-- +-- Name: TourFile TourFile_pkey; Type: CONSTRAINT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY public."TourFile" + ADD CONSTRAINT "TourFile_pkey" PRIMARY KEY (id); + + -- -- Name: TourSource TourSource_pkey; Type: CONSTRAINT; Schema: public; Owner: - -- @@ -1104,6 +1130,13 @@ ALTER TABLE ONLY public._prisma_migrations CREATE UNIQUE INDEX "CostType_id_key" ON public."CostType" USING btree (id); +-- +-- Name: TourFile_tourId_ticketId_idx; Type: INDEX; Schema: public; Owner: - +-- + +CREATE INDEX "TourFile_tourId_ticketId_idx" ON public."TourFile" USING btree ("tourId", "ticketId"); + + -- -- Name: Tour_operationId_key; Type: INDEX; Schema: public; Owner: - -- diff --git a/service/data-hub/business-engine/db/queries/payroll.sql b/service/data-hub/business-engine/db/queries/payroll.sql index e2435cd..4318b2b 100644 --- a/service/data-hub/business-engine/db/queries/payroll.sql +++ b/service/data-hub/business-engine/db/queries/payroll.sql @@ -5,6 +5,7 @@ SELECT de.surname, de."contractStart", de."contractEnd", + de."contractDaysWeek", de."contractHoursWeek", de."contractSalaryHour", de."contractTypeName", @@ -119,6 +120,25 @@ SELECT COUNT(CASE WHEN was_punctual THEN 1 END) AS punctual_days FROM daily_comparison; +-- name: IsEmployeesDepartmentNotLeitstelle :one +SELECT COALESCE( + ( + ( + bool_or(department LIKE '%KTW%') + OR bool_or(department LIKE '%BTW%') + OR bool_or(department LIKE '%TSW%') + ) + AND + bool_and(department <> 'Leitstelle') + ), + false +)::bool as meets_requirements +FROM "PlannedTime" +WHERE + "userId"::int = @employee_id::bigint + AND "startDate" BETWEEN @start_date AND @end_date + AND department IS NOT NULL; + -- name: IsEmployeesDepartmentKTW :one SELECT COALESCE( ( @@ -152,16 +172,7 @@ WITH ToursInPeriod AS ( CASE WHEN "occupiedKm" <= 30 THEN 1.0 ELSE ROUND("occupiedKm" / 30.0) - END AS tour_value, - CASE - WHEN EXTRACT(ISODOW FROM "startDate") = 6 AND "occupiedKm" <= 30 THEN 0.5 - ELSE 0.0 - END AS weekend_bonus, - "infectionName", - CASE - WHEN "infectionName" = 'Covid-19' THEN 0.5 - ELSE 0.0 - END AS infection_bonus + END AS tour_value FROM "Tour" WHERE @@ -193,7 +204,7 @@ WITH ToursInPeriod AS ( DailyCounts AS ( SELECT day, - SUM(tour_value) + SUM(weekend_bonus) + SUM(infection_bonus) AS tour_amount + SUM(tour_value) AS tour_amount FROM ToursInPeriod GROUP BY @@ -214,4 +225,15 @@ TourenGeld AS ( ) SELECT COALESCE(tourengeld, 0.0) -FROM TourenGeld; \ No newline at end of file +FROM TourenGeld; + +-- name: ListSickdaysForEmployee :many +SELECT + "start", + "end", + "days", + locked +FROM "Sickdays" +WHERE + "employeeId" = @employee_id +ORDER BY start asc; \ No newline at end of file diff --git a/service/data-hub/business-engine/internal/database/models.go b/service/data-hub/business-engine/internal/database/models.go index 7c89df0..698bc8c 100644 --- a/service/data-hub/business-engine/internal/database/models.go +++ b/service/data-hub/business-engine/internal/database/models.go @@ -275,6 +275,7 @@ type DyflexisEmployee struct { ContractSalaryHour float64 `json:"contractSalaryHour"` ContractTypeName pgtype.Text `json:"contractTypeName"` InternalId pgtype.UUID `json:"internalId"` + ContractDaysWeek int32 `json:"contractDaysWeek"` } type Employee struct { @@ -564,6 +565,18 @@ type Tour struct { Schwerlast bool `json:"schwerlast"` } +type TourFile struct { + ID pgtype.UUID `json:"id"` + TourId string `json:"tourId"` + TicketId string `json:"ticketId"` + StoragePath string `json:"storagePath"` + OriginalFilename string `json:"originalFilename"` + MimeType string `json:"mimeType"` + FileSizeBytes int32 `json:"fileSizeBytes"` + DlUploadStatus string `json:"dlUploadStatus"` + CreatedAt *time.Time `json:"createdAt"` +} + type TourSource struct { InternalId pgtype.UUID `json:"internalId"` InsertedAt time.Time `json:"insertedAt"` diff --git a/service/data-hub/business-engine/internal/database/payroll.sql.go b/service/data-hub/business-engine/internal/database/payroll.sql.go index 2991f9f..e7856d9 100644 --- a/service/data-hub/business-engine/internal/database/payroll.sql.go +++ b/service/data-hub/business-engine/internal/database/payroll.sql.go @@ -309,6 +309,39 @@ func (q *Queries) IsEmployeesDepartmentKTW(ctx context.Context, arg IsEmployeesD return meets_requirements, err } +const isEmployeesDepartmentNotLeitstelle = `-- name: IsEmployeesDepartmentNotLeitstelle :one +SELECT COALESCE( + ( + ( + bool_or(department LIKE '%KTW%') + OR bool_or(department LIKE '%BTW%') + OR bool_or(department LIKE '%TSW%') + ) + AND + bool_and(department <> 'Leitstelle') + ), + false +)::bool as meets_requirements +FROM "PlannedTime" +WHERE + "userId"::int = $1::bigint + AND "startDate" BETWEEN $2 AND $3 + AND department IS NOT NULL +` + +type IsEmployeesDepartmentNotLeitstelleParams struct { + EmployeeID int64 `json:"employee_id"` + StartDate *time.Time `json:"start_date"` + EndDate *time.Time `json:"end_date"` +} + +func (q *Queries) IsEmployeesDepartmentNotLeitstelle(ctx context.Context, arg IsEmployeesDepartmentNotLeitstelleParams) (bool, error) { + row := q.db.QueryRow(ctx, isEmployeesDepartmentNotLeitstelle, arg.EmployeeID, arg.StartDate, arg.EndDate) + var meets_requirements bool + err := row.Scan(&meets_requirements) + return meets_requirements, err +} + const listActiveEmployees = `-- name: ListActiveEmployees :many SELECT de.id, @@ -316,6 +349,7 @@ SELECT de.surname, de."contractStart", de."contractEnd", + de."contractDaysWeek", de."contractHoursWeek", de."contractSalaryHour", de."contractTypeName", @@ -334,6 +368,7 @@ type ListActiveEmployeesRow struct { Surname string `json:"surname"` ContractStart time.Time `json:"contractStart"` ContractEnd *time.Time `json:"contractEnd"` + ContractDaysWeek int32 `json:"contractDaysWeek"` ContractHoursWeek float64 `json:"contractHoursWeek"` ContractSalaryHour float64 `json:"contractSalaryHour"` ContractTypeName pgtype.Text `json:"contractTypeName"` @@ -356,6 +391,7 @@ func (q *Queries) ListActiveEmployees(ctx context.Context) ([]ListActiveEmployee &i.Surname, &i.ContractStart, &i.ContractEnd, + &i.ContractDaysWeek, &i.ContractHoursWeek, &i.ContractSalaryHour, &i.ContractTypeName, @@ -371,3 +407,47 @@ func (q *Queries) ListActiveEmployees(ctx context.Context) ([]ListActiveEmployee } return items, nil } + +const listSickdaysForEmployee = `-- name: ListSickdaysForEmployee :many +SELECT + "start", + "end", + "days", + locked +FROM "Sickdays" +WHERE + "employeeId" = $1 +ORDER BY start asc +` + +type ListSickdaysForEmployeeRow struct { + Start time.Time `json:"start"` + End time.Time `json:"end"` + Days int32 `json:"days"` + Locked bool `json:"locked"` +} + +func (q *Queries) ListSickdaysForEmployee(ctx context.Context, employeeID int32) ([]ListSickdaysForEmployeeRow, error) { + rows, err := q.db.Query(ctx, listSickdaysForEmployee, employeeID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ListSickdaysForEmployeeRow + for rows.Next() { + var i ListSickdaysForEmployeeRow + if err := rows.Scan( + &i.Start, + &i.End, + &i.Days, + &i.Locked, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/service/data-hub/business-engine/internal/domain/domain.go b/service/data-hub/business-engine/internal/domain/domain.go index 5392b66..b729d0d 100644 --- a/service/data-hub/business-engine/internal/domain/domain.go +++ b/service/data-hub/business-engine/internal/domain/domain.go @@ -1,6 +1,7 @@ package domain import ( + "business-engine/internal/database" "time" ) @@ -9,9 +10,10 @@ type PayrollInput struct { Surname string // Vertragliche Basis - HourlyRate float64 - ContractHours int64 - DepartmentIsKtw bool + HourlyRate float64 + ContractHours int64 + DepartmentIsKtw bool + DepartmentNotLeitstelle bool // Erfasste Zeiten WorkedHours float64 @@ -21,6 +23,8 @@ type PayrollInput struct { TotalHours float64 OvertimeHours float64 + SickdaysYear []database.ListSickdaysForEmployeeRow + // Zulagen und Boni ZulageTourengeld float64 ZulagePassengerTransport int64 @@ -59,12 +63,15 @@ type PayrollStatement struct { Tourengeld float64 `json:"tourengeld" csv:"Tourengeld Anzahl"` TourengeldBonus float64 `json:"tourengeldBonus" csv:"Tourengeld-Bonus (Platz 1-3, EUR)"` GesundheitsbonusAbzug string `json:"gesundheitsbonusAbzug" csv:"Gesundheitsbonus abzuziehen? (ja/nein)"` + Gesundheitsbonus float64 `json:"gesundheitsbonus" csv:"Gesundheitsbonus"` Urlaubsgeld float64 `json:"urlaubsgeld" csv:"Urlaubsgeld (44 EUR pro tag)"` PScheinZulage float64 `json:"pScheinZulage" csv:"P-schein Zulage"` Wochenendzuschlag15 float64 `json:"wochenendzuschlag15" csv:"Wochenendzuschlag 15%"` Sonntagszuschlag50 float64 `json:"sonntagszuschlag50" csv:"Sonntagszuschlag 50%"` - Feiertagszuschlag125 float64 `json:"feiertagszuschlag125" csv:"Feiertagszuschlag 125%"` - Feiertagszuschlag150 float64 `json:"feiertagszuschlag150" csv:"Feiertagszuschlag 150%"` + Feiertagszuschlag125 float64 `json:"feiertagszuschlag125" csv:"Feiertagszuschlag 125%,omitempty"` + Feiertagszuschlag150 float64 `json:"feiertagszuschlag150" csv:"Feiertagszuschlag 150%,omitempty"` Nachtzuschlag25 float64 `json:"nachtzuschlag25" csv:"Nachtzuschlag 25%"` Nachtzuschlag40 float64 `json:"nachtzuschlag40" csv:"Nachtzuschlag 40%"` + + SickdaysYear []database.ListSickdaysForEmployeeRow `json:"-" csv:"-"` } diff --git a/service/data-hub/business-engine/internal/genpdf/generate.go b/service/data-hub/business-engine/internal/genpdf/generate.go index aa2ec7d..a5c4199 100644 --- a/service/data-hub/business-engine/internal/genpdf/generate.go +++ b/service/data-hub/business-engine/internal/genpdf/generate.go @@ -1,6 +1,7 @@ package genpdf import ( + "business-engine/internal/database" domain "business-engine/internal/domain" "fmt" "slices" @@ -77,6 +78,8 @@ func GenerateSalaryStatement(stmt domain.PayrollStatement, filename string, mont drawSummary(pdf, gesamtbetrag) + drawSickdays(pdf, stmt.SickdaysYear) + if err := pdf.OutputFileAndClose(filename); err != nil { return err } @@ -147,12 +150,12 @@ func genLineItemsFromStatement(stmt domain.PayrollStatement) []LineItem { Betrag: 14.0, }) } - if stmt.GesundheitsbonusAbzug == "" { + if stmt.Gesundheitsbonus > 0 { items = append(items, LineItem{ Lohnart: "1032", Beschreibung: "Gesundheitsbonus", Anzahl: 1, - Betrag: 200.0, + Betrag: stmt.Gesundheitsbonus, }) } @@ -295,6 +298,41 @@ func drawSummary(pdf *fpdf.Fpdf, total float64) { pdf.CellFormat(30, 8, formatCurrency(total), "T", 0, "R", false, 0, "") } +func drawSickdays(pdf *fpdf.Fpdf, sickdays []database.ListSickdaysForEmployeeRow) { + // 1. Abstand und Überschrift + pdf.Ln(10) + + pdf.SetFont("DejaVu", "B", 11) + // Kein Rahmen, Zeilenumbruch nach der Zelle + pdf.CellFormat(0, 10, "Krankmeldungen", "", 1, "L", false, 0, "") + + // 2. Fallback: Wenn keine Krankmeldungen vorhanden sind + if len(sickdays) == 0 { + pdf.SetFont("DejaVu", "", 10) + text := "- Keine Einträge vorhanden" + pdf.CellFormat(0, 6, text, "", 1, "L", false, 0, "") + pdf.Ln(5) + return + } + + // 3. Liste zeichne + pdf.SetFont("DejaVu", "", 10) + + for _, sick := range sickdays { + startStr := sick.Start.Format("02.01.2006") + endStr := sick.End.Format("02.01.2006") + + // Formatierung: "- 01.01.2023 bis 05.01.2023: 4 Tage" + text := fmt.Sprintf("- %s bis %s: %d Tage", startStr, endStr, sick.Days) + + // Zeichnen der Zeile + pdf.CellFormat(0, 6, text, "", 1, "L", false, 0, "") + } + + // Kleiner Abstand nach der Liste + pdf.Ln(5) +} + func formatFloat(f float64) string { p := message.NewPrinter(language.German) str := p.Sprintf("%.2f", f) diff --git a/service/data-hub/business-engine/internal/payroll/handler.go b/service/data-hub/business-engine/internal/payroll/handler.go index 522d762..8f18867 100644 --- a/service/data-hub/business-engine/internal/payroll/handler.go +++ b/service/data-hub/business-engine/internal/payroll/handler.go @@ -25,7 +25,7 @@ func NewEmployeeHandler(service Service, logger *slog.Logger) *EmployeeHandler { } func (h *EmployeeHandler) RunPayroll(w http.ResponseWriter, r *http.Request) { - month := time.Date(2025, time.November, 1, 0, 0, 0, 0, time.UTC) + month := time.Date(2025, time.December, 1, 0, 0, 0, 0, time.UTC) employees, err := h.service.FetchActiveEmployees(r.Context()) if err != nil { @@ -85,7 +85,7 @@ func (h *EmployeeHandler) RunPayroll(w http.ResponseWriter, r *http.Request) { } w.Header().Set("Content-Type", "application/json") - if err := json.NewEncoder(w).Encode(data); err != nil { + if err := json.NewEncoder(w).Encode(payrollStatements); err != nil { h.logger.Error("failed to encode response", "error", err) http.Error(w, "Internal Server Error", http.StatusInternalServerError) } diff --git a/service/data-hub/business-engine/internal/payroll/service.go b/service/data-hub/business-engine/internal/payroll/service.go index 3bf9493..3144576 100644 --- a/service/data-hub/business-engine/internal/payroll/service.go +++ b/service/data-hub/business-engine/internal/payroll/service.go @@ -16,8 +16,10 @@ type Repository interface { CountTourengeldAmountInPeriod(ctx context.Context, args database.CountTourengeldAmountInPeriodParams) (float64, error) GetWeeklyTimeSummaryForEmployee(ctx context.Context, args database.GetWeeklyTimeSummaryForEmployeeParams) ([]database.GetWeeklyTimeSummaryForEmployeeRow, error) EvaluatePunctualityForEmployee(ctx context.Context, args database.EvaluatePunctualityForEmployeeParams) (int64, error) + IsEmployeesDepartmentNotLeitstelle(ctx context.Context, args database.IsEmployeesDepartmentNotLeitstelleParams) (bool, error) IsEmployeesDepartmentKTW(ctx context.Context, args database.IsEmployeesDepartmentKTWParams) (bool, error) CountVerpflegungspauschale(ctx context.Context, args database.CountVerpflegungspauschaleParams) (int64, error) + ListSickdaysForEmployee(ctx context.Context, employeeId int32) ([]database.ListSickdaysForEmployeeRow, error) } type Service struct { @@ -55,8 +57,7 @@ func (s *Service) GeneratePayrollStatement(input domain.PayrollInput) domain.Pay GearbeiteteTage: float64(input.WorkedDays), Krankheitstage: float64(input.SickDays), Ueberstunden: input.OvertimeHours, - - Verpflegungspauschale: float64(input.Verpflegungspauschale), + SickdaysYear: input.SickdaysYear, Wochenendzuschlag15: input.ZuschlagSamstag, Sonntagszuschlag50: input.ZuschlagSonntag, @@ -66,10 +67,27 @@ func (s *Service) GeneratePayrollStatement(input domain.PayrollInput) domain.Pay Feiertagszuschlag150: input.ZuschlagFeiertag150, } + if input.DepartmentNotLeitstelle { + statement.Verpflegungspauschale = float64(input.Verpflegungspauschale) + } + if input.SickDays > 0 || !input.DepartmentIsKtw { statement.GesundheitsbonusAbzug = "ja" } + if input.SickDays <= 0 && input.DepartmentIsKtw { + switch { + case statement.Vertragsstunden > 173.0: + statement.Gesundheitsbonus = 200.0 + case statement.Vertragsstunden > 120: + statement.Gesundheitsbonus = 150.0 + case statement.Vertragsstunden > 100: + statement.Gesundheitsbonus = 100.0 + default: + statement.Gesundheitsbonus = 0.0 + } + } + if input.DepartmentIsKtw { statement.Urlaubsgeld = float64(input.HolidayDays) statement.PScheinZulage = float64(input.ZulagePassengerTransport) @@ -107,19 +125,30 @@ func (s *Service) LoadPayrollInput(ctx context.Context, month time.Time, employe return domain.PayrollInput{}, err } + isNotLeitstelle, err := s.isEmployeesDepartmentNotLeitstelle(ctx, month, int64(employee.ID)) + if err != nil { + s.logger.Error("could not load employee department", "error", err) + return domain.PayrollInput{}, err + } + isKtw, err := s.isEmployeesDepartmentKTW(ctx, month, int64(employee.ID)) if err != nil { s.logger.Error("could not load employee department", "error", err) return domain.PayrollInput{}, err } - s.logger.Debug("fetched department", "isKtw", isKtw) + + sickdays, err := s.loadSickdays(ctx, int64(employee.ID)) + if err != nil { + s.logger.Error("could not load sickdays of employee", "employeeId", employee.ID, "error", err) + } input := domain.PayrollInput{ - Firstname: employee.Firstname, - Surname: employee.Surname, - HourlyRate: employee.ContractSalaryHour, - ContractHours: int64(employee.ContractHoursWeek), - DepartmentIsKtw: isKtw, + Firstname: employee.Firstname, + Surname: employee.Surname, + HourlyRate: employee.ContractSalaryHour, + ContractHours: int64(employee.ContractHoursWeek), + DepartmentIsKtw: isKtw, + DepartmentNotLeitstelle: isNotLeitstelle, WorkedHours: metrics.WorkedHours, WorkedDays: int64(metrics.WorkedDays), @@ -128,6 +157,8 @@ func (s *Service) LoadPayrollInput(ctx context.Context, month time.Time, employe OvertimeHours: metrics.OvertimeHours, TotalHours: metrics.TotalHours, + SickdaysYear: sickdays, + ZulageTourengeld: tourengeld, ZulagePuenktlichkeit: punctuality, Verpflegungspauschale: verpflegungsPauschale, @@ -150,12 +181,15 @@ func (s *Service) LoadPayrollInput(ctx context.Context, month time.Time, employe input.ZuschlagVerpflegung = zuschlagData.Verpflegung14 } else { s.logger.Warn("Keine Zuschlag-Daten für Mitarbeiter gefunden", "key", compoundKey) - // (Kein Fehler, der Mitarbeiter hatte vielleicht keine Zuschläge) } return input, nil } +func (s *Service) loadSickdays(ctx context.Context, employeeId int64) ([]database.ListSickdaysForEmployeeRow, error) { + return s.repo.ListSickdaysForEmployee(ctx, int32(employeeId)) +} + func (s *Service) countVerpflegungspauschale(ctx context.Context, month time.Time, employeeId int64) (int64, error) { startOfMonth := beginningOfMonth(month) endOfMonth := endOfMonth(month) @@ -172,6 +206,22 @@ func (s *Service) countVerpflegungspauschale(ctx context.Context, month time.Tim return verpflegungsPauschale, nil } +func (s *Service) isEmployeesDepartmentNotLeitstelle(ctx context.Context, month time.Time, employeeId int64) (bool, error) { + startOfMonth := beginningOfMonth(month) + endOfMonth := endOfMonth(month) + s.logger.Info("fetching department for employee", "employeeId", employeeId, "startDate", startOfMonth, "endDate", endOfMonth) + + isNotLeitstelle, err := s.repo.IsEmployeesDepartmentNotLeitstelle(ctx, database.IsEmployeesDepartmentNotLeitstelleParams{ + StartDate: &startOfMonth, + EndDate: &endOfMonth, + EmployeeID: employeeId, + }) + if err != nil { + return false, fmt.Errorf("failed to fetch department for employee %d: %w", employeeId, err) + } + return isNotLeitstelle, nil +} + func (s *Service) isEmployeesDepartmentKTW(ctx context.Context, month time.Time, employeeId int64) (bool, error) { startOfMonth := beginningOfMonth(month) endOfMonth := endOfMonth(month) @@ -217,7 +267,13 @@ type payrollMetrics struct { func (s *Service) calculatePayrollMetrics(weeklyTimeData []domain.WeeklyTimeData, employee database.ListActiveEmployeesRow) payrollMetrics { var m payrollMetrics - employeeDailyContractHours := employee.ContractHoursWeek / 5 + employeeDailyContractHours := 0.0 + switch { + case employee.ContractDaysWeek <= 0: + employeeDailyContractHours = employee.ContractHoursWeek / 5 + default: + employeeDailyContractHours = employee.ContractHoursWeek / float64(employee.ContractDaysWeek) + } for _, week := range weeklyTimeData { m.WorkedHours += week.WorkedHours @@ -261,6 +317,7 @@ func (s *Service) getWeeklyTimeData(ctx context.Context, month time.Time, employ func (s *Service) fetchTourengeld(ctx context.Context, month time.Time, dlEmployeeId string) (float64, error) { startOfMonth := beginningOfMonth(month) endOfMonth := endOfMonth(month) + s.logger.Info("fetching tourengeld for employee", "employeeId", dlEmployeeId, "startDate", startOfMonth, "endDate", endOfMonth) tourengeld, err := s.repo.CountTourengeldAmountInPeriod(ctx, database.CountTourengeldAmountInPeriodParams{ StartDate: startOfMonth, diff --git a/service/data-hub/business-engine/payroll_statement.csv b/service/data-hub/business-engine/payroll_statement.csv deleted file mode 100644 index 7f0404d..0000000 --- a/service/data-hub/business-engine/payroll_statement.csv +++ /dev/null @@ -1,84 +0,0 @@ -Nachname;Vorname;Verpflegungspauschale;Vertr. Stundenlohn;Arbeitsstunden lt. Vertrag;Gearbeitet Stunden;Gearbeitet Tage;Pünktlichkeitsprämie anzahl;Krankheitstage x 8 Stunden;davon Überstunden;Tourengeld Anzahl;Tourengeld-Bonus (Platz 1-3;Gesundheitsbonus abzuziehen? (ja/nein);Urlaubsgeld (44 EUR pro tag);P-schein Zulage;Wochenendzuschlag 15%;Sonntagszuschlag 50%;Feiertagszuschlag 125%;Feiertagszuschlag 150%;Nachtzuschlag 25%;Nachtzuschlag 40% -Malani Karizi;Arasch;24;14.42;173.32;211.98333333333332;24;24;0;38.651333333333305;41.5;500;;0;0;24.7;0;8.25;0;2.6;0 -Saeedpour;Fouad;23;14.42;173.32;203.28333333333333;23;23;0;29.951333333333316;41;400;;0;23;25.25;26.8;9;0;4.25;0 -Sharh Ghaboos;Peyman;24;14.42;173.32;212.63333333333333;24;24;0;39.30133333333331;37;300;;0;24;16.683333333333;0;8.25;0;2.6;0 -Kalantari;Kaveh;18;14.42;173.32;159.05;18;18;0;25.717999999999996;31;0;;5;18;16.916666666667;10.25;9.9;0;4.25;0 -Ahmadpour;Amirhossein;21;14.42;173.32;193.63333333333333;21;21;0;36.30133333333331;31;0;;2;21;0;8.4666666666667;8.7833333333333;0;0;0 -Hosseini Jahed;Sajad;20;14.42;173.32;193.38333333333333;21;21;0;44.05133333333331;30;0;;3;21;0;8.4666666666667;8.7833333333333;0;0;0 -Rasul Khani;Mohammad;24;14.42;173.32;209.48333333333332;24;24;0;36.151333333333305;29.5;0;;0;24;8.0166666666667;17.45;8.25;0;2.25;0 -Moshtagh Askari;Adel;25;15.58;173.32;218.41666666666666;25;23;0;45.08466666666664;29;0;;0;25;24.95;0;18.65;0;0;0 -Rasulkhani;Hossein;23;14.42;173.32;194.86666666666667;23;22;0;21.53466666666666;28;0;;0;23;32.366666666667;9.25;9;0;10.433333333333;0 -Sajaei Khouzestani;Farid;22;14.42;173.32;197.43333333333334;22;22;0;24.101333333333322;26;0;;0;22;16.366666666667;0;17.316666666667;0;0;0 -Perez Y Waldt;Sebastian;17;14.42;173.32;181.89999999999998;22;15;0;8.567999999999962;25;0;;0;0;24.666666666667;0;8.0166666666667;0;14.1;0 -Rahimzadeh;Siamak;23;14.42;173.32;197.5;23;23;0;24.167999999999985;25;0;;0;23;25.016666666667;0;16.25;0;0;0 -Shokripour;Vahid;24;15;173.32;208.11666666666667;24;24;0;34.78466666666666;23.5;0;;0;24;25.333333333333;9.5;16.166666666667;0;0;0 -Hosseini;Seyed Hamid;18;14.42;173.32;153.41666666666666;18;18;5;20.084666666666642;23;0;ja;0;18;8.0833333333333;0;16.5;0;0;0 -Safari;Abdul Latif ;20;14.42;173.32;180.41666666666669;20;20;0;47.08466666666667;23;0;;5;20;17.35;0;16.166666666667;0;0;0 -Pourhossein;Reza;20;14.42;173.32;181.55;21;21;0;8.217999999999996;20.5;0;;0;21;8.0166666666667;0;16.316666666667;0;36.533333333333;15.016666666667 -Salehi;Iman;26;17.31;173.32;220.1;26;26;0;46.76799999999998;20;0;;0;26;8.0166666666667;18.2;16.383333333333;0;68.766666666667;13.483333333333 -Rohany Oskoee;Iman;22;16.15;173.32;190.38333333333333;22;10;0;17.05133333333331;20;0;;0;0;8.0333333333333;0;8.7333333333333;0;0;0 -Sahem;Khalid;24;14.42;173.32;204.35000000000002;24;24;0;31.018000000000008;18.5;0;;0;24;26.033333333333;0;16.833333333333;0;0;0 -Toraman;Tolga Can;20;14.42;173.32;183.13333333333333;22;19;0;9.80133333333331;18;0;;0;0;16.3;9.5;0;0;0;0 -Tokhi;Shokrollah;18;14.42;173.32;152.6;18;18;0;19.26799999999998;17;0;;5;18;8.6333333333333;0;9.3;0;47.75;21.483333333333 -Eggerstedt;Matthias;21;15.58;173.32;190.13333333333333;22;22;0;16.80133333333331;16;0;;0;22;0;0;8.6333333333333;0;0;0 -Mihailescu;Adrian Lucian;18;16.73;173.32;177.56666666666666;21;4;0;4.234666666666648;14.5;0;;0;21;24.116666666667;0;8.6333333333333;0;0;0 -Hastedt;David;11;14.93;138.656;112.31666666666666;14;11;4;5.651066666666651;14;0;ja;0;0;0;0;0;0;0;0 -Faridani Rad;Farzad;21;15;173.32;174.08333333333334;21;21;2;16.751333333333328;13.5;0;ja;0;21;0;0;16.15;0;44.5;5.6666666666667 -Tajikzadeh;Mohammad;18;16.15;173.32;152.31666666666666;18;18;0;18.984666666666648;13.5;0;;5;18;8.0833333333333;0;8.25;0;0;0 -Saki;Sara;14;15;173.32;117.63333333333333;14;14;0;32.30133333333331;13;0;;11;14;0;8.7;16.383333333333;0;35.05;0 -Imanian;Shahriyar;12;14.42;173.32;104.28333333333333;12;12;0;26.951333333333316;12.5;0;;12;12;8.1666666666667;8.35;0;0;0.083333333333333;0 -Sabahi;Mohammad;18;16.15;173.32;152.58333333333334;18;17;4;19.251333333333328;11;0;ja;1;18;0;0;16.583333333333;0;0;0 -Florescu;Silviu-Cezar;20;15;173.32;173.53333333333336;20;20;0;0.2013333333333449;10.5;0;;0;0;8.35;0;0;0;0.28333333333333;0 -Florescu;Silviu-Cezar;20;15;173.32;173.53333333333336;20;20;0;0.2013333333333449;10.5;0;;0;0;8.35;0;0;0;0.28333333333333;0 -Altner;Christian Van Manh;21;15;173.32;184.08333333333334;22;22;0;10.751333333333328;9;0;;0;22;8.0166666666667;0;7.9333333333333;0;0.2;0 -Pourhossein;Milad;14;14.42;173.32;125.61666666666665;15;15;0;8.28466666666663;8.5;0;;7;15;16.6;0;7.9333333333333;0;0;0 -Pouzesh;Esmail;24;16.15;173.32;202.08333333333334;24;24;0;28.751333333333328;7;0;;0;24;0;9.5;17.816666666667;0;70.416666666667;20.6 -Khodayaran;Hossein;12;16.15;173.32;105.30000000000001;13;13;0;11.967999999999996;7;0;;10;13;0;0;8.1333333333333;0;31;5.6666666666667 -Juyande;Masoud;22;15;173.32;182.9;22;22;0;9.56799999999999;7;0;;0;0;0;0;8.5166666666667;0;68.1;23.783333333333 -Maleki;Mohammad;3;14.44;103.992;41.11666666666667;5;1;2;-46.88253333333334;3.5;0;ja;0;5;0;0;0;0;0;0 -Saffarnajib;Majid;16;15.38;90.99300000000001;133.36666666666665;16;16;0;42.36736666666664;1;0;;0;16;0;0;0;0;0;0 -Jasarevic;Noel;12;14.42;173.32;116.63333333333333;14;0;0;-0.6986666666666892;0;0;ja;0;0;0;0;0;0;0;0 -Movafagh;Farzad ;23;12.82;173.32;202.61666666666667;23;0;1;37.28466666666666;0;0;ja;0;0;24.55;0;0;0;0;0 -Haralambous;Martin;0;12.41;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Hazrati;Kamyar;20;12.82;173.32;182.75;21;0;0;9.417999999999985;0;0;ja;0;0;16.616666666667;0;0;0;0;0 -Krüger;Julian;19;22.5;173.32;197.35;23;0;0;24.01799999999998;0;0;ja;0;0;15.116666666667;0;14.283333333333;0;0;0 -Arabnia;Mehdi;21;12.82;173.32;194.38333333333333;22;0;0;21.05133333333331;0;0;ja;0;0;15.783333333333;0;0;0;0;0 -Taghadosi;Mehdi;21;12.82;173.32;188.93333333333334;22;0;0;15.601333333333322;0;0;ja;0;0;16.6;0;6.3;0;0;0 -Jalali Wagener;Mehdi;24;12.82;173.32;204.48333333333332;24;0;0;31.151333333333305;0;0;ja;0;0;16.35;0;8.5333333333333;0;0;0 -Mazidi;Mehrdad;21;12.82;173.32;183.16666666666666;21;0;0;9.834666666666642;0;0;ja;0;0;17.033333333333;0;8.1166666666667;0;0;0 -Koell;Melanie Nadine;0;15.58;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Esmaeili Miandehi;Milad;0;12.82;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Mohamed Salah;Hussin Noureldin;21;12.82;173.32;186.58333333333334;22;0;0;13.251333333333328;0;0;ja;0;0;24.55;0;8.5166666666667;0;0;0 -Tokhi;Haroun;0;14.42;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Feilbach;Raoul Nikolai ;24;19.62;173.32;215.88333333333335;24;0;0;42.55133333333334;0;0;ja;0;0;0;8.7;17.483333333333;0;55.5;40.75 -Hashimazada;Firuz;18;12.82;173.32;155.35;18;0;4;14.01799999999998;0;0;ja;0;0;0;0;8.5333333333333;0;0;0 -Esser;Detlef;0;12;121.32400000000001;0;0;0;0;-121.3324;0;0;ja;0;0;0;0;0;0;0;0 -Atrafi;Mohammad Nasir;17;12.82;17.332;162.96666666666667;19;0;0;145.63346666666666;0;0;ja;0;0;22.5;0;0;0;0;0 -Amiri;Mohammad Samir;20;19.62;173.32;190.14999999999998;22;0;0;16.817999999999962;0;0;ja;0;0;12.316666666667;10.166666666667;0;0;17.25;12.633333333333 -Babaei Dezghi;Mojtaba;0;15;160.321;0;0;0;0;-162.49875;0;0;ja;0;0;0;0;0;0;0;0 -Aydin;Muhammet Ali;0;14.51;73.661;0;0;0;0;-73.6661;0;0;ja;0;0;0;0;0;0;0;0 -El Moustaiqid;Najlae;9;12.82;173.32;151.7;20;0;0;-5.632000000000026;0;0;ja;0;0;0;0;0;0;0;0 -Heucke;Niklas;0;15;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Saei;Kasra;0;5.65;173.32;37.266666666666666;6;0;0;-56.06533333333335;0;0;ja;0;0;0;0;0;0;0;0 -Latza;Lelia Eleonore;0;6.35;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Karimloo;Hamidreza;0;12.82;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Hatami;Reza;20;12.82;173.32;173.9666666666667;20;0;0;0.634666666666682;0;0;ja;0;0;16.6;0;0;0;0;0 -Abdallah;Delshad;0;12.82;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Sidiqi;Sahel;0;14.42;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Golmohammadi;Davood ;20;12.82;173.32;182.2166666666667;20;0;0;8.884666666666682;0;0;ja;0;0;0;0;0;0;0;0 -Shahrasebi;David;0;0;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Lolies;Danny;17;12.82;173.32;158.9;19;0;4;18.06799999999999;0;0;ja;0;0;17.05;0;5.55;0;0;0 -Emkani;Daniel;12;22.48;108.325;118.45;14;0;0;10.117499999999993;0;0;ja;0;0;13.3;0;8.6833333333333;0;0;0 -Askarian Pour;Seyed Hosein;0;15.58;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Jabbari;Shahram;20;12.82;173.32;175.21666666666667;20;0;0;1.8846666666666536;0;0;ja;0;0;16.95;0;0;0;0;0 -Haghighivand;Danial;19;12.82;173.32;166.03333333333333;19;0;0;8.701333333333316;0;0;ja;0;0;0;0;0;0;0;0 -Alami;Shoaib;0;12.82;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Mohammadi;Danial;20;12.82;173.32;182.86666666666665;21;0;0;9.53466666666663;0;0;ja;0;0;16.616666666667;0;8.3333333333333;0;0;0 -Aba;Cuan;0;5.65;173.32;50.25;8;0;0;-75.08200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Modrau;Cara Marleen;0;14.42;173.32;0;0;0;0;-173.33200000000002;0;0;ja;0;0;0;0;0;0;0;0 -Rahmati;Behnam;20;12.82;173.32;176.04999999999998;20;0;1;11.217999999999968;0;0;ja;0;0;0;0;0;0;0;0 -Vafaei;Soheil;18;12.82;173.32;155.48333333333332;18;0;1;14.151333333333305;0;0;ja;0;0;8.0166666666667;0;0;0;0;0 -Ziaudin;Atiq;21;12.82;173.32;194.31666666666666;23;0;0;20.984666666666648;0;0;ja;0;0;15.05;0;6.4333333333333;0;0;0 -Haugg;Uwe;5;12.82;138.656;50.616666666666674;6;0;4;-4.848933333333349;0;0;ja;0;0;6.9666666666667;0;0;0;0;0 -Esmaeili Dashtbayaz;Amin;20;12.82;173.32;171.26666666666665;20;0;0;-2.0653333333333634;0;0;ja;0;0;16.083333333333;0;0;0;0;0 -Konak;Zidar;15;22.5;173.32;183.65000000000003;22;0;0;10.31800000000002;0;0;ja;0;0;16.433333333333;18.5;7;0;0;0 diff --git a/service/data-hub/data-connector/prisma/migrations/20251209163203_add_employee_workdays/migration.sql b/service/data-hub/data-connector/prisma/migrations/20251209163203_add_employee_workdays/migration.sql new file mode 100644 index 0000000..d87b2bb --- /dev/null +++ b/service/data-hub/data-connector/prisma/migrations/20251209163203_add_employee_workdays/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "DyflexisEmployee" ADD COLUMN "contractDaysWeek" INTEGER NOT NULL DEFAULT 0; diff --git a/service/data-hub/data-connector/prisma/schema.prisma b/service/data-hub/data-connector/prisma/schema.prisma index 9748e10..5f2edfb 100644 --- a/service/data-hub/data-connector/prisma/schema.prisma +++ b/service/data-hub/data-connector/prisma/schema.prisma @@ -553,6 +553,7 @@ model DyflexisEmployee { surname String contractStart DateTime contractEnd DateTime? + contractDaysWeek Int @default(0) contractHoursWeek Float contractSalaryHour Float contractTypeName String? diff --git a/service/data-hub/data-connector/src/core/database/types.ts b/service/data-hub/data-connector/src/core/database/types.ts index 4a60a31..ab4fc7b 100644 --- a/service/data-hub/data-connector/src/core/database/types.ts +++ b/service/data-hub/data-connector/src/core/database/types.ts @@ -109,6 +109,7 @@ export type DyflexisEmployee = { surname: string; contractStart: Timestamp; contractEnd: Timestamp | null; + contractDaysWeek: Generated; contractHoursWeek: number; contractSalaryHour: number; contractTypeName: string | null; diff --git a/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/dyflexis-user-access-extractors.service.ts b/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/dyflexis-user-access-extractors.service.ts index e6c06fc..f8d0b8c 100644 --- a/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/dyflexis-user-access-extractors.service.ts +++ b/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/dyflexis-user-access-extractors.service.ts @@ -1,9 +1,9 @@ import { HttpService } from '@nestjs/axios'; import { Injectable } from '@nestjs/common'; -import { SourceRepository } from './source.repository'; -import { ConfigService } from 'src/core/config/config.service'; +import { format, Interval } from 'date-fns'; import { catchError, + combineLatest, EMPTY, expand, forkJoin, @@ -12,11 +12,15 @@ import { Observable, of, reduce, - switchMap, - tap, + switchMap } from 'rxjs'; -import { format, Interval } from 'date-fns'; -import { HolidayRaw, SickDaysRaw } from './source.interface'; +import { ConfigService } from 'src/core/config/config.service'; +import { + EmployeeContractRaw, + HolidayRaw, + SickDaysRaw, +} from './source.interface'; +import { SourceRepository } from './source.repository'; interface DyflexisAuthHeader { Cookie: string; @@ -40,11 +44,72 @@ export class DyflexisUserAccessExtractorsService { ) {} loadData(): Observable { - // return this.extractSicknessDays({ - // start: new Date('2025-01-01T00:00:00.000Z'), - // end: new Date('2025-12-31T23:59:59.999Z'), - // }); - return this.extractHolidays(new Date('2025-01-01T00:00:00.000Z')); + return combineLatest([ + // this.extractWorkdays(), + // this.extractSicknessDays({ + // start: new Date('2025-01-01T00:00:00.000Z'), + // end: new Date('2025-12-31T23:59:59.999Z'), + // }), + this.extractHolidays(new Date('2025-01-01T00:00:00.000Z')), + ]); + } + + extractWorkdays(): Observable { + return this.dyflexisLogin( + this.config.dyflexisAppUsername(), + this.config.dyflexisAppPassword(), + ).pipe( + switchMap((authHeader) => + forkJoin({ + authHeader: of(authHeader), + employees: this.fetchEmployees(authHeader), + }), + ), + switchMap(({ authHeader, employees }) => + forkJoin( + employees.map((employee) => + this.fetchWorkdaysForEmployee(authHeader, employee.id), + ), + ), + ), + map((workdaysPerEmployee) => workdaysPerEmployee.flat(1)), + switchMap((workdays) => from(this.repository.createWorkdays(workdays))), + map((res) => { + return { count: Number(res.at(0).numUpdatedRows) }; + }), + ); + } + + private fetchWorkdaysForEmployee( + authHeader: DyflexisAuthHeader, + employeeId: number, + ): Observable<{ employeeId: number; daysPerWeek: number }> { + const endpoint = (employeeId: number) => + `hamburg/employees/contract/data/${employeeId}`; + + return this.http + .get<{ + contracts: EmployeeContractRaw[]; + }>(`${this.config.dyflexisAppBaseUrl()}${endpoint(employeeId)}`, { + headers: { + ...authHeader, + }, + }) + .pipe( + map((response) => + response.data.contracts + .sort( + ({ startDate: dateA }, { startDate: dateB }) => + new Date(dateB).getTime() - new Date(dateA).getTime(), + ) + .map(({ daysPerWeek }) => daysPerWeek) + .at(0), + ), + map((daysPerWeek) => ({ + employeeId, + daysPerWeek, + })), + ); } extractHolidays(year: Date): Observable { @@ -101,6 +166,9 @@ export class DyflexisUserAccessExtractorsService { return { bookDate, isLocked, isExcludedFromPayroll, employeeId }; }), ), + catchError(() => { + return [[]]; + }), ); } @@ -115,7 +183,6 @@ export class DyflexisUserAccessExtractorsService { employees: this.fetchEmployees(authHeader), }), ), - tap(({ employees }) => console.log(employees.length)), switchMap(({ authHeader, employees }) => forkJoin( employees.map((employee) => diff --git a/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.interface.ts b/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.interface.ts index fee2946..85817f5 100644 --- a/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.interface.ts +++ b/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.interface.ts @@ -67,7 +67,7 @@ export interface TourRaw { beifahrer?: string; // ID fahrerName?: string; fahrer?: string; // ID - + overRTW?: string; firmName?: string; schwerlast?: string; @@ -184,7 +184,6 @@ export interface FahrzeugItemDto { verordnungsart: string; } - export interface SickDaysRaw { startDate: string; endDate: string; @@ -198,4 +197,25 @@ export interface HolidayRaw { bookDate: string; isLocked: boolean; isExcludedFromPayroll: boolean; -} \ No newline at end of file +} + +export interface EmployeeContractRaw { + id: number; + officeId: number; + employeeId: number; + typeId: number; + serial: string; + daysPerWeek: number; + hoursPerWeek: number; + upperLimit: any; + startDate: string; + endDate: any; + salaryAmount: number; + salaryPeriod: number; + salaryType: number; + hourlySalary: number; + active: boolean; + workingPattern: any; + isSyncedWithPayroll: boolean; + lastLockDate: string; +} diff --git a/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.repository.ts b/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.repository.ts index edecad1..74ec02a 100644 --- a/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.repository.ts +++ b/service/data-hub/data-connector/src/modules/feat-etl/feat-extractors/source.repository.ts @@ -22,7 +22,7 @@ import { TourRaw, WorkTimeRaw, } from './source.interface'; -import { Kysely } from 'kysely'; +import { Kysely, sql } from 'kysely'; import { KYSELY_CLIENT_PROVIDER_TOKEN } from 'src/core/database/database.module'; import { DB } from 'src/core/database/types'; @@ -112,6 +112,23 @@ export class SourceRepository { }); } + createWorkdays(workdays: { employeeId: number; daysPerWeek: number }[]) { + const values = workdays.map( + ({ employeeId, daysPerWeek }) => + sql`(${employeeId}::int4, ${daysPerWeek}::int4)`, + ); + + return this.db + .with('v(id, days)', () => sql`(VALUES ${sql.join(values)})`) + .updateTable('DyflexisEmployee as e') + .set({ + contractDaysWeek: sql.ref('v.days'), + }) + .from('v') + .whereRef('e.id', '=', 'v.id') + .execute(); + } + createPatients( patients: PatientRaw[], jobId: string,