added start_booking, see #14

This commit is contained in:
Jottyfan 2024-03-16 22:40:36 +01:00
parent ce819f80de
commit 03eb781a98
8 changed files with 101 additions and 43 deletions

View File

@ -8,7 +8,7 @@ plugins {
} }
group = 'de.jottyfan.camporganizer' group = 'de.jottyfan.camporganizer'
version = '0.7.6' version = '0.7.7'
description = """CampOrganizer2""" description = """CampOrganizer2"""
@ -41,12 +41,12 @@ war {
} }
dependencies { dependencies {
implementation 'org.jooq:jooq:3.19.1' implementation 'org.jooq:jooq:3.19.6'
implementation 'de.jottyfan:COJooq:2024.02.23' implementation 'de.jottyfan:COJooq:2024.03.16c'
implementation 'org.apache.logging.log4j:log4j-api:2.22.0' implementation 'org.apache.logging.log4j:log4j-api:2.23.1'
implementation 'org.apache.logging.log4j:log4j-core:2.22.0' implementation 'org.apache.logging.log4j:log4j-core:2.23.1'
implementation 'org.apache.logging.log4j:log4j-to-slf4j:2.22.0' implementation 'org.apache.logging.log4j:log4j-to-slf4j:2.23.1'
implementation 'org.webjars:bootstrap:5.3.2' implementation 'org.webjars:bootstrap:5.3.2'
implementation 'org.webjars:font-awesome:6.5.1' implementation 'org.webjars:font-awesome:6.5.1'
@ -58,8 +58,8 @@ dependencies {
implementation 'net.sf.biweekly:biweekly:0.6.7' implementation 'net.sf.biweekly:biweekly:0.6.7'
// for using the keycloak rest interface // for using the keycloak rest interface
implementation 'org.keycloak:keycloak-server-spi:23.0.3' implementation 'org.keycloak:keycloak-server-spi:24.0.1'
implementation 'org.keycloak:keycloak-admin-client:23.0.3' implementation 'org.keycloak:keycloak-admin-client:24.0.1'
implementation 'org.jboss.resteasy:resteasy-client:6.2.6.Final' implementation 'org.jboss.resteasy:resteasy-client:6.2.6.Final'
// backward compatibility until the complete registration is converted to keycloak // backward compatibility until the complete registration is converted to keycloak

View File

@ -25,7 +25,7 @@ import org.jooq.DeleteConditionStep;
import org.jooq.Field; import org.jooq.Field;
import org.jooq.InsertResultStep; import org.jooq.InsertResultStep;
import org.jooq.InsertReturningStep; import org.jooq.InsertReturningStep;
import org.jooq.InsertValuesStep15; import org.jooq.InsertValuesStep16;
import org.jooq.InsertValuesStep3; import org.jooq.InsertValuesStep3;
import org.jooq.Record4; import org.jooq.Record4;
import org.jooq.Record5; import org.jooq.Record5;
@ -435,10 +435,12 @@ public class AdminRepository {
jooq.transaction(t -> { jooq.transaction(t -> {
LocalDate arriveDate = bean.getArrive(); LocalDate arriveDate = bean.getArrive();
LocalDate departDate = bean.getDepart(); LocalDate departDate = bean.getDepart();
LocalDate startBookingDate = bean.getStartBooking();
LocalDateTime arrive = arriveDate == null ? null : arriveDate.atStartOfDay(); LocalDateTime arrive = arriveDate == null ? null : arriveDate.atStartOfDay();
LocalDateTime depart = departDate == null ? null : departDate.atStartOfDay(); LocalDateTime depart = departDate == null ? null : departDate.atStartOfDay();
LocalDateTime startBooking = startBookingDate == null ? null : startBookingDate.atStartOfDay();
if (bean.getPk() == null) { if (bean.getPk() == null) {
InsertValuesStep15<TCampRecord, LocalDateTime, String, LocalDateTime, Integer, Integer, Integer, Boolean, Integer, Integer, String, String, Integer, Integer, Integer, Integer> sql = DSL InsertValuesStep16<TCampRecord, LocalDateTime, String, LocalDateTime, Integer, Integer, Integer, Boolean, Integer, Integer, String, String, Integer, Integer, Integer, Integer, LocalDateTime> sql = DSL
.using(t) .using(t)
// @formatter:off // @formatter:off
.insertInto(T_CAMP, .insertInto(T_CAMP,
@ -456,10 +458,11 @@ public class AdminRepository {
T_CAMP.BEDS_FEMALE, T_CAMP.BEDS_FEMALE,
T_CAMP.BEDS_MALE, T_CAMP.BEDS_MALE,
T_CAMP.BLOCKED_BEDS_FEMALE, T_CAMP.BLOCKED_BEDS_FEMALE,
T_CAMP.BLOCKED_BEDS_MALE) T_CAMP.BLOCKED_BEDS_MALE,
T_CAMP.START_BOOKING)
.values(arrive, bean.getCountries(), depart, bean.getFkDocument(), bean.getFkLocation(), bean.getFkProfile(), .values(arrive, bean.getCountries(), depart, bean.getFkDocument(), bean.getFkLocation(), bean.getFkProfile(),
bean.getLockSales() != null ? bean.getLockSales() : false, bean.getMaxAge(), bean.getMinAge(), bean.getName(), bean.getPrice(), bean.getLockSales() != null ? bean.getLockSales() : false, bean.getMaxAge(), bean.getMinAge(), bean.getName(), bean.getPrice(),
bean.getBedsFemale(), bean.getBedsMale(), bean.getBlockedBedsFemale(), bean.getBlockedBedsMale()); bean.getBedsFemale(), bean.getBedsMale(), bean.getBlockedBedsFemale(), bean.getBlockedBedsMale(), startBooking);
// @formatter:on // @formatter:on
LOGGER.debug(sql.toString()); LOGGER.debug(sql.toString());
sql.execute(); sql.execute();
@ -482,6 +485,7 @@ public class AdminRepository {
.set(T_CAMP.BEDS_MALE, bean.getBedsMale()) .set(T_CAMP.BEDS_MALE, bean.getBedsMale())
.set(T_CAMP.BLOCKED_BEDS_FEMALE, bean.getBlockedBedsFemale()) .set(T_CAMP.BLOCKED_BEDS_FEMALE, bean.getBlockedBedsFemale())
.set(T_CAMP.BLOCKED_BEDS_MALE, bean.getBlockedBedsMale()) .set(T_CAMP.BLOCKED_BEDS_MALE, bean.getBlockedBedsMale())
.set(T_CAMP.START_BOOKING, startBooking)
.where(T_CAMP.PK.eq(bean.getPk())); .where(T_CAMP.PK.eq(bean.getPk()));
// @formatter:on // @formatter:on
LOGGER.debug(sql.toString()); LOGGER.debug(sql.toString());

View File

@ -57,6 +57,9 @@ public class CampBean implements Serializable {
@NotNull @NotNull
@Min(value = 0) @Min(value = 0)
private Integer blockedBedsMale; private Integer blockedBedsMale;
@NotNull
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startBooking;
/** /**
* generate a camp bean out of r * generate a camp bean out of r
@ -71,6 +74,7 @@ public class CampBean implements Serializable {
CampBean bean = new CampBean(); CampBean bean = new CampBean();
LocalDateTime arrive = r.getArrive(); LocalDateTime arrive = r.getArrive();
LocalDateTime depart = r.getDepart(); LocalDateTime depart = r.getDepart();
LocalDateTime startBooking = r.getStartBooking();
bean.setArrive(arrive == null ? null : arrive.toLocalDate()); bean.setArrive(arrive == null ? null : arrive.toLocalDate());
bean.setCountries(r.getCountries()); bean.setCountries(r.getCountries());
bean.setDepart(depart == null ? null : depart.toLocalDate()); bean.setDepart(depart == null ? null : depart.toLocalDate());
@ -87,6 +91,7 @@ public class CampBean implements Serializable {
bean.setBedsMale(r.getBedsMale()); bean.setBedsMale(r.getBedsMale());
bean.setBlockedBedsFemale(r.getBlockedBedsFemale()); bean.setBlockedBedsFemale(r.getBlockedBedsFemale());
bean.setBlockedBedsMale(r.getBlockedBedsMale()); bean.setBlockedBedsMale(r.getBlockedBedsMale());
bean.setStartBooking(startBooking == null ? null : startBooking.toLocalDate());
return bean; return bean;
} }
@ -344,4 +349,18 @@ public class CampBean implements Serializable {
public void setBlockedBedsMale(Integer blockedBedsMale) { public void setBlockedBedsMale(Integer blockedBedsMale) {
this.blockedBedsMale = blockedBedsMale; this.blockedBedsMale = blockedBedsMale;
} }
/**
* @return the startBooking
*/
public LocalDate getStartBooking() {
return startBooking;
}
/**
* @param startBooking the startBooking to set
*/
public void setStartBooking(LocalDate startBooking) {
this.startBooking = startBooking;
}
} }

View File

@ -6,6 +6,7 @@ import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSONDOCUMENT;
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE; import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILEROLE; import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILEROLE;
import static de.jottyfan.camporganizer.db.jooq.Tables.T_RSS; import static de.jottyfan.camporganizer.db.jooq.Tables.T_RSS;
import static de.jottyfan.camporganizer.db.jooq.Tables.V_CAMP;
import java.time.LocalDate; import java.time.LocalDate;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@ -42,11 +43,11 @@ import org.springframework.transaction.annotation.Transactional;
import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole; import de.jottyfan.camporganizer.db.jooq.enums.EnumCamprole;
import de.jottyfan.camporganizer.db.jooq.enums.EnumSex; import de.jottyfan.camporganizer.db.jooq.enums.EnumSex;
import de.jottyfan.camporganizer.db.jooq.tables.records.TCampRecord;
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersonRecord; import de.jottyfan.camporganizer.db.jooq.tables.records.TPersonRecord;
import de.jottyfan.camporganizer.db.jooq.tables.records.TPersondocumentRecord; import de.jottyfan.camporganizer.db.jooq.tables.records.TPersondocumentRecord;
import de.jottyfan.camporganizer.db.jooq.tables.records.TProfileRecord; import de.jottyfan.camporganizer.db.jooq.tables.records.TProfileRecord;
import de.jottyfan.camporganizer.db.jooq.tables.records.TRssRecord; import de.jottyfan.camporganizer.db.jooq.tables.records.TRssRecord;
import de.jottyfan.camporganizer.db.jooq.tables.records.VCampRecord;
import de.jottyfan.camporganizer.module.camplist.model.BookingBean; import de.jottyfan.camporganizer.module.camplist.model.BookingBean;
import de.jottyfan.camporganizer.module.camplist.model.LambdaResultWrapper; import de.jottyfan.camporganizer.module.camplist.model.LambdaResultWrapper;
import de.jottyfan.camporganizer.module.registration.model.CampBean; import de.jottyfan.camporganizer.module.registration.model.CampBean;
@ -73,15 +74,17 @@ public class RegistrationRepository {
* @return the camp bean or null * @return the camp bean or null
*/ */
public CampBean getCamp(Integer pk) { public CampBean getCamp(Integer pk) {
SelectConditionStep<TCampRecord> sql = jooq.selectFrom(T_CAMP).where(T_CAMP.PK.eq(pk)); SelectConditionStep<VCampRecord> sql = jooq.selectFrom(V_CAMP).where(V_CAMP.PK.eq(pk));
LOGGER.debug(sql.toString()); LOGGER.debug(sql.toString());
TCampRecord r = sql.fetchOne(); VCampRecord r = sql.fetchOne();
if (r != null) { if (r != null) {
CampBean bean = new CampBean(); CampBean bean = new CampBean();
bean.setPk(r.getPk()); bean.setPk(r.getPk());
bean.setName(r.getName()); bean.setName(r.getName());
LocalDateTime arrive = r.getArrive(); LocalDateTime arrive = r.getArrive();
bean.setYear(arrive == null ? null : arrive.getYear()); bean.setYear(arrive == null ? null : arrive.getYear());
bean.setBookingHasStarted(r.getBookingHasStarted());
bean.setStartBooking(r.getStartBooking());
return bean; return bean;
} else { } else {
return null; return null;

View File

@ -1,6 +1,7 @@
package de.jottyfan.camporganizer.module.registration.model; package de.jottyfan.camporganizer.module.registration.model;
import java.io.Serializable; import java.io.Serializable;
import java.time.LocalDateTime;
/** /**
* *
@ -13,6 +14,8 @@ public class CampBean implements Serializable {
private Integer pk; private Integer pk;
private String name; private String name;
private Integer year; private Integer year;
private LocalDateTime startBooking;
private Boolean bookingHasStarted;
/** /**
* @return the pk * @return the pk
@ -55,4 +58,32 @@ public class CampBean implements Serializable {
public void setYear(Integer year) { public void setYear(Integer year) {
this.year = year; this.year = year;
} }
/**
* @return the bookingHasStarted
*/
public Boolean getBookingHasStarted() {
return bookingHasStarted;
}
/**
* @param bookingHasStarted the bookingHasStarted to set
*/
public void setBookingHasStarted(Boolean bookingHasStarted) {
this.bookingHasStarted = bookingHasStarted;
}
/**
* @return the startBooking
*/
public LocalDateTime getStartBooking() {
return startBooking;
}
/**
* @param startBooking the startBooking to set
*/
public void setStartBooking(LocalDateTime startBooking) {
this.startBooking = startBooking;
}
} }

View File

@ -105,8 +105,8 @@
</div> </div>
</div> </div>
<div class="row mb-2"> <div class="row mb-2">
<label for="inputProfile" class="col-sm-2 col-form-label">Verantwortlicher</label> <label for="inputProfile" class="col-sm-2 col-form-label mb-2">Verantwortlicher</label>
<div class="col-sm-10"> <div class="col-sm-4 mb-2">
<span class="error" th:each="error : ${#fields.errors('fkProfile')}">[[${error}]]<br /></span> <select id="inputProfile" th:field="*{fkProfile}" <span class="error" th:each="error : ${#fields.errors('fkProfile')}">[[${error}]]<br /></span> <select id="inputProfile" th:field="*{fkProfile}"
th:class="${'form-select ' + (#fields.hasErrors('fkProfile') ? 'inputerror' : '')}"> th:class="${'form-select ' + (#fields.hasErrors('fkProfile') ? 'inputerror' : '')}">
<option value="">--- bitte wählen ---</option> <option value="">--- bitte wählen ---</option>
@ -118,33 +118,26 @@
}); });
</script> </script>
</div> </div>
</div> <label for="startBooking" class="col-sm-2 col-form-label mb-2">Buchungsbeginn</label>
<div class="row mb-2"> <div class="col-sm-4 mb-2">
<label for="inputBedsFemale" class="col-sm-2 col-form-label">Anzahl Betten für Mädchen</label> <span class="error" th:each="error : ${#fields.errors('startBooking')}">[[${error}]]<br /></span> <input id="startBooking" type="date" th:field="*{startBooking}"
<div class="col-sm-10"> th:class="${'form-control ' + (#fields.hasErrors('startBooking') ? 'inputerror' : '')}" />
<span class="error" th:each="error : ${#fields.errors('bedsFemale')}">[[${error}]]<br /></span> </div>
<input type="number" class="form-control" th:field="*{bedsFemale}" /> <label for="inputBedsFemale" class="col-sm-2 col-form-label mb-2">Anzahl Betten für Mädchen</label>
<div class="col-sm-4 mb-2">
<span class="error" th:each="error : ${#fields.errors('bedsFemale')}">[[${error}]]<br /></span> <input type="number" class="form-control" th:field="*{bedsFemale}" />
</div> </div>
</div>
<div class="row mb-2">
<label for="inputBedsMale" class="col-sm-2 col-form-label">Anzahl Betten für Jungen</label> <label for="inputBedsMale" class="col-sm-2 col-form-label">Anzahl Betten für Jungen</label>
<div class="col-sm-10"> <div class="col-sm-4">
<span class="error" th:each="error : ${#fields.errors('bedsMale')}">[[${error}]]<br /></span> <span class="error" th:each="error : ${#fields.errors('bedsMale')}">[[${error}]]<br /></span> <input type="number" class="form-control" th:field="*{bedsMale}" />
<input type="number" class="form-control" th:field="*{bedsMale}" />
</div> </div>
</div>
<div class="row mb-2">
<label for="inputBlockedBedsFemale" class="col-sm-2 col-form-label">Reservierte Betten für Mädchen</label> <label for="inputBlockedBedsFemale" class="col-sm-2 col-form-label">Reservierte Betten für Mädchen</label>
<div class="col-sm-10"> <div class="col-sm-4">
<span class="error" th:each="error : ${#fields.errors('blockedBedsFemale')}">[[${error}]]<br /></span> <span class="error" th:each="error : ${#fields.errors('blockedBedsFemale')}">[[${error}]]<br /></span> <input type="number" class="form-control" th:field="*{blockedBedsFemale}" />
<input type="number" class="form-control" th:field="*{blockedBedsFemale}" />
</div> </div>
</div>
<div class="row mb-2">
<label for="inputBlockedBedsMale" class="col-sm-2 col-form-label">Reservierte Betten für Jungen</label> <label for="inputBlockedBedsMale" class="col-sm-2 col-form-label">Reservierte Betten für Jungen</label>
<div class="col-sm-10"> <div class="col-sm-4">
<span class="error" th:each="error : ${#fields.errors('blockedBedsMale')}">[[${error}]]<br /></span> <span class="error" th:each="error : ${#fields.errors('blockedBedsMale')}">[[${error}]]<br /></span> <input type="number" class="form-control" th:field="*{blockedBedsMale}" />
<input type="number" class="form-control" th:field="*{blockedBedsMale}" />
</div> </div>
</div> </div>
<div class="row mb-2"> <div class="row mb-2">

View File

@ -37,7 +37,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="row g-5" th:if="${c.bedsFemale + c.bedsMale > 0}"> <div class="row g-5" th:if="${c.bedsFemale + c.bedsMale > 0 and c.bookingHasStarted}">
<div class="col-2"><img th:src="@{/images/Icon_Bett.svg}" width="48px" height="48px" /></div> <div class="col-2"><img th:src="@{/images/Icon_Bett.svg}" width="48px" height="48px" /></div>
<div class="col-10 d-flex align-items-center" th:text="${'es sind nur noch ' + (c.bedsFemale - c.blockedBedsFemale - c.usedBedsFemale) + ' Mädchen- und ' + (c.bedsMale - c.blockedBedsMale - c.usedBedsMale) + ' Jungs- von ' + (c.bedsFemale + c.bedsMale) + ' Betten frei'}"></div> <div class="col-10 d-flex align-items-center" th:text="${'es sind nur noch ' + (c.bedsFemale - c.blockedBedsFemale - c.usedBedsFemale) + ' Mädchen- und ' + (c.bedsMale - c.blockedBedsMale - c.usedBedsMale) + ' Jungs- von ' + (c.bedsFemale + c.bedsMale) + ' Betten frei'}"></div>
<div class="col-12 alert alert-info alert-dismissible fade show" role="alert"> <div class="col-12 alert alert-info alert-dismissible fade show" role="alert">
@ -45,8 +45,13 @@
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Schließen"></button> <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Schließen"></button>
</div> </div>
</div> </div>
<div class="row g-5" th:unless="${c.bookingHasStarted}">
<div class="col-12 alert alert-info" role="alert">
Die Anmeldung wird erst am <span th:text="${#temporals.format(c.startBooking, 'dd.MM.yyyy')}"></span> freigeschaltet.
</div>
</div>
</div> </div>
<div style="text-align: center; margin-top: 48px"> <div style="text-align: center; margin-top: 48px" th:if="${c.bookingHasStarted}">
<a class="btn btn-linda buttonfont" th:href="@{/registration/{id}(id=${c.pk})}">jetzt anmelden</a> <a class="btn btn-linda buttonfont" th:href="@{/registration/{id}(id=${c.pk})}">jetzt anmelden</a>
</div> </div>
</div> </div>

View File

@ -9,7 +9,10 @@
<div class="mainpage"> <div class="mainpage">
<h1 class="centered cabin">Anmeldung</h1> <h1 class="centered cabin">Anmeldung</h1>
<h3 class="centered cabin" th:text="'zur ' + ${camp.name} + ' ' + ${camp.year}"></h3> <h3 class="centered cabin" th:text="'zur ' + ${camp.name} + ' ' + ${camp.year}"></h3>
<div class="card centered-card lindaborders" style="max-width: 48rem"> <div class="alert alert-warning" style="margin: auto; max-width: 450px" th:unless="${camp.bookingHasStarted}">
Die Anmeldung wird erst am <span th:text="${#temporals.format(camp.startBooking, 'dd.MM.yyyy')}"></span> freigeschaltet.
</div>
<div class="card centered-card lindaborders" style="max-width: 48rem" th:if="${camp.bookingHasStarted}">
<div class="card-body"> <div class="card-body">
<h1 class="centered cabin">Teilnehmeranmeldung</h1> <h1 class="centered cabin">Teilnehmeranmeldung</h1>
<form th:action="@{/registration/register}" th:object="${bean}" method="post"> <form th:action="@{/registration/register}" th:object="${bean}" method="post">
@ -143,8 +146,8 @@
$("#phone").val(j.phone); $("#phone").val(j.phone);
$("#email").val(j.email); $("#email").val(j.email);
$("#sex").val(j.sex); $("#sex").val(j.sex);
$("#birthDate").val(j.birthDate); $("#birthDate").val(j.birthDate);
} }
</script> </script>
</div> </div>
</div> </div>