overtime calculation optimized
This commit is contained in:
@ -23,7 +23,7 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'de.jottyfan:timetrackjooq:20240103d'
|
implementation 'de.jottyfan:timetrackjooq:20240104b'
|
||||||
|
|
||||||
implementation 'org.apache.logging.log4j:log4j-api:latest.release'
|
implementation 'org.apache.logging.log4j:log4j-api:latest.release'
|
||||||
implementation 'org.apache.logging.log4j:log4j-core:latest.release'
|
implementation 'org.apache.logging.log4j:log4j-core:latest.release'
|
||||||
|
@ -8,11 +8,17 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.web.bind.annotation.*;
|
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.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||||
|
|
||||||
import de.jottyfan.timetrack.component.OAuth2Provider;
|
import de.jottyfan.timetrack.component.OAuth2Provider;
|
||||||
import de.jottyfan.timetrack.modules.CommonController;
|
import de.jottyfan.timetrack.modules.CommonController;
|
||||||
import de.jottyfan.timetrack.modules.done.model.DoneBean;
|
import de.jottyfan.timetrack.modules.done.model.DoneBean;
|
||||||
import de.jottyfan.timetrack.modules.done.model.DoneModel;
|
import de.jottyfan.timetrack.modules.done.model.DoneModel;
|
||||||
|
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
||||||
import de.jottyfan.timetrack.modules.done.model.SummaryBean;
|
import de.jottyfan.timetrack.modules.done.model.SummaryBean;
|
||||||
import de.jottyfan.timetrack.modules.profile.ProfileService;
|
import de.jottyfan.timetrack.modules.profile.ProfileService;
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
import jakarta.annotation.security.RolesAllowed;
|
||||||
@ -53,6 +59,7 @@ public class DoneController extends CommonController {
|
|||||||
model.addAttribute("doneList", list);
|
model.addAttribute("doneList", list);
|
||||||
model.addAttribute("sum", sumBean);
|
model.addAttribute("sum", sumBean);
|
||||||
model.addAttribute("daysum", doneService.getDaysum(day, username));
|
model.addAttribute("daysum", doneService.getDaysum(day, username));
|
||||||
|
model.addAttribute("overtimeBean", doneService.getOvertimeBean(username));
|
||||||
model.addAttribute("schedule", weekBean.toJson());
|
model.addAttribute("schedule", weekBean.toJson());
|
||||||
model.addAttribute("recentList", doneService.getListRecent(username, 10));
|
model.addAttribute("recentList", doneService.getListRecent(username, 10));
|
||||||
model.addAttribute("projectList", doneService.getProjects(false));
|
model.addAttribute("projectList", doneService.getProjects(false));
|
||||||
@ -64,6 +71,14 @@ public class DoneController extends CommonController {
|
|||||||
return "done/list";
|
return "done/list";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@PostMapping("/done/list")
|
||||||
|
public String getListForDate(Model model, @ModelAttribute("day") LocalDate day) {
|
||||||
|
DoneModel doneModel = new DoneModel();
|
||||||
|
doneModel.setDay(day);
|
||||||
|
return getList(model, doneModel);
|
||||||
|
}
|
||||||
|
|
||||||
@RolesAllowed("timetrack_user")
|
@RolesAllowed("timetrack_user")
|
||||||
@GetMapping("/done/abort/{day}")
|
@GetMapping("/done/abort/{day}")
|
||||||
public String abort(@PathVariable String day, Model model) {
|
public String abort(@PathVariable String day, Model model) {
|
||||||
@ -177,4 +192,12 @@ public class DoneController extends CommonController {
|
|||||||
doneService.usefavorite(id);
|
doneService.usefavorite(id);
|
||||||
return "redirect:/done/list";
|
return "redirect:/done/list";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RolesAllowed("timetrack_user")
|
||||||
|
@PostMapping(value = "/done/overtime/update")
|
||||||
|
public String upsertOvertime(@ModelAttribute("overtimeBean") OvertimeBean bean) {
|
||||||
|
String username = provider.getName();
|
||||||
|
doneService.upsertOvertime(bean, username);
|
||||||
|
return "redirect:/done/list";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,26 +1,35 @@
|
|||||||
package de.jottyfan.timetrack.modules.done;
|
package de.jottyfan.timetrack.modules.done;
|
||||||
|
|
||||||
|
import static de.jottyfan.timetrack.db.done.Tables.T_OVERTIME;
|
||||||
|
import static de.jottyfan.timetrack.db.done.Tables.T_REQUIRED_WORKTIME;
|
||||||
import static de.jottyfan.timetrack.db.done.Tables.V_DAY;
|
import static de.jottyfan.timetrack.db.done.Tables.V_DAY;
|
||||||
import static de.jottyfan.timetrack.db.profile.Tables.T_LOGIN;
|
import static de.jottyfan.timetrack.db.profile.Tables.T_LOGIN;
|
||||||
|
|
||||||
import java.sql.Time;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.time.LocalTime;
|
import java.time.LocalTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.apache.logging.log4j.Logger;
|
import org.apache.logging.log4j.Logger;
|
||||||
import org.jooq.DSLContext;
|
import org.jooq.DSLContext;
|
||||||
|
import org.jooq.DatePart;
|
||||||
import org.jooq.Field;
|
import org.jooq.Field;
|
||||||
|
import org.jooq.InsertOnDuplicateStep;
|
||||||
|
import org.jooq.Record1;
|
||||||
|
import org.jooq.Record3;
|
||||||
import org.jooq.Record5;
|
import org.jooq.Record5;
|
||||||
import org.jooq.SelectConditionStep;
|
import org.jooq.SelectConditionStep;
|
||||||
|
import org.jooq.SelectHavingStep;
|
||||||
|
import org.jooq.UpdateConditionStep;
|
||||||
import org.jooq.impl.DSL;
|
import org.jooq.impl.DSL;
|
||||||
import org.jooq.types.YearToSecond;
|
import org.jooq.types.YearToSecond;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import de.jottyfan.timetrack.db.done.tables.records.TOvertimeRecord;
|
||||||
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
|
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
|
||||||
|
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@ -62,29 +71,82 @@ public class DoneRepository {
|
|||||||
bean.setBreaks(r.get(BREAKTIME));
|
bean.setBreaks(r.get(BREAKTIME));
|
||||||
YearToSecond dayOvertime = r.get(V_DAY.DAY_OVERTIME);
|
YearToSecond dayOvertime = r.get(V_DAY.DAY_OVERTIME);
|
||||||
Duration dayOvertimeDuration = dayOvertime == null ? null : dayOvertime.toDuration();
|
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(dayOvertimeDuration == null ? null : Long.valueOf(dayOvertimeDuration.toMinutes()).intValue());
|
||||||
bean.setDayOvertime(dayOvertimeString == null ? "?" : dayOvertimeString);
|
|
||||||
bean.setTotalOvertime(getOvertimeOf(day, login));
|
bean.setTotalOvertime(getOvertimeOf(day, login));
|
||||||
return bean;
|
return bean;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LocalTime getOvertimeOf(LocalDate day, String login) {
|
private Integer getOvertimeOf(LocalDate day, String login) {
|
||||||
// using sql string here, because the DSL.sum function does not allow LocalTime, whilst the postgreSQL sum function does allow time calculations
|
Field<Integer> OVERTIME = DSL.field("overtime", Integer.class);
|
||||||
String sqlRaw = """
|
SelectHavingStep<Record1<Integer>> sql = jooq
|
||||||
select o.worktime_offset + sum(d.worktime - r.required) as overtime
|
// @formatter:off
|
||||||
from done.v_day d
|
.select(T_OVERTIME.OVERTIME_MINUTES.plus(DSL.sum(DSL.extract(V_DAY.WORKTIME, DatePart.MINUTE).minus(T_REQUIRED_WORKTIME.REQUIRED_MINUTES))).as(OVERTIME))
|
||||||
inner join done.t_required_worktime r on r.day = d.day and r.fk_login = d.fk_login
|
.from(V_DAY)
|
||||||
inner join done.t_overtime o on o.fk_login = d.fk_login
|
.innerJoin(T_REQUIRED_WORKTIME).on(T_REQUIRED_WORKTIME.DAY.eq(V_DAY.DAY).and(T_REQUIRED_WORKTIME.FK_LOGIN.eq(V_DAY.FK_LOGIN)))
|
||||||
inner join profile.t_login p on p.pk = d.fk_login
|
.innerJoin(T_OVERTIME).on(T_OVERTIME.FK_LOGIN.eq(V_DAY.FK_LOGIN))
|
||||||
where o.impact < d.day
|
.innerJoin(T_LOGIN).on(T_LOGIN.PK.eq(V_DAY.FK_LOGIN))
|
||||||
and d.day <= '?'
|
.where(T_OVERTIME.IMPACT.ge(V_DAY.DAY.cast(LocalDateTime.class)))
|
||||||
and p.login = '?'
|
.and(V_DAY.DAY.le(day))
|
||||||
group by d.fk_login, o.worktime_offset;
|
.and(T_LOGIN.LOGIN.eq(login))
|
||||||
""";
|
.groupBy(V_DAY.FK_LOGIN, T_OVERTIME.OVERTIME_MINUTES);
|
||||||
String sql = sqlRaw.replaceFirst("\\?", day.format(DateTimeFormatter.ISO_DATE)).replaceFirst("\\?", login);
|
// @formatter:on
|
||||||
LOGGER.trace(sql);
|
LOGGER.trace(sql);
|
||||||
Time time = (Time) jooq.fetchOne(sql).get(0);
|
return sql.fetchOne(OVERTIME);
|
||||||
return time.toLocalTime();
|
}
|
||||||
|
|
||||||
|
public OvertimeBean getOvertimeBean(String login) {
|
||||||
|
SelectConditionStep<Record3<Integer, LocalDateTime, Integer>> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.select(T_OVERTIME.PK_OVERTIME,
|
||||||
|
T_OVERTIME.IMPACT,
|
||||||
|
T_OVERTIME.OVERTIME_MINUTES)
|
||||||
|
.from(T_OVERTIME)
|
||||||
|
.innerJoin(T_LOGIN).on(T_LOGIN.PK.eq(T_OVERTIME.FK_LOGIN))
|
||||||
|
.where(T_LOGIN.LOGIN.eq(login));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.trace(sql);
|
||||||
|
Record3<Integer, LocalDateTime, Integer> r = sql.fetchOne();
|
||||||
|
OvertimeBean bean = new OvertimeBean();
|
||||||
|
if (r == null) {
|
||||||
|
bean.setImpact(LocalDate.now());
|
||||||
|
bean.setOvertimeMinutes(0);
|
||||||
|
} else {
|
||||||
|
bean.setId(r.get(T_OVERTIME.PK_OVERTIME));
|
||||||
|
bean.setImpact(r.get(T_OVERTIME.IMPACT).toLocalDate());
|
||||||
|
bean.setOvertimeMinutes(r.get(T_OVERTIME.OVERTIME_MINUTES));
|
||||||
|
}
|
||||||
|
return bean;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void upsertOvertime(Integer pkOvertime, String login, LocalDate impact, Integer overtimeMinutes) {
|
||||||
|
if (pkOvertime == null) {
|
||||||
|
InsertOnDuplicateStep<TOvertimeRecord> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.insertInto(T_OVERTIME,
|
||||||
|
T_OVERTIME.IMPACT,
|
||||||
|
T_OVERTIME.OVERTIME_MINUTES,
|
||||||
|
T_OVERTIME.FK_LOGIN)
|
||||||
|
.select(jooq
|
||||||
|
.select(DSL.val(impact == null ? null : impact.atStartOfDay()), DSL.val(overtimeMinutes), T_LOGIN.PK)
|
||||||
|
.from(T_LOGIN)
|
||||||
|
.where(T_LOGIN.LOGIN.eq(login)));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.trace(sql);
|
||||||
|
sql.execute();
|
||||||
|
}
|
||||||
|
UpdateConditionStep<TOvertimeRecord> sql = jooq
|
||||||
|
// @formatter:off
|
||||||
|
.update(T_OVERTIME)
|
||||||
|
.set(T_OVERTIME.IMPACT, impact == null ? null : impact.atStartOfDay())
|
||||||
|
.set(T_OVERTIME.OVERTIME_MINUTES, overtimeMinutes)
|
||||||
|
.where(T_OVERTIME.PK_OVERTIME.eq(pkOvertime))
|
||||||
|
.and(T_OVERTIME.FK_LOGIN.in(jooq
|
||||||
|
.select(T_LOGIN.PK)
|
||||||
|
.from(T_LOGIN)
|
||||||
|
.where(T_LOGIN.LOGIN.eq(login))));
|
||||||
|
// @formatter:on
|
||||||
|
LOGGER.trace(sql);
|
||||||
|
sql.execute();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ import de.jottyfan.timetrack.db.done.tables.records.VProjectRecord;
|
|||||||
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
|
import de.jottyfan.timetrack.modules.done.model.DaysumBean;
|
||||||
import de.jottyfan.timetrack.modules.done.model.DoneBean;
|
import de.jottyfan.timetrack.modules.done.model.DoneBean;
|
||||||
import de.jottyfan.timetrack.modules.done.model.FavoriteBean;
|
import de.jottyfan.timetrack.modules.done.model.FavoriteBean;
|
||||||
|
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
||||||
import de.jottyfan.timetrack.modules.note.NoteService;
|
import de.jottyfan.timetrack.modules.note.NoteService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -235,4 +236,12 @@ public class DoneService {
|
|||||||
public DaysumBean getDaysum(LocalDate day, String login) {
|
public DaysumBean getDaysum(LocalDate day, String login) {
|
||||||
return repository.getDaysum(day, login);
|
return repository.getDaysum(day, login);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public OvertimeBean getOvertimeBean(String login) {
|
||||||
|
return repository.getOvertimeBean(login);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void upsertOvertime(OvertimeBean bean, String username) {
|
||||||
|
repository.upsertOvertime(bean.getId(), username, bean.getImpact(), bean.getOvertimeMinutes());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,44 @@ public class DaysumBean implements Serializable {
|
|||||||
private LocalTime daytimeUntil;
|
private LocalTime daytimeUntil;
|
||||||
private LocalTime dayworktime;
|
private LocalTime dayworktime;
|
||||||
private LocalTime breaks;
|
private LocalTime breaks;
|
||||||
private String dayOvertime;
|
private Integer dayOvertime;
|
||||||
private LocalTime totalOvertime;
|
private Integer totalOvertime;
|
||||||
|
|
||||||
|
private String lz(Integer i) {
|
||||||
|
if (i < 10) {
|
||||||
|
return "0" + i;
|
||||||
|
} else {
|
||||||
|
return i.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String printTotalOvertime() {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
if (totalOvertime == null) {
|
||||||
|
buf.append("?");
|
||||||
|
} else {
|
||||||
|
Boolean isNegative = totalOvertime < 0;
|
||||||
|
buf.append(isNegative ? "-" : "");
|
||||||
|
buf.append(Math.abs(totalOvertime) / 60);
|
||||||
|
buf.append(":");
|
||||||
|
buf.append(lz(Math.abs(totalOvertime) % 60));
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String printDayOvertime() {
|
||||||
|
StringBuilder buf = new StringBuilder();
|
||||||
|
if (dayOvertime == null) {
|
||||||
|
buf.append("?");
|
||||||
|
} else {
|
||||||
|
Boolean isNegative = dayOvertime < 0;
|
||||||
|
buf.append(isNegative ? "-" : "");
|
||||||
|
buf.append(Math.abs(dayOvertime) / 60);
|
||||||
|
buf.append(":");
|
||||||
|
buf.append(lz(Math.abs(dayOvertime) % 60));
|
||||||
|
}
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the daytimeFrom
|
* @return the daytimeFrom
|
||||||
@ -77,28 +113,28 @@ public class DaysumBean implements Serializable {
|
|||||||
/**
|
/**
|
||||||
* @return the dayOvertime
|
* @return the dayOvertime
|
||||||
*/
|
*/
|
||||||
public String getDayOvertime() {
|
public Integer getDayOvertime() {
|
||||||
return dayOvertime;
|
return dayOvertime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param dayOvertime the dayOvertime to set
|
* @param dayOvertime the dayOvertime to set
|
||||||
*/
|
*/
|
||||||
public void setDayOvertime(String dayOvertime) {
|
public void setDayOvertime(Integer dayOvertime) {
|
||||||
this.dayOvertime = dayOvertime;
|
this.dayOvertime = dayOvertime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the totalovertime
|
* @return the totalovertime
|
||||||
*/
|
*/
|
||||||
public LocalTime getTotalOvertime() {
|
public Integer getTotalOvertime() {
|
||||||
return totalOvertime;
|
return totalOvertime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param totalovertime the totalovertime to set
|
* @param totalovertime the totalovertime to set
|
||||||
*/
|
*/
|
||||||
public void setTotalOvertime(LocalTime totalOvertime) {
|
public void setTotalOvertime(Integer totalOvertime) {
|
||||||
this.totalOvertime = totalOvertime;
|
this.totalOvertime = totalOvertime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,62 @@
|
|||||||
|
package de.jottyfan.timetrack.modules.done.model;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jotty
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class OvertimeBean implements Serializable {
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
@DateTimeFormat(pattern="yyyy-MM-dd")
|
||||||
|
private LocalDate impact;
|
||||||
|
private Integer overtimeMinutes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the id
|
||||||
|
*/
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param id the id to set
|
||||||
|
*/
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the impact
|
||||||
|
*/
|
||||||
|
public LocalDate getImpact() {
|
||||||
|
return impact;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param impact the impact to set
|
||||||
|
*/
|
||||||
|
public void setImpact(LocalDate impact) {
|
||||||
|
this.impact = impact;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the overtimeMinutes
|
||||||
|
*/
|
||||||
|
public Integer getOvertimeMinutes() {
|
||||||
|
return overtimeMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param overtimeMinutes the overtimeMinutes to set
|
||||||
|
*/
|
||||||
|
public void setOvertimeMinutes(Integer overtimeMinutes) {
|
||||||
|
this.overtimeMinutes = overtimeMinutes;
|
||||||
|
}
|
||||||
|
}
|
@ -310,6 +310,15 @@ body {
|
|||||||
padding: 4px;
|
padding: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.emphpink {
|
||||||
|
font-weight: bolder;
|
||||||
|
color: #613583;
|
||||||
|
border: 1px solid gray;
|
||||||
|
border-radius: 8px;
|
||||||
|
background-image: linear-gradient(to left, #e6e6e6, white);
|
||||||
|
padding: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.tab-pane-table {
|
.tab-pane-table {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
@ -52,6 +52,8 @@
|
|||||||
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_module">Modul</a></li>
|
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_module">Modul</a></li>
|
||||||
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_job">Aufgabe</a></li>
|
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_job">Aufgabe</a></li>
|
||||||
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_billing">Abrechnung</a></li>
|
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_billing">Abrechnung</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_overtime">Überstunden</a></li>
|
||||||
|
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_slot">Slots</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="tabdivblurred tab-content">
|
<div class="tabdivblurred tab-content">
|
||||||
<div id="div_list" class="tab-pane active tab-pane-table">
|
<div id="div_list" class="tab-pane active tab-pane-table">
|
||||||
@ -104,8 +106,8 @@
|
|||||||
<td>Ende: <span class="emphgreen" th:text="${#temporals.format(daysum.daytimeUntil, 'HH:mm')}" th:if="${daysum.daytimeUntil}"></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>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>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>Überstunden heute: <span class="emphred" th:text="${daysum.printDayOvertime()}"></span></td>
|
||||||
<td colspan="2">Überstunden total: <span class="emphred" th:text="${#temporals.format(daysum.totalOvertime, 'HH:mm')}" th:if="${daysum.totalOvertime}"></span></td>
|
<td colspan="2">Überstunden total: <span class="emphpink" th:text="${daysum.printTotalOvertime()}" th:if="${daysum.totalOvertime}"></span></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td></td>
|
<td></td>
|
||||||
@ -213,6 +215,37 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="div_overtime" class="tab-pane fade tab-pane-table">
|
||||||
|
<form th:action="@{/done/overtime/update}" method="post" th:object="${overtimeBean}">
|
||||||
|
<input type="hidden" th:field="*{id}" />
|
||||||
|
<div class="container">
|
||||||
|
<div class="row g-3">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<div class="alert alert-info">Hier werden die Überstunden einmalig angegeben. Dabei wird für einen bestimmten Tagesbeginn, an dem die Überstunden bekannt sind, der Wert gesetzt. Alle
|
||||||
|
nachfolgenden Zeiten werden bei der Anzeige der Überstunden während der Datenerfassung berücksichtigt und einberechnet.</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">Tagesbeginn</div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="date" th:field="*{impact}" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3">Überstunden (min)</div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="number" th:field="*{overtimeMinutes}" class="form-control" />
|
||||||
|
</div>
|
||||||
|
<div class="col-sm-3"></div>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<button type="submit" class="btn btn-outline-primary">Übernehmen</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="div_slot" class="tab-pane fade tab-pane-table">
|
||||||
|
<div class="alert alert-info">
|
||||||
|
Zur Berechnung der täglichen Überstunden müssen Slots angelegt werden, die definieren, an welchen Tagen wieviele Stunden zu arbeiten ist.
|
||||||
|
Urlaub und Arbeitsbefreiung können durch das Entfernen des jeweiligen Slots ermöglicht werden.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
Reference in New Issue
Block a user