diff --git a/build.gradle b/build.gradle index bfdd32f..cf5d4be 100644 --- a/build.gradle +++ b/build.gradle @@ -7,7 +7,7 @@ plugins { apply plugin: 'io.spring.dependency-management' group = 'de.jottyfan' -version = '1.4.4' +version = '1.4.5' description = """timetrack""" diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java b/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java index 5fbf027..a8319cc 100644 --- a/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java +++ b/src/main/java/de/jottyfan/timetrack/modules/done/DoneController.java @@ -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"; + } } diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java b/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java index c756974..24c96c3 100644 --- a/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java +++ b/src/main/java/de/jottyfan/timetrack/modules/done/DoneRepository.java @@ -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 days) { + Integer fkLogin = jooq.select(T_LOGIN.PK).from(T_LOGIN).where(T_LOGIN.LOGIN.eq(login)).fetchOne(T_LOGIN.PK); + + List> rows = new ArrayList>(); + for(LocalDate day : days) { + rows.add(DSL.row(day, minutes, nullIfEmpty(reason), fkLogin)); + } + InsertReturningStep 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 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) diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java b/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java index 8b53bbe..25e05ea 100644 --- a/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java +++ b/src/main/java/de/jottyfan/timetrack/modules/done/DoneService.java @@ -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 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); + } } diff --git a/src/main/java/de/jottyfan/timetrack/modules/done/model/SlotRangeBean.java b/src/main/java/de/jottyfan/timetrack/modules/done/model/SlotRangeBean.java new file mode 100644 index 0000000..60a63bd --- /dev/null +++ b/src/main/java/de/jottyfan/timetrack/modules/done/model/SlotRangeBean.java @@ -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; + } +} diff --git a/src/main/resources/templates/done/list.html b/src/main/resources/templates/done/list.html index 11cf981..7575960 100644 --- a/src/main/resources/templates/done/list.html +++ b/src/main/resources/templates/done/list.html @@ -269,6 +269,13 @@ class="slot_badge_right" th:unless="${s.id}"> --:--  +
+ +
Legende diff --git a/src/main/resources/templates/done/slot/range.html b/src/main/resources/templates/done/slot/range.html new file mode 100644 index 0000000..21b5067 --- /dev/null +++ b/src/main/resources/templates/done/slot/range.html @@ -0,0 +1,59 @@ + + + +Slot aktualisieren + + + +
+
+
+
+
ab
+
+ +
+
bis
+
+ +
+
vereinbarte Arbeitszeit in Minuten
+
+ +
+
Abweichungsgrund
+
+ +
+
inklusive Samstage
+
+ +
+
inklusive Sonntage
+
+ +
+
+
+ +
+
+
+
+
+ + \ No newline at end of file