basic overtime calculation corrections; needs slots

This commit is contained in:
Jörg Henke
2024-01-03 17:49:26 +01:00
parent 9373eacab7
commit 48168aaf65
6 changed files with 210 additions and 29 deletions

View File

@ -7,7 +7,7 @@ plugins {
apply plugin: 'io.spring.dependency-management'
group = 'de.jottyfan'
version = '1.4.2'
version = '1.4.3'
description = """timetrack"""
@ -23,9 +23,11 @@ repositories {
}
dependencies {
implementation 'org.apache.logging.log4j:log4j-api:2.20.0'
implementation 'org.apache.logging.log4j:log4j-core:2.20.0'
implementation 'org.apache.logging.log4j:log4j-to-slf4j:2.20.0'
implementation 'de.jottyfan:timetrackjooq:20240103d'
implementation 'org.apache.logging.log4j:log4j-api:latest.release'
implementation 'org.apache.logging.log4j:log4j-core:latest.release'
implementation 'org.apache.logging.log4j:log4j-to-slf4j:latest.release'
implementation 'org.webjars:bootstrap:5.3.1'
implementation 'org.webjars:font-awesome:6.4.2'
@ -35,7 +37,7 @@ dependencies {
implementation 'org.webjars:jquery-ui:1.13.2'
implementation 'org.webjars:fullcalendar:5.11.3'
implementation 'com.google.code.gson:gson:2.10.1';
implementation 'com.google.code.gson:gson:latest.release';
implementation 'org.webjars.bowergithub.datatables:datatables:1.10.21'
@ -48,9 +50,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-devtools'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity6'
implementation 'de.jottyfan:timetrackjooq:0.1.3'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.2.1'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:latest.release'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'org.postgresql:postgresql'

View File

@ -8,13 +8,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.annotation.*;
import de.jottyfan.timetrack.component.OAuth2Provider;
import de.jottyfan.timetrack.modules.CommonController;
import de.jottyfan.timetrack.modules.done.model.DoneModel;
@ -46,17 +40,18 @@ public class DoneController extends CommonController {
}
@RolesAllowed("timetrack_user")
@RequestMapping(value = "/done/list")
@GetMapping("/done/list")
public String getList(Model model, @ModelAttribute("doneModel") DoneModel doneModel) {
String username = provider.getName();
Duration maxWorkTime = Duration.ofHours(8); // TODO: to the configuration file
LocalDate day = doneModel.getDay();
List<DoneBean> list = doneService.getList(day, username);
List<DoneBean> week = doneService.getWeek(day, username);
SummaryBean bean = new SummaryBean(list, day, maxWorkTime);
SummaryBean sumBean = new SummaryBean(list, day, maxWorkTime);
SummaryBean weekBean = new SummaryBean(week, day, maxWorkTime);
model.addAttribute("doneList", list);
model.addAttribute("sum", bean);
model.addAttribute("sum", sumBean);
model.addAttribute("daysum", doneService.getDaysum(day, username));
model.addAttribute("schedule", weekBean.toJson());
model.addAttribute("recentList", doneService.getListRecent(username, 10));
model.addAttribute("projectList", doneService.getProjects(false));
@ -75,7 +70,7 @@ public class DoneController extends CommonController {
}
@RolesAllowed("timetrack_user")
@RequestMapping(value = "/done/add/{day}", method = RequestMethod.GET)
@GetMapping("/done/add/{day}")
public String toAdd(@PathVariable @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate day, Model model) {
DoneBean bean = new DoneBean();
bean.setLocalDate(day);
@ -122,7 +117,7 @@ public class DoneController extends CommonController {
}
@RolesAllowed("timetrack_user")
@RequestMapping(value = "/done/upsert", method = RequestMethod.POST)
@PostMapping("/done/upsert")
public String doUpsert(Model model, @ModelAttribute DoneBean bean) {
String username = provider.getName();
Integer amount = doneService.doUpsert(bean, username);
@ -130,7 +125,7 @@ public class DoneController extends CommonController {
}
@RolesAllowed("timetrack_user")
@RequestMapping(value = "/done/addrecent/{id}", method = RequestMethod.GET)
@GetMapping("/done/addrecent/{id}")
public String addRecent(Model model, @PathVariable Integer id) {
String username = provider.getName();
DoneBean bean = doneService.getBean(id);
@ -139,7 +134,7 @@ public class DoneController extends CommonController {
}
@RolesAllowed("timetrack_user")
@RequestMapping(value = "/done/list/previousday", method = RequestMethod.GET)
@GetMapping("/done/list/previousday")
public String previousDay(Model model, @ModelAttribute("doneModel") DoneModel doneModel) {
LocalDate day = doneModel.getDay();
doneModel.setDay(day.minusDays(1));
@ -147,7 +142,7 @@ public class DoneController extends CommonController {
}
@RolesAllowed("timetrack_user")
@RequestMapping(value = "/done/list/nextday", method = RequestMethod.GET)
@GetMapping("/done/list/nextday")
public String nextDay(Model model, @ModelAttribute("doneModel") DoneModel doneModel) {
LocalDate day = doneModel.getDay();
doneModel.setDay(day.plusDays(1));

View File

@ -0,0 +1,72 @@
package de.jottyfan.timetrack.modules.done;
import static de.jottyfan.timetrack.db.done.Tables.V_CURRENT_OVERTIME;
import static de.jottyfan.timetrack.db.done.Tables.V_DAY;
import static de.jottyfan.timetrack.db.profile.Tables.T_LOGIN;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DSLContext;
import org.jooq.Field;
import org.jooq.Record6;
import org.jooq.SelectConditionStep;
import org.jooq.impl.DSL;
import org.jooq.types.YearToSecond;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
/**
*
* @author jotty
*
*/
@Repository
public class DoneRepository {
private static final Logger LOGGER = LogManager.getLogger(DoneRepository.class);
@Autowired
private DSLContext jooq;
public DaysumBean getDaysum(LocalDate day, String login) {
Field<LocalTime> WORKTIME = DSL.field("worktime", LocalTime.class);
Field<LocalTime> BREAKTIME = DSL.field("breaktime", LocalTime.class);
SelectConditionStep<Record6<LocalTime, LocalTime, LocalTime, LocalTime, YearToSecond, LocalTime>> sql = jooq
// @formatter:off
.select(V_DAY.STARTTIME,
V_DAY.ENDTIME,
V_DAY.WORKTIME.cast(LocalTime.class).as(WORKTIME),
V_DAY.BREAKTIME.cast(LocalTime.class).as(BREAKTIME),
V_DAY.DAY_OVERTIME,
V_CURRENT_OVERTIME.OVERTIME.plus(DSL.coalesce(V_DAY.DAY_OVERTIME, YearToSecond.valueOf(0))).as(V_CURRENT_OVERTIME.OVERTIME))
.from(V_DAY)
.innerJoin(T_LOGIN).on(T_LOGIN.PK.eq(V_DAY.FK_LOGIN))
.leftJoin(V_CURRENT_OVERTIME).on(V_CURRENT_OVERTIME.FK_LOGIN.eq(V_DAY.FK_LOGIN))
.where(V_DAY.DAY.eq(day))
.and(T_LOGIN.LOGIN.eq(login));
// @formatter:on
LOGGER.trace(sql);
Record6<LocalTime, LocalTime, LocalTime, LocalTime, YearToSecond, LocalTime> r = sql.fetchOne();
if (r == null) {
return null;
} else {
DaysumBean bean = new DaysumBean();
bean.setDaytimeFrom(r.get(V_DAY.STARTTIME));
bean.setDaytimeUntil(r.get(V_DAY.ENDTIME));
bean.setDayworktime(r.get(WORKTIME));
bean.setBreaks(r.get(BREAKTIME));
YearToSecond dayOvertime = r.get(V_DAY.DAY_OVERTIME);
Duration dayOvertimeDuration = dayOvertime == null ? null : dayOvertime.toDuration();
String dayOvertimeString = dayOvertimeDuration == null ? null : String.format("%3d:%2d", dayOvertimeDuration.toHours(), Math.abs(dayOvertimeDuration.toMinutes() % 60));
bean.setDayOvertime(dayOvertimeString == null ? "?" : dayOvertimeString);
bean.setTotalOvertime(r.get(V_CURRENT_OVERTIME.OVERTIME));
return bean;
}
}
}

View File

@ -19,6 +19,7 @@ import de.jottyfan.timetrack.db.done.tables.records.VBillingRecord;
import de.jottyfan.timetrack.db.done.tables.records.VJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.VModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.VProjectRecord;
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
import de.jottyfan.timetrack.modules.done.model.FavoriteBean;
import de.jottyfan.timetrack.modules.note.NoteService;
@ -35,6 +36,9 @@ public class DoneService {
@Autowired
private TimeService timeService;
@Autowired
private DoneRepository repository;
@Autowired
private DSLContext dsl;
@ -226,4 +230,8 @@ public class DoneService {
} catch (Exception e) {
}
}
public DaysumBean getDaysum(LocalDate day, String login) {
return repository.getDaysum(day, login);
}
}

View File

@ -0,0 +1,105 @@
package de.jottyfan.timetrack.modules.done.model;
import java.io.Serializable;
import java.time.LocalTime;
/**
*
* @author jotty
*
*/
public class DaysumBean implements Serializable {
private static final long serialVersionUID = 1L;
private LocalTime daytimeFrom;
private LocalTime daytimeUntil;
private LocalTime dayworktime;
private LocalTime breaks;
private String dayOvertime;
private LocalTime totalOvertime;
/**
* @return the daytimeFrom
*/
public LocalTime getDaytimeFrom() {
return daytimeFrom;
}
/**
* @param daytimeFrom the daytimeFrom to set
*/
public void setDaytimeFrom(LocalTime daytimeFrom) {
this.daytimeFrom = daytimeFrom;
}
/**
* @return the daytimeUntil
*/
public LocalTime getDaytimeUntil() {
return daytimeUntil;
}
/**
* @param daytimeUntil the daytimeUntil to set
*/
public void setDaytimeUntil(LocalTime daytimeUntil) {
this.daytimeUntil = daytimeUntil;
}
/**
* @return the dayworktime
*/
public LocalTime getDayworktime() {
return dayworktime;
}
/**
* @param dayworktime the dayworktime to set
*/
public void setDayworktime(LocalTime dayworktime) {
this.dayworktime = dayworktime;
}
/**
* @return the breaks
*/
public LocalTime getBreaks() {
return breaks;
}
/**
* @param breaks the breaks to set
*/
public void setBreaks(LocalTime breaks) {
this.breaks = breaks;
}
/**
* @return the dayOvertime
*/
public String getDayOvertime() {
return dayOvertime;
}
/**
* @param dayOvertime the dayOvertime to set
*/
public void setDayOvertime(String dayOvertime) {
this.dayOvertime = dayOvertime;
}
/**
* @return the totalovertime
*/
public LocalTime getTotalOvertime() {
return totalOvertime;
}
/**
* @param totalovertime the totalovertime to set
*/
public void setTotalOvertime(LocalTime totalOvertime) {
this.totalOvertime = totalOvertime;
}
}

View File

@ -99,13 +99,13 @@
</tr>
</tbody>
<tfoot>
<tr>
<td>Zusammenfassung</td>
<td>Start: <span class="emphgreen" th:text="${sum.start}"></span></td>
<td>Ende: <span class="emphgreen" th:text="${sum.end}"></span></td>
<td>Arbeitszeit total: <span class="emphblue" th:text="${sum.total}"></span></td>
<td>Pausezeit total: <span class="emphorange" th:text="${sum.pause}"></span></td>
<td colspan="2">Überstunden: <span class="emphred" th:text="${sum.overdue}"></span></td>
<tr th:if="${daysum}">
<td>Start: <span class="emphgreen" th:text="${#temporals.format(daysum.daytimeFrom, 'HH:mm')}" th:if="${daysum.daytimeFrom}"></span></td>
<td>Ende: <span class="emphgreen" th:text="${#temporals.format(daysum.daytimeUntil, 'HH:mm')}" th:if="${daysum.daytimeUntil}"></span></td>
<td>Arbeitszeit total: <span class="emphblue" th:text="${#temporals.format(daysum.dayworktime, 'HH:mm')}" th:if="${daysum.dayworktime}"></span></td>
<td>Pausezeit total: <span class="emphorange" th:text="${#temporals.format(daysum.breaks, 'HH:mm')}" th:if="${daysum.breaks}"></span></td>
<td>Überstunden heute: <span class="emphred" th:text="${daysum.dayOvertime}"></span></td>
<td colspan="2">Überstunden total: <span class="emphred" th:text="${#temporals.format(daysum.totalOvertime, 'HH:mm')}" th:if="${daysum.totalOvertime}"></span></td>
</tr>
<tr>
<td></td>