added bulk slot creation
This commit is contained in:
@ -7,7 +7,7 @@ plugins {
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
group = 'de.jottyfan'
|
||||
version = '1.4.4'
|
||||
version = '1.4.5'
|
||||
|
||||
description = """timetrack"""
|
||||
|
||||
|
@ -21,6 +21,7 @@ import de.jottyfan.timetrack.modules.done.model.DoneBean;
|
||||
import de.jottyfan.timetrack.modules.done.model.DoneModel;
|
||||
import de.jottyfan.timetrack.modules.done.model.OvertimeBean;
|
||||
import de.jottyfan.timetrack.modules.done.model.SlotBean;
|
||||
import de.jottyfan.timetrack.modules.done.model.SlotRangeBean;
|
||||
import de.jottyfan.timetrack.modules.done.model.SummaryBean;
|
||||
import jakarta.annotation.security.RolesAllowed;
|
||||
|
||||
@ -69,7 +70,7 @@ public class DoneController extends CommonController {
|
||||
model.addAttribute("favorites", doneService.getFavorites(username));
|
||||
return "done/list";
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@PostMapping("/done/list")
|
||||
public String getListForDate(Model model, @ModelAttribute("day") LocalDate day) {
|
||||
@ -168,28 +169,28 @@ public class DoneController extends CommonController {
|
||||
Integer amount = doneService.doDelete(id);
|
||||
return amount.equals(1) ? "redirect:/done/list" : "redirect:/" + toItem(id, model);
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@GetMapping(value = "/done/favorize/{id}")
|
||||
public String favorize(@PathVariable Integer id) {
|
||||
doneService.favorize(id);
|
||||
return "redirect:/done/list";
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@GetMapping(value = "/done/unfavorize/{id}")
|
||||
public String unfavorize(@PathVariable Integer id) {
|
||||
doneService.unfavorize(id);
|
||||
return "redirect:/done/list";
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@GetMapping(value = "/done/usefav/{id}")
|
||||
public String usefavorite(@PathVariable Integer id) {
|
||||
doneService.usefavorite(id);
|
||||
return "redirect:/done/list";
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@PostMapping(value = "/done/overtime/update")
|
||||
public String upsertOvertime(@ModelAttribute("overtimeBean") OvertimeBean bean) {
|
||||
@ -197,7 +198,7 @@ public class DoneController extends CommonController {
|
||||
doneService.upsertOvertime(bean, username);
|
||||
return "redirect:/done/list";
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@GetMapping("/done/slot/{id}")
|
||||
public String loadSlot(@PathVariable("id") Integer id, Model model) {
|
||||
@ -205,7 +206,7 @@ public class DoneController extends CommonController {
|
||||
model.addAttribute("bean", doneService.getSlot(id, username));
|
||||
return "/done/slot/item";
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@GetMapping("/done/slot/add")
|
||||
public String addSlot(@RequestParam("day") LocalDate day, Model model) {
|
||||
@ -219,11 +220,26 @@ public class DoneController extends CommonController {
|
||||
doneService.upsert(bean, provider.getName());
|
||||
return "redirect:/done/list";
|
||||
}
|
||||
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@GetMapping("/done/slot/{id}/delete")
|
||||
public String deleteSlot(@PathVariable("id") Integer slotId) {
|
||||
doneService.delete(slotId, provider.getName());
|
||||
return "redirect:/done/list";
|
||||
}
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@GetMapping("/done/slot/range")
|
||||
public String toAddRange(Model model) {
|
||||
model.addAttribute("bean", new SlotRangeBean());
|
||||
return "/done/slot/range";
|
||||
}
|
||||
|
||||
@RolesAllowed("timetrack_user")
|
||||
@PostMapping("/done/slot/addrange")
|
||||
public String addRange(@ModelAttribute("bean") SlotRangeBean bean) {
|
||||
doneService.addSlotRange(bean.getMinutes(), bean.getFrom(), bean.getUntil(), bean.getReason(), provider.getName(),
|
||||
bean.getIncludeSaturday(), bean.getIncludeSunday());
|
||||
return "redirect:/done/list";
|
||||
}
|
||||
}
|
||||
|
@ -9,8 +9,10 @@ import java.time.Duration;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
@ -21,10 +23,12 @@ import org.jooq.DeleteConditionStep;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.InsertOnDuplicateSetMoreStep;
|
||||
import org.jooq.InsertOnDuplicateStep;
|
||||
import org.jooq.InsertReturningStep;
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.Record3;
|
||||
import org.jooq.Record4;
|
||||
import org.jooq.Record5;
|
||||
import org.jooq.Row4;
|
||||
import org.jooq.SelectConditionStep;
|
||||
import org.jooq.SelectHavingStep;
|
||||
import org.jooq.SelectSeekStep1;
|
||||
@ -213,7 +217,34 @@ public class DoneRepository {
|
||||
: SlotBean.of(r.get(T_REQUIRED_WORKTIME.PK_REQUIRED_WORKTIME), r.get(T_REQUIRED_WORKTIME.DAY),
|
||||
r.get(T_REQUIRED_WORKTIME.REQUIRED_MINUTES), r.get(T_REQUIRED_WORKTIME.REASON));
|
||||
}
|
||||
|
||||
private String nullIfEmpty(String s) {
|
||||
return s == null ? null : (s.isBlank() ? null : s);
|
||||
}
|
||||
|
||||
public void addSlotRange(Integer minutes, String login, String reason, List<LocalDate> days) {
|
||||
Integer fkLogin = jooq.select(T_LOGIN.PK).from(T_LOGIN).where(T_LOGIN.LOGIN.eq(login)).fetchOne(T_LOGIN.PK);
|
||||
|
||||
List<Row4<LocalDate, Integer, String, Integer>> rows = new ArrayList<Row4<LocalDate,Integer,String,Integer>>();
|
||||
for(LocalDate day : days) {
|
||||
rows.add(DSL.row(day, minutes, nullIfEmpty(reason), fkLogin));
|
||||
}
|
||||
InsertReturningStep<TRequiredWorktimeRecord> sql = jooq
|
||||
// @formatter:off
|
||||
.insertInto(T_REQUIRED_WORKTIME,
|
||||
T_REQUIRED_WORKTIME.DAY,
|
||||
T_REQUIRED_WORKTIME.REQUIRED_MINUTES,
|
||||
T_REQUIRED_WORKTIME.REASON,
|
||||
T_REQUIRED_WORKTIME.FK_LOGIN)
|
||||
.valuesOfRows(rows)
|
||||
.onConflict(T_REQUIRED_WORKTIME.FK_LOGIN, T_REQUIRED_WORKTIME.DAY)
|
||||
.doUpdate()
|
||||
.setAllToExcluded();
|
||||
// @formatter:on
|
||||
LOGGER.trace(sql);
|
||||
sql.execute();
|
||||
}
|
||||
|
||||
public void addSlot(SlotBean bean, String login) {
|
||||
InsertOnDuplicateSetMoreStep<TRequiredWorktimeRecord> sql = jooq
|
||||
// @formatter:off
|
||||
@ -223,13 +254,13 @@ public class DoneRepository {
|
||||
T_REQUIRED_WORKTIME.REASON,
|
||||
T_REQUIRED_WORKTIME.FK_LOGIN)
|
||||
.select(jooq
|
||||
.select(DSL.val(bean.getDay()), DSL.val(bean.getMinutes()), DSL.val(bean.getReason()), T_LOGIN.PK)
|
||||
.select(DSL.val(bean.getDay()), DSL.val(bean.getMinutes()), DSL.val(nullIfEmpty(bean.getReason())), T_LOGIN.PK)
|
||||
.from(T_LOGIN)
|
||||
.where(T_LOGIN.LOGIN.eq(login)))
|
||||
.onConflict(T_REQUIRED_WORKTIME.FK_LOGIN, T_REQUIRED_WORKTIME.DAY)
|
||||
.doUpdate()
|
||||
.set(T_REQUIRED_WORKTIME.REQUIRED_MINUTES, bean.getMinutes())
|
||||
.set(T_REQUIRED_WORKTIME.REASON, bean.getReason());
|
||||
.set(T_REQUIRED_WORKTIME.REASON, nullIfEmpty(bean.getReason()));
|
||||
// @formatter:off
|
||||
LOGGER.trace(sql);
|
||||
sql.execute();
|
||||
@ -240,7 +271,7 @@ public class DoneRepository {
|
||||
// @formatter:off
|
||||
.update(T_REQUIRED_WORKTIME)
|
||||
.set(T_REQUIRED_WORKTIME.REQUIRED_MINUTES, bean.getMinutes())
|
||||
.set(T_REQUIRED_WORKTIME.REASON, bean.getReason())
|
||||
.set(T_REQUIRED_WORKTIME.REASON, nullIfEmpty(bean.getReason()))
|
||||
.where(T_REQUIRED_WORKTIME.PK_REQUIRED_WORKTIME.eq(bean.getId()))
|
||||
.and(T_REQUIRED_WORKTIME.FK_LOGIN.in(jooq
|
||||
.select(T_LOGIN.PK)
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.jottyfan.timetrack.modules.done;
|
||||
|
||||
import java.time.DayOfWeek;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.YearMonth;
|
||||
@ -305,4 +306,25 @@ public class DoneService {
|
||||
public void delete(Integer slotId, String username) {
|
||||
repository.deleteSlot(slotId, username);
|
||||
}
|
||||
|
||||
public void addSlotRange(Integer minutes, LocalDate from, LocalDate until, String reason, String username, Boolean includeSaturdays, Boolean includeSundays) {
|
||||
List<LocalDate> days = new ArrayList<>();
|
||||
if (!from.isBefore(until)) {
|
||||
LocalDate tmp = from;
|
||||
from = until;
|
||||
until = tmp;
|
||||
}
|
||||
includeSaturdays = includeSaturdays == null ? false : includeSaturdays;
|
||||
includeSundays = includeSundays == null ? false : includeSundays;
|
||||
for (LocalDate i = from; i.isBefore(until.plusDays(1)); i = i.plusDays(1)) {
|
||||
if (i.getDayOfWeek().equals(DayOfWeek.SUNDAY) && !includeSundays) {
|
||||
// ignore
|
||||
} else if (i.getDayOfWeek().equals(DayOfWeek.SATURDAY) && !includeSaturdays) {
|
||||
// ignore
|
||||
} else {
|
||||
days.add(i);
|
||||
}
|
||||
}
|
||||
repository.addSlotRange(minutes, username, reason, days);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,104 @@
|
||||
package de.jottyfan.timetrack.modules.done.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author jotty
|
||||
*
|
||||
*/
|
||||
public class SlotRangeBean implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Integer minutes;
|
||||
private LocalDate from;
|
||||
private LocalDate until;
|
||||
private String reason;
|
||||
private Boolean includeSaturday;
|
||||
private Boolean includeSunday;
|
||||
|
||||
/**
|
||||
* @return the minutes
|
||||
*/
|
||||
public Integer getMinutes() {
|
||||
return minutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param minutes the minutes to set
|
||||
*/
|
||||
public void setMinutes(Integer minutes) {
|
||||
this.minutes = minutes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the from
|
||||
*/
|
||||
public LocalDate getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param from the from to set
|
||||
*/
|
||||
public void setFrom(LocalDate from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the until
|
||||
*/
|
||||
public LocalDate getUntil() {
|
||||
return until;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param until the until to set
|
||||
*/
|
||||
public void setUntil(LocalDate until) {
|
||||
this.until = until;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the reason
|
||||
*/
|
||||
public String getReason() {
|
||||
return reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param reason the reason to set
|
||||
*/
|
||||
public void setReason(String reason) {
|
||||
this.reason = reason;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the includeSaturday
|
||||
*/
|
||||
public Boolean getIncludeSaturday() {
|
||||
return includeSaturday;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param includeSaturday the includeSaturday to set
|
||||
*/
|
||||
public void setIncludeSaturday(Boolean includeSaturday) {
|
||||
this.includeSaturday = includeSaturday;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the includeSunday
|
||||
*/
|
||||
public Boolean getIncludeSunday() {
|
||||
return includeSunday;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param includeSunday the includeSunday to set
|
||||
*/
|
||||
public void setIncludeSunday(Boolean includeSunday) {
|
||||
this.includeSunday = includeSunday;
|
||||
}
|
||||
}
|
@ -269,6 +269,13 @@
|
||||
class="slot_badge_right" th:unless="${s.id}"> --:-- </span>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<a th:href="@{/done/slot/range}" class="btn btn-outline-primary">mehrere Slots auf einmal anlegen</a>
|
||||
</div>
|
||||
</div>
|
||||
<br />
|
||||
<div class="row alert alert-info">
|
||||
<div class="col-sm-12">
|
||||
<span style="text-decoration: underline">Legende</span>
|
||||
|
59
src/main/resources/templates/done/slot/range.html
Normal file
59
src/main/resources/templates/done/slot/range.html
Normal file
@ -0,0 +1,59 @@
|
||||
<!DOCTYPE html>
|
||||
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security" layout:decorate="~{layout/main.html}">
|
||||
<head>
|
||||
<title>Slot aktualisieren</title>
|
||||
</head>
|
||||
<body>
|
||||
<ul layout:fragment="menu">
|
||||
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
|
||||
<a class="nav-link btn btn-outline-primary btn-white-text" th:href="@{/done/list}">zur Arbeitszeit</a>
|
||||
</li>
|
||||
</ul>
|
||||
<main layout:fragment="content">
|
||||
<div class="container formpane">
|
||||
<form th:action="@{/done/slot/addrange}" method="post" th:object="${bean}">
|
||||
<div class="row g-2" th:if="${bean}">
|
||||
<div class="col-sm-3">ab</div>
|
||||
<div class="col-sm-9">
|
||||
<input type="date" th:field="*{from}" class="form-control" />
|
||||
</div>
|
||||
<div class="col-sm-3">bis</div>
|
||||
<div class="col-sm-9">
|
||||
<input type="date" th:field="*{until}" class="form-control" />
|
||||
</div>
|
||||
<div class="col-sm-3">vereinbarte Arbeitszeit in Minuten</div>
|
||||
<div class="col-sm-9">
|
||||
<input type="number" th:field="*{minutes}" class="form-control">
|
||||
</div>
|
||||
<div class="col-sm-3">Abweichungsgrund</div>
|
||||
<div class="col-sm-9">
|
||||
<select th:field="*{reason}" class="form-select">
|
||||
<option value="">-</option>
|
||||
<option value="Ar">Arbeits- und Dienstbefreiung</option>
|
||||
<option value="Di">Dienstreise, Dienstgänge</option>
|
||||
<option value="gF">gesetzlicher Feiertag</option>
|
||||
<option value="Gl">Freistellung aus Gleitzeitguthaben</option>
|
||||
<option value="Kr">Arbeits- und Dienstunfähigkeit</option>
|
||||
<option value="mK">"mit Kind krank"</option>
|
||||
<option value="Ur">Urlaub, Sonderurlaub, Kur</option>
|
||||
<option value="Üb">Überstunden, Mehrarbeit</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="col-sm-3">inklusive Samstage</div>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" th:checked="*{includeSaturday}" name="includeSaturday" />
|
||||
</div>
|
||||
<div class="col-sm-3">inklusive Sonntage</div>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" th:checked="*{includeSunday}" name="includeSunday" />
|
||||
</div>
|
||||
<div class="col-sm-3"></div>
|
||||
<div class="col-sm-9">
|
||||
<button type="submit" class="btn btn-outline-primary">Anlegen</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user