show work times

This commit is contained in:
Jörg Henke
2022-05-05 14:52:21 +02:00
parent 59bfb266ae
commit 25b0288f3e
10 changed files with 714 additions and 266 deletions

View File

@ -1,20 +1,239 @@
package de.jottyfan.timetrack.spring.done;
import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;
import de.jottyfan.timetrack.db.done.tables.records.TBillingRecord;
import de.jottyfan.timetrack.db.done.tables.records.TDoneRecord;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
/**
*
* @author henkej
*
*/
public class DoneBean implements Serializable, Comparable<DoneBean>{
public class DoneBean implements Serializable, Comparable<DoneBean> {
private static final long serialVersionUID = 1L;
@Override
public int compareTo(DoneBean bean) {
// TODO: implement
return 0;
private static final DateTimeFormatter hhmm = DateTimeFormatter.ofPattern("HH:mm");
private Integer pk;
private LocalDateTime timeFrom;
private LocalDateTime timeUntil;
private TProjectRecord project;
private TModuleRecord module;
private TJobRecord activity;
private TBillingRecord billing;
public DoneBean() {
}
public DoneBean(TDoneRecord r, Map<Integer, TProjectRecord> projectMap, Map<Integer, TModuleRecord> moduleMap,
Map<Integer, TJobRecord> jobMap, Map<Integer, TBillingRecord> billingMap) {
this.pk = r.getPk();
this.timeFrom = r.getTimeFrom();
this.timeUntil = r.getTimeUntil();
this.project = projectMap.get(r.getFkProject());
this.module = moduleMap.get(r.getFkModule());
this.activity = jobMap.get(r.getFkJob());
this.billing = billingMap.get(r.getFkBilling());
}
@Override
public final String toString() {
StringBuilder buf = new StringBuilder("DoneBean{");
buf.append("pk=").append(pk);
buf.append(",timeFrom=").append(timeFrom == null ? "" : timeFrom.format(DateTimeFormatter.ISO_DATE_TIME));
buf.append(",timeUntil=").append(timeUntil == null ? "" : timeUntil.format(DateTimeFormatter.ISO_DATE_TIME));
buf.append(",project=").append(project == null ? "" : project.getName());
buf.append(",module=").append(module == null ? "" : module.getName());
buf.append(",activity=").append(activity == null ? "" : activity.getName());
buf.append(",billing=").append(billing == null ? "" : billing.getName());
buf.append("}");
return buf.toString();
}
/**
* set the day of timeFrom and timeUntil, keeping the times
*
* @param day the day
*/
public void setDay(Date day) {
if (timeFrom != null) {
LocalDateTime ldt = timeFrom;
LocalDate date = day.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
ldt = ldt.withYear(date.getYear()).withMonth(date.getMonthValue()).withDayOfMonth(date.getDayOfMonth());
timeFrom = ldt;
}
if (timeUntil != null) {
LocalDateTime ldt = timeUntil;
LocalDate date = day.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
ldt = ldt.withYear(date.getYear()).withMonth(date.getMonthValue()).withDayOfMonth(date.getDayOfMonth());
timeUntil = ldt;
}
}
public String getTimeSummary() {
StringBuilder buf = new StringBuilder();
if (timeFrom != null) {
buf.append(timeFrom.format(hhmm));
}
if (timeUntil != null) {
buf.append(" - ");
buf.append(timeUntil.format(hhmm));
}
return buf.toString();
}
@Override
public int compareTo(DoneBean o) {
return o == null || timeFrom == null || o.getTimeFrom() == null ? 0 : timeFrom.compareTo(o.getTimeFrom());
}
public String getTimeDiff() {
LocalDateTime earlier = timeFrom != null ? timeFrom : LocalDateTime.now();
LocalDateTime later = timeUntil != null ? timeUntil : LocalDateTime.now();
Duration diff = Duration.between(earlier, later);
return String.format("%02d:%02d", diff.toHours(), diff.toMinutes() % 60);
}
/**
* get local date time from s
*
* @param s the HH:mm formatted values
* @param ldt the date as basic for that datetime, for today one can use
* LocalDateTime.now(); in fact this is set if ldt is null internally
* @return the generated datetime
*/
public LocalDateTime getLocalDateTimeFromHHmm(String s, LocalDateTime ldt) {
if (s == null || s.trim().isEmpty()) {
return null;
} else if (ldt == null) {
ldt = LocalDateTime.now();
}
String[] hm = s.split(":");
Integer hours = 0;
Integer minutes = 0;
if (hm.length > 0) {
hours = Integer.valueOf(hm[0]);
}
if (hm.length > 1) {
minutes = Integer.valueOf(hm[1]);
}
ldt = ldt.withHour(hours);
ldt = ldt.withMinute(minutes);
ldt = ldt.withSecond(0);
ldt = ldt.withNano(0);
return ldt;
}
public String getProjectName() {
return project == null ? "" : project.getName();
}
public String getModuleName() {
return module == null ? "" : module.getName();
}
public String getJobName() {
return activity == null ? "" : activity.getName();
}
public String getBillingName() {
return billing == null ? "" : billing.getName();
}
public String getBillingShortcut() {
return billing == null ? "" : billing.getShortcut();
}
public String getBillingCsskey() {
return billing == null ? "" : billing.getCsskey();
}
public String getTimeFromString() {
return timeFrom == null ? "" : timeFrom.format(hhmm);
}
public void setTimeFromString(String s) {
this.timeFrom = getLocalDateTimeFromHHmm(s, null); // use setDay instead
}
public String getTimeUntilString() {
return timeUntil == null ? "" : timeUntil.format(hhmm);
}
public void setTimeUntilString(String s) {
this.timeUntil = getLocalDateTimeFromHHmm(s, null); // use setDay instead
}
public Integer getPk() {
return this.pk;
}
public void setPk(Integer pk) {
this.pk = pk;
}
public LocalDateTime getTimeFrom() {
return timeFrom;
}
public void setTimeFrom(LocalDateTime timeFrom) {
this.timeFrom = timeFrom;
}
public LocalDateTime getTimeUntil() {
return timeUntil;
}
public void setTimeUntil(LocalDateTime timeUntil) {
this.timeUntil = timeUntil;
}
public TProjectRecord getProject() {
return project;
}
public void setProject(TProjectRecord project) {
this.project = project;
}
public TModuleRecord getModule() {
return module;
}
public void setModule(TModuleRecord module) {
this.module = module;
}
public TJobRecord getActivity() {
return activity;
}
public void setActivity(TJobRecord activity) {
this.activity = activity;
}
/**
* @return the billing
*/
public TBillingRecord getBilling() {
return billing;
}
/**
* @param billing the billing to set
*/
public void setBilling(TBillingRecord billing) {
this.billing = billing;
}
}

View File

@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired;
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;
@ -36,9 +37,15 @@ public class DoneController {
@RolesAllowed("timetrack_user")
@RequestMapping(value = "/done/list")
public String getList(Model model) {
List<DoneBean> list = doneService.getList();
public String getList(@ModelAttribute DoneModel doneModel, Model model) {
String username = doneService.getCurrentUser(request);
List<DoneBean> list = doneService.getList(doneModel.getDay(), username);
model.addAttribute("doneList", list);
model.addAttribute("doneModel", doneModel);
model.addAttribute("projectList", doneService.getProjects());
model.addAttribute("moduleList", doneService.getModules());
model.addAttribute("jobList", doneService.getJobs());
model.addAttribute("billingList", doneService.getBillings());
return "done/list";
}

View File

@ -0,0 +1,37 @@
package de.jottyfan.timetrack.spring.done;
import java.io.Serializable;
import java.time.LocalDate;
import org.springframework.format.annotation.DateTimeFormat;
/**
*
* @author henkej
*
*/
public class DoneModel implements Serializable {
private static final long serialVersionUID = 1L;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate day;
public DoneModel() {
this.day = LocalDate.now();
}
/**
* @return the day
*/
public LocalDate getDay() {
return day;
}
/**
* @param day the day to set
*/
public void setDay(LocalDate day) {
this.day = day;
}
}

View File

@ -1,18 +1,32 @@
package de.jottyfan.timetrack.spring.done;
import java.time.LocalDate;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import de.jottyfan.timetrack.db.done.tables.records.TBillingRecord;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
/**
*
* @author henkej
*
*/
public interface IDoneService {
public List<DoneBean> getList();
public List<DoneBean> getList(LocalDate day, String username);
public DoneBean getBean(Integer id);
public String getCurrentUser(HttpServletRequest request);
public List<TProjectRecord> getProjects();
public List<TModuleRecord> getModules();
public List<TJobRecord> getJobs();
public List<TBillingRecord> getBillings();
}

View File

@ -0,0 +1,251 @@
package de.jottyfan.timetrack.spring.done.impl;
import static de.jottyfan.timetrack.db.done.Tables.T_BILLING;
import static de.jottyfan.timetrack.db.done.Tables.T_DONE;
import static de.jottyfan.timetrack.db.done.Tables.T_JOB;
import static de.jottyfan.timetrack.db.done.Tables.T_MODULE;
import static de.jottyfan.timetrack.db.done.Tables.T_PROJECT;
import static de.jottyfan.timetrack.db.profile.Tables.T_LOGIN;
import java.sql.SQLException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DSLContext;
import org.jooq.DeleteConditionStep;
import org.jooq.Record7;
import org.jooq.Result;
import org.jooq.SelectConditionStep;
import org.jooq.exception.DataAccessException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import de.jottyfan.timetrack.db.done.tables.records.TBillingRecord;
import de.jottyfan.timetrack.db.done.tables.records.TDoneRecord;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
import de.jottyfan.timetrack.db.profile.tables.records.TLoginRecord;
import de.jottyfan.timetrack.spring.done.DoneBean;
/**
*
* @author jotty
*
*/
@Repository
public class DoneGateway {
private static final Logger LOGGER = LogManager.getLogger(DoneGateway.class);
private final DSLContext jooq;
public DoneGateway(@Autowired DSLContext jooq) throws Exception {
this.jooq = jooq;
}
public DSLContext getJooq() {
return this.jooq;
}
/**
* get the user id of the user with username
*
* @param username the name of the user
* @return the ID of the user; if not found, null
*/
public Integer getUserId(String username) {
Result<TLoginRecord> r = getJooq().selectFrom(T_LOGIN).where(T_LOGIN.LOGIN.eq(username)).fetch();
return r == null || r.size() < 1 ? null : r.get(0).getPk();
}
/**
* get all projects from the database
*
* @return a list of found projects
*
* @throws DataAccessException
* @throws ClassNotFoundException
* @throws SQLException
*/
public List<TProjectRecord> getAllProjects() throws DataAccessException, ClassNotFoundException, SQLException {
return getJooq().selectFrom(T_PROJECT).fetchInto(TProjectRecord.class);
}
/**
* get all modules from the database
*
* @return a list of found modules
*
* @throws DataAccessException
* @throws ClassNotFoundException
* @throws SQLException
*/
public List<TModuleRecord> getAllModules() throws DataAccessException, ClassNotFoundException, SQLException {
return getJooq().selectFrom(T_MODULE).fetchInto(TModuleRecord.class);
}
/**
* get all jobs from the database
*
* @return a list of found jobs
*
* @throws DataAccessException
* @throws ClassNotFoundException
* @throws SQLException
*/
public List<TJobRecord> getAllJobs() throws DataAccessException, ClassNotFoundException, SQLException {
return getJooq().selectFrom(T_JOB).fetchInto(TJobRecord.class);
}
/**
* get all billings from the database
*
* @return a list of found billings
*
* @throws DataAccessException
* @throws ClassNotFoundException
* @throws SQLException
*/
public List<TBillingRecord> getAllBillings() throws DataAccessException, ClassNotFoundException, SQLException {
return getJooq().selectFrom(T_BILLING).fetchInto(TBillingRecord.class);
}
/**
* generate a project map from the database
*
* @return the project map
* @throws SQLException
* @throws ClassNotFoundException
* @throws DataAccessException
*/
private Map<Integer, TProjectRecord> getProjectMap()
throws DataAccessException, ClassNotFoundException, SQLException {
Map<Integer, TProjectRecord> map = new HashMap<>();
for (TProjectRecord r : getAllProjects()) {
map.put(r.getPk(), r);
}
return map;
}
/**
* generate a module map from the database
*
* @return the module map
* @throws SQLException
* @throws ClassNotFoundException
* @throws DataAccessException
*/
private Map<Integer, TModuleRecord> getModuleMap() throws DataAccessException, ClassNotFoundException, SQLException {
Map<Integer, TModuleRecord> map = new HashMap<>();
for (TModuleRecord r : getAllModules()) {
map.put(r.getPk(), r);
}
return map;
}
/**
* generate a job map from the database
*
* @return the job map
* @throws SQLException
* @throws ClassNotFoundException
* @throws DataAccessException
*/
private Map<Integer, TJobRecord> getJobMap() throws DataAccessException, ClassNotFoundException, SQLException {
Map<Integer, TJobRecord> map = new HashMap<>();
for (TJobRecord r : getAllJobs()) {
map.put(r.getPk(), r);
}
return map;
}
/**
* generate a billing map from the database
*
* @return the billing map
* @throws SQLException
* @throws ClassNotFoundException
* @throws DataAccessException
*/
private Map<Integer, TBillingRecord> getBillingMap()
throws DataAccessException, ClassNotFoundException, SQLException {
Map<Integer, TBillingRecord> map = new HashMap<>();
for (TBillingRecord r : getAllBillings()) {
map.put(r.getPk(), r);
}
return map;
}
/**
* get list of entries of day
*
* @param day the day
*
* @return a list (an empty one at least)
* @throws SQLException
* @throws ClassNotFoundException
* @throws DataAccessException
*/
public List<DoneBean> getAllOfDay(LocalDate day, Integer userId)
throws DataAccessException, ClassNotFoundException, SQLException {
LocalDateTime dayStart = day.atStartOfDay();
LocalDateTime dayEnd = day.atTime(23, 59, 59);
SelectConditionStep<Record7<Integer, LocalDateTime, LocalDateTime, Integer, Integer, Integer, Integer>> sql = getJooq()
// @formatter:off
.select(T_DONE.PK,
T_DONE.TIME_FROM,
T_DONE.TIME_UNTIL,
T_DONE.FK_PROJECT,
T_DONE.FK_MODULE,
T_DONE.FK_JOB,
T_DONE.FK_BILLING)
.from(T_DONE)
.where(T_DONE.TIME_FROM.between(dayStart, dayEnd))
.and(T_DONE.TIME_UNTIL.between(dayStart, dayEnd))
.and(T_DONE.FK_LOGIN.eq(userId == null ? -999999 : userId));
// @formatter:on
LOGGER.debug("{}", sql.toString());
List<DoneBean> list = new ArrayList<>();
Map<Integer, TProjectRecord> projectMap = getProjectMap();
Map<Integer, TModuleRecord> moduleMap = getModuleMap();
Map<Integer, TJobRecord> jobMap = getJobMap();
Map<Integer, TBillingRecord> billingMap = getBillingMap();
for (Record7<Integer, LocalDateTime, LocalDateTime, Integer, Integer, Integer, Integer> r : sql.fetch()) {
DoneBean bean = new DoneBean();
bean.setPk(r.get(T_DONE.PK));
bean.setTimeFrom(r.get(T_DONE.TIME_FROM));
bean.setTimeUntil(r.get(T_DONE.TIME_UNTIL));
bean.setProject(projectMap.get(r.get(T_DONE.FK_PROJECT)));
bean.setModule(moduleMap.get(r.get(T_DONE.FK_MODULE)));
bean.setActivity(jobMap.get(r.get(T_DONE.FK_JOB)));
bean.setBilling(billingMap.get(r.get(T_DONE.FK_BILLING)));
list.add(bean);
}
list.sort((o1, o2) -> o1 == null ? 0 : o1.compareTo(o2));
return list;
}
/**
* delete an entry from the database
*
* @param pk the id of the entry
* @return the number of affected database rows, should be 1
* @throws SQLException
* @throws ClassNotFoundException
* @throws DataAccessException
*/
public Integer delete(Integer pk) throws DataAccessException, ClassNotFoundException, SQLException {
DeleteConditionStep<TDoneRecord> sql = getJooq()
// @formatter:off
.deleteFrom(T_DONE)
.where(T_DONE.PK.eq(pk));
// @formatter:on
LOGGER.debug("{}", sql.toString());
return sql.execute();
}
}

View File

@ -1,5 +1,6 @@
package de.jottyfan.timetrack.spring.done.impl;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
@ -13,10 +14,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import de.jottyfan.timetrack.db.done.tables.records.TBillingRecord;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
import de.jottyfan.timetrack.spring.done.DoneBean;
import de.jottyfan.timetrack.spring.done.IDoneService;
import de.jottyfan.timetrack.spring.note.NoteBean;
import de.jottyfan.timetrack.spring.note.impl.NoteGateway;
import de.jottyfan.timetrack.spring.note.impl.NoteService;
/**
@ -34,18 +37,24 @@ public class DoneService implements IDoneService {
@Override
public String getCurrentUser(HttpServletRequest request) {
KeycloakSecurityContext ksc = (KeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
KeycloakSecurityContext ksc = (KeycloakSecurityContext) request
.getAttribute(KeycloakSecurityContext.class.getName());
return ksc == null ? "" : ksc.getIdToken().getPreferredUsername();
}
@Override
public List<DoneBean> getList() {
// try {
// return new DoneGateway(dsl).getAll();
// } catch (Exception e) {
// LOGGER.error(e);
public List<DoneBean> getList(LocalDate day, String username) {
try {
DoneGateway gw = new DoneGateway(dsl);
Integer userId = gw.getUserId(username);
if (userId == null) {
LOGGER.warn("userId of user {} is null", username);
}
return gw.getAllOfDay(day, userId);
} catch (Exception e) {
LOGGER.error(e);
return new ArrayList<>();
// }
}
}
@Override
@ -54,4 +63,44 @@ public class DoneService implements IDoneService {
return null;
}
@Override
public List<TProjectRecord> getProjects() {
try {
return new DoneGateway(dsl).getAllProjects();
} catch (Exception e) {
LOGGER.error(e);
return new ArrayList<>();
}
}
@Override
public List<TModuleRecord> getModules() {
try {
return new DoneGateway(dsl).getAllModules();
} catch (Exception e) {
LOGGER.error(e);
return new ArrayList<>();
}
}
@Override
public List<TJobRecord> getJobs() {
try {
return new DoneGateway(dsl).getAllJobs();
} catch (Exception e) {
LOGGER.error(e);
return new ArrayList<>();
}
}
@Override
public List<TBillingRecord> getBillings() {
try {
return new DoneGateway(dsl).getAllBillings();
} catch (Exception e) {
LOGGER.error(e);
return new ArrayList<>();
}
}
}

View File

@ -1,226 +0,0 @@
package de.jottyfan.timetrack.modules.done;
import java.io.Serializable;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Map;
import de.jottyfan.timetrack.db.done.tables.records.TBillingRecord;
import de.jottyfan.timetrack.db.done.tables.records.TDoneRecord;
import de.jottyfan.timetrack.db.done.tables.records.TJobRecord;
import de.jottyfan.timetrack.db.done.tables.records.TModuleRecord;
import de.jottyfan.timetrack.db.done.tables.records.TProjectRecord;
import de.jottyfan.timetrack.modules.Bean;
/**
*
* @author henkej
*
*/
public class DoneBean implements Bean, Serializable, Comparable<DoneBean> {
private static final long serialVersionUID = 1L;
private static final DateTimeFormatter hhmm = DateTimeFormatter.ofPattern("HH:mm");
private Integer pk;
private LocalDateTime timeFrom;
private LocalDateTime timeUntil;
private TProjectRecord project;
private TModuleRecord module;
private TJobRecord activity;
private TBillingRecord billing;
public DoneBean() {
}
public DoneBean(TDoneRecord r, Map<Integer, TProjectRecord> projectMap, Map<Integer, TModuleRecord> moduleMap,
Map<Integer, TJobRecord> jobMap, Map<Integer, TBillingRecord> billingMap) {
this.pk = r.getPk();
this.timeFrom = r.getTimeFrom();
this.timeUntil = r.getTimeUntil();
this.project = projectMap.get(r.getFkProject());
this.module = moduleMap.get(r.getFkModule());
this.activity = jobMap.get(r.getFkJob());
this.billing = billingMap.get(r.getFkBilling());
}
/**
* set the day of timeFrom and timeUntil, keeping the times
*
* @param day the day
*/
public void setDay(Date day) {
if (timeFrom != null) {
LocalDateTime ldt = timeFrom;
LocalDate date = day.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
ldt = ldt.withYear(date.getYear()).withMonth(date.getMonthValue()).withDayOfMonth(date.getDayOfMonth());
timeFrom = ldt;
}
if (timeUntil != null) {
LocalDateTime ldt = timeUntil;
LocalDate date = day.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
ldt = ldt.withYear(date.getYear()).withMonth(date.getMonthValue()).withDayOfMonth(date.getDayOfMonth());
timeUntil = ldt;
}
}
public String getTimeSummary() {
StringBuilder buf = new StringBuilder();
if (timeFrom != null) {
buf.append(timeFrom.format(hhmm));
}
if (timeUntil != null) {
buf.append(" - ");
buf.append(timeUntil.format(hhmm));
}
return buf.toString();
}
@Override
public int compareTo(DoneBean o) {
return o == null || timeFrom == null || o.getTimeFrom() == null ? 0 : timeFrom.compareTo(o.getTimeFrom());
}
public String getTimeDiff() {
LocalDateTime earlier = timeFrom != null ? timeFrom : LocalDateTime.now();
LocalDateTime later = timeUntil != null ? timeUntil : LocalDateTime.now();
Duration diff = Duration.between(earlier, later);
return String.format("%02d:%02d", diff.toHours(), diff.toMinutes() % 60);
}
/**
* get local date time from s
*
* @param s the HH:mm formatted values
* @param ldt the date as basic for that datetime, for today one can use
* LocalDateTime.now(); in fact this is set if ldt is null internally
* @return the generated datetime
*/
public LocalDateTime getLocalDateTimeFromHHmm(String s, LocalDateTime ldt) {
if (s == null || s.trim().isEmpty()) {
return null;
} else if (ldt == null) {
ldt = LocalDateTime.now();
}
String[] hm = s.split(":");
Integer hours = 0;
Integer minutes = 0;
if (hm.length > 0) {
hours = Integer.valueOf(hm[0]);
}
if (hm.length > 1) {
minutes = Integer.valueOf(hm[1]);
}
ldt = ldt.withHour(hours);
ldt = ldt.withMinute(minutes);
ldt = ldt.withSecond(0);
ldt = ldt.withNano(0);
return ldt;
}
public String getProjectName() {
return project == null ? "" : project.getName();
}
public String getModuleName() {
return module == null ? "" : module.getName();
}
public String getJobName() {
return activity == null ? "" : activity.getName();
}
public String getBillingName() {
return billing == null ? "" : billing.getName();
}
public String getBillingShortcut() {
return billing == null ? "" : billing.getShortcut();
}
public String getBillingCsskey() {
return billing == null ? "" : billing.getCsskey();
}
public String getTimeFromString() {
return timeFrom == null ? "" : timeFrom.format(hhmm);
}
public void setTimeFromString(String s) {
this.timeFrom = getLocalDateTimeFromHHmm(s, null); // use setDay instead
}
public String getTimeUntilString() {
return timeUntil == null ? "" : timeUntil.format(hhmm);
}
public void setTimeUntilString(String s) {
this.timeUntil = getLocalDateTimeFromHHmm(s, null); // use setDay instead
}
public Integer getPk() {
return this.pk;
}
public void setPk(Integer pk) {
this.pk = pk;
}
public LocalDateTime getTimeFrom() {
return timeFrom;
}
public void setTimeFrom(LocalDateTime timeFrom) {
this.timeFrom = timeFrom;
}
public LocalDateTime getTimeUntil() {
return timeUntil;
}
public void setTimeUntil(LocalDateTime timeUntil) {
this.timeUntil = timeUntil;
}
public TProjectRecord getProject() {
return project;
}
public void setProject(TProjectRecord project) {
this.project = project;
}
public TModuleRecord getModule() {
return module;
}
public void setModule(TModuleRecord module) {
this.module = module;
}
public TJobRecord getActivity() {
return activity;
}
public void setActivity(TJobRecord activity) {
this.activity = activity;
}
/**
* @return the billing
*/
public TBillingRecord getBilling() {
return billing;
}
/**
* @param billing the billing to set
*/
public void setBilling(TBillingRecord billing) {
this.billing = billing;
}
}

View File

@ -28,7 +28,6 @@ body {
.tabdivblurred {
padding: 8px;
padding-bottom: 0px;
background-color: rgba(255, 255, 255, 0.5);
height: calc(100% - 42px);
}
@ -109,32 +108,31 @@ body {
!important;
}
.WP2 {
.billing {
color: black !important;
background: radial-gradient(#ffff00, #ffe169) !important;
border: 1px solid darkgray;
padding-top: 8px !important;
border-radius: 16px;
padding: 4px !important;
padding-left: 8px !important;
padding-right: 8px !important;
font-weight: bolder;
font-size: smaller
}
.WP2 {
background: radial-gradient(#ffff00, #ffe169) !important;
}
.WP4 {
color: black !important;
background: radial-gradient(#00ffff, #69c3ff) !important;
border: 1px solid darkgray;
padding-top: 8px !important;
}
.WP5 {
color: black !important;
background: radial-gradient(#ff0000, #e396ff) !important;
border: 1px solid darkgray;
padding-top: 8px !important;
}
.TA3 {
color: black !important;
background: radial-gradient(#99ff99, #ccffcc) !important;
border: 1px solid darkgray;
padding-top: 8px !important;
}
.left {

View File

@ -6,6 +6,18 @@
</head>
<body>
<font layout:fragment="title">Arbeitszeit</font>
<ul layout:fragment="menuitem">
<li class="nav-item" sec:authorize="hasRole('timetrack_user')">
<form th:action="@{/done/list}" th:object="${doneModel}" method="post">
<div class="nav-link" style="padding-top: 0px !important">
<div class="input-group input-group-sm mb-3" style="margin-bottom: 0px !important">
<input type="date" class="form-control" th:value="*{day}" th:field="*{day}" />
<button type="submit" class="btn btn-primary btn-sm">Ok</button>
</div>
</div>
</form>
</li>
</ul>
<ul layout:fragment="menu">
<li class="nav-item" sec:authorize="hasRole('timetrack_user')"><a class="nav-link" th:href="@{/done/add}">Neuer
Eintrag</a></li>
@ -18,18 +30,104 @@
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_calendar">Kalender</a></li>
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_project">Projekt</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">Tätigkeit</a></li>
<li class="nav-item"><a class="nav-link navlinkstyle" data-bs-toggle="tab" href="#div_budget">Abrechnung</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>
</ul>
<div class="tabdivblurred tab-content">
<div id="div_list" class="tab-pane active">Liste</div>
<div id="div_list" class="tab-pane active" style="background-color: white">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Von</th>
<th>Bis</th>
<th>Projekt</th>
<th>Modul</th>
<th>Aufgabe</th>
<th>Abrechnung</th>
</tr>
</thead>
<tbody>
<tr th:each="done : ${doneList}">
<td><span th:text="${#temporals.format(done.timeFrom, 'HH:mm')}"></span></td>
<td><span th:text="${#temporals.format(done.timeUntil, 'HH:mm')}"></span></td>
<td><span th:text="${done.project.name}"></span></td>
<td><span th:text="${done.module.name}"></span></td>
<td><span th:text="${done.activity.name}"></span></td>
<td><span th:text="${done.billing.shortcut}" th:class="'billing ' + ${done.billing.csskey}"
th:if="${done.billing != null}"></span></td>
</tr>
</tbody>
</table>
</div>
<div id="div_summary" class="tab-pane fade">Zusammenfassung</div>
<div id="div_attachment" class="tab-pane fade">Anhang</div>
<div id="div_calendar" class="tab-pane fade">Kalender</div>
<div id="div_project" class="tab-pane fade">Projekt</div>
<div id="div_module" class="tab-pane fade">Modul</div>
<div id="div_job" class="tab-pane fade">Tätigkeit</div>
<div id="div_budget" class="tab-pane fade">Abrechnung</div>
<div id="div_project" class="tab-pane fade" style="background-color: white">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Benutzt</th>
</tr>
</thead>
<tbody>
<tr th:each="project : ${projectList}">
<td><span th:text="${project.name}"></span></td>
<td>TODO</td>
</tr>
</tbody>
</table>
</div>
<div id="div_module" class="tab-pane fade" style="background-color: white">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Benutzt</th>
</tr>
</thead>
<tbody>
<tr th:each="module : ${moduleList}">
<td><span th:text="${module.name}"></span></td>
<td>TODO</td>
</tr>
</tbody>
</table>
</div>
<div id="div_job" class="tab-pane fade" style="background-color: white">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Benutzt</th>
</tr>
</thead>
<tbody>
<tr th:each="job : ${jobList}">
<td><span th:text="${job.name}"></span></td>
<td>TODO</td>
</tr>
</tbody>
</table>
</div>
<div id="div_billing" class="tab-pane fade" style="background-color: white">
<table class="table table-striped table-condensed">
<thead>
<tr>
<th>Name</th>
<th>Symbol</th>
<th>Benutzt</th>
</tr>
</thead>
<tbody>
<tr th:each="billing : ${billingList}">
<td><span th:text="${billing.name}"></span></td>
<td><span th:text="${billing.shortcut}" th:class="'billing ' + ${billing.csskey}"></span></td>
<td>TODO</td>
</tr>
</tbody>
</table>
</div>
</div>
</main>
</body>

View File

@ -38,6 +38,7 @@
<li><a class="dropdown-item" th:href="@{/logout}">[[${currentUser}]] abmelden</a></li>
</ul></li>
<li class="nav-item"><a class="nav-link titlemod"><font layout:fragment="title"></font></a></li>
<li layout:fragment="menuitem" style="list-style-type: none"></li>
<li layout:fragment="menu" style="list-style-type: none"></li>
</ul>
</div>