Jottyfan 2023-03-26 21:18:57 +02:00
parent edb0430456
commit 93a1289629
19 changed files with 208 additions and 48 deletions

View File

@ -18,7 +18,7 @@ apply plugin: 'war'
apply plugin: 'application'
group = 'de.jottyfan.camporganizer'
version = '0.3.9'
version = '0.4.0'
sourceCompatibility = 17
mainClassName = "de.jottyfan.camporganizer.Main"
@ -79,7 +79,7 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-validation'
implementation 'org.thymeleaf.extras:thymeleaf-extras-springsecurity5'
implementation 'de.jottyfan:COJooq:2021.02'
implementation 'de.jottyfan:COJooq:2023.03'
implementation 'nz.net.ultraq.thymeleaf:thymeleaf-layout-dialect:3.0.0'
runtimeOnly 'org.springframework.boot:spring-boot-starter-tomcat'
testImplementation 'org.springframework.boot:spring-boot-starter-test'

View File

@ -7,6 +7,8 @@ import static de.jottyfan.camporganizer.db.jooq.Tables.T_LOCATION;
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PERSON;
import static de.jottyfan.camporganizer.db.jooq.Tables.T_PROFILE;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
@ -23,6 +25,7 @@ import org.jooq.DeleteConditionStep;
import org.jooq.Field;
import org.jooq.InsertResultStep;
import org.jooq.InsertReturningStep;
import org.jooq.InsertValuesStep11;
import org.jooq.InsertValuesStep3;
import org.jooq.Record4;
import org.jooq.Record5;
@ -401,7 +404,8 @@ public class AdminRepository {
LOGGER.debug(sql2.toString());
sql2.execute();
} else {
lrw.putString("error", String.format("Es gibt bereits %d Anmeldungen. Die Freizeit kann daher nicht gelöscht werden.", registrations));
lrw.putString("error", String
.format("Es gibt bereits %d Anmeldungen. Die Freizeit kann daher nicht gelöscht werden.", registrations));
}
});
return lrw.getString("error");
@ -411,14 +415,57 @@ public class AdminRepository {
* upsert the camp
*
* @param bean the bean
* @return an error message, if any
*/
public String upsertCamp(@Valid CampBean bean) {
jooq.transaction(t -> {
LocalDate arriveDate = bean.getArrive();
LocalDate departDate = bean.getDepart();
LocalDateTime arrive = arriveDate == null ? null : arriveDate.atStartOfDay();
LocalDateTime depart = departDate == null ? null : departDate.atStartOfDay();
if (bean.getPk() == null) {
// TODO: insert
InsertValuesStep11<TCampRecord, LocalDateTime, String, LocalDateTime, Integer, Integer, Integer, Boolean, Integer, Integer, String, String> sql = DSL
.using(t)
// @formatter:off
.insertInto(T_CAMP,
T_CAMP.ARRIVE,
T_CAMP.COUNTRIES,
T_CAMP.DEPART,
T_CAMP.FK_DOCUMENT,
T_CAMP.FK_LOCATION,
T_CAMP.FK_PROFILE,
T_CAMP.LOCK_SALES,
T_CAMP.MAX_AGE,
T_CAMP.MIN_AGE,
T_CAMP.NAME,
T_CAMP.PRICE)
.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());
// @formatter:on
LOGGER.debug(sql.toString());
sql.execute();
} else {
// TODO: update
UpdateConditionStep<TCampRecord> sql = DSL.using(t)
// @formatter:off
.update(T_CAMP)
.set(T_CAMP.ARRIVE, arrive)
.set(T_CAMP.COUNTRIES, bean.getCountries())
.set(T_CAMP.DEPART, depart)
.set(T_CAMP.FK_DOCUMENT, bean.getFkDocument())
.set(T_CAMP.FK_LOCATION, bean.getFkLocation())
.set(T_CAMP.FK_PROFILE, bean.getFkProfile())
.set(T_CAMP.LOCK_SALES, bean.getLockSales() != null ? bean.getLockSales() : false)
.set(T_CAMP.MAX_AGE, bean.getMaxAge())
.set(T_CAMP.MIN_AGE, bean.getMinAge())
.set(T_CAMP.NAME, bean.getName())
.set(T_CAMP.PRICE, bean.getPrice())
.where(T_CAMP.PK.eq(bean.getPk()));
// @formatter:on
LOGGER.debug(sql.toString());
sql.execute();
}
return "not yet implemented";
});
return null;
}
/**

View File

@ -1,11 +1,16 @@
package de.jottyfan.camporganizer.module.admin;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import org.springframework.format.annotation.DateTimeFormat;
import de.jottyfan.camporganizer.db.jooq.tables.records.TCampRecord;
/**
@ -31,9 +36,11 @@ public class CampBean implements Serializable {
@NotNull
private Integer minAge;
@NotNull
private LocalDateTime arrive;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate arrive;
@NotNull
private LocalDateTime depart;
@DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate depart;
private String countries;
@NotNull
private String price;
@ -49,9 +56,11 @@ public class CampBean implements Serializable {
return null;
}
CampBean bean = new CampBean();
bean.setArrive(r.getArrive());
LocalDateTime arrive = r.getArrive();
LocalDateTime depart = r.getDepart();
bean.setArrive(arrive == null ? null : arrive.toLocalDate());
bean.setCountries(r.getCountries());
bean.setDepart(r.getDepart());
bean.setDepart(depart == null ? null : depart.toLocalDate());
bean.setFkDocument(r.getFkDocument());
bean.setFkLocation(r.getFkLocation());
bean.setFkProfile(r.getFkProfile());
@ -179,28 +188,28 @@ public class CampBean implements Serializable {
/**
* @return the arrive
*/
public LocalDateTime getArrive() {
public LocalDate getArrive() {
return arrive;
}
/**
* @param arrive the arrive to set
*/
public void setArrive(LocalDateTime arrive) {
public void setArrive(LocalDate arrive) {
this.arrive = arrive;
}
/**
* @return the depart
*/
public LocalDateTime getDepart() {
public LocalDate getDepart() {
return depart;
}
/**
* @param depart the depart to set
*/
public void setDepart(LocalDateTime depart) {
public void setDepart(LocalDate depart) {
this.depart = depart;
}
@ -231,4 +240,31 @@ public class CampBean implements Serializable {
public void setPrice(String price) {
this.price = price;
}
/**
* @return the countriesList
*/
public List<String> getCountriesList() {
String[] splitted = countries == null ? null : countries.split(",");
List<String> list = new ArrayList<>();
if (splitted != null && splitted.length > 0) {
for (String s : splitted) {
list.add(s.trim());
}
}
return list;
}
/**
* @param countriesList the countriesList to set
*/
public void setCountriesList(List<String> countriesList) {
StringBuilder buf = new StringBuilder();
boolean first = true;
for (String s : countriesList) {
buf.append(first ? "" : ", ").append(s);
first = false;
}
this.countries = buf.toString();
}
}

View File

@ -22,6 +22,7 @@ public class BookerBean implements Serializable {
private String camp;
private String price;
private Integer campId;
private BigDecimal requiredPrice;
/**
* @return the accept
@ -126,4 +127,18 @@ public class BookerBean implements Serializable {
public void setCampId(Integer campId) {
this.campId = campId;
}
/**
* @return the requiredPrice
*/
public BigDecimal getRequiredPrice() {
return requiredPrice;
}
/**
* @param requiredPrice the requiredPrice to set
*/
public void setRequiredPrice(BigDecimal requiredPrice) {
this.requiredPrice = requiredPrice;
}
}

View File

@ -15,7 +15,7 @@ import org.apache.logging.log4j.Logger;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Record10;
import org.jooq.Record12;
import org.jooq.Record13;
import org.jooq.SelectConditionStep;
import org.jooq.SelectSeekStep4;
import org.jooq.UpdateConditionStep;
@ -89,9 +89,21 @@ public class BookingsRepository {
* @return the booker bean or null
*/
public BookerBean getBooking(Integer id, String username) {
SelectConditionStep<Record12<Integer, Boolean, BigDecimal, String, String, EnumCamprole, EnumSex, LocalDateTime, String, Double, String, Integer>> sql = jooq
SelectConditionStep<Record13<Integer, Boolean, BigDecimal, String, String, EnumCamprole, EnumSex, LocalDateTime, BigDecimal, String, Double, String, Integer>> sql = jooq
// @formatter:off
.select(T_PERSON.PK, T_PERSON.ACCEPT, T_PERSON.PAID, T_PERSON.FORENAME, T_PERSON.SURNAME, T_PERSON.CAMPROLE, T_PERSON.SEX, T_PERSON.CREATED, V_CAMP.NAME, V_CAMP.YEAR, V_CAMP.PRICE, V_CAMP.PK)
.select(T_PERSON.PK,
T_PERSON.ACCEPT,
T_PERSON.PAID,
T_PERSON.FORENAME,
T_PERSON.SURNAME,
T_PERSON.CAMPROLE,
T_PERSON.SEX,
T_PERSON.CREATED,
T_PERSON.REQUIRED_PRICE,
V_CAMP.NAME,
V_CAMP.YEAR,
V_CAMP.PRICE,
V_CAMP.PK)
.from(T_PERSON)
.leftJoin(V_CAMP).on(V_CAMP.PK.eq(T_PERSON.FK_CAMP))
.leftJoin(T_SALESPROFILE).on(T_SALESPROFILE.FK_CAMP.eq(T_PERSON.FK_CAMP))
@ -108,6 +120,7 @@ public class BookingsRepository {
String surname = r.get(T_PERSON.SURNAME);
EnumCamprole role = r.get(T_PERSON.CAMPROLE);
EnumSex sex = r.get(T_PERSON.SEX);
BigDecimal requiredPrice = r.get(T_PERSON.REQUIRED_PRICE);
String campName = r.get(V_CAMP.NAME);
Double campYear = r.get(V_CAMP.YEAR);
Integer campId = r.get(V_CAMP.PK);
@ -122,6 +135,7 @@ public class BookingsRepository {
bean.setCamp(String.format("%s %4.0f", campName, campYear));
bean.setCampId(campId);
bean.setPrice(r.get(V_CAMP.PRICE));
bean.setRequiredPrice(requiredPrice);
return bean;
}
}

View File

@ -26,7 +26,6 @@ public class BusinessController extends CommonController {
@GetMapping("/business")
public String getIndex(Model model) {
String username = indexService.getCurrentUser(request);
model.addAttribute("currentUser", username);
model.addAttribute("campBudgets", indexService.getCampBudgets(username));
return "business/business";
}

View File

@ -21,9 +21,10 @@ public class BusinessBean implements Serializable {
private final String locationName;
private BigDecimal paid;
private boolean changed;
private BigDecimal requiredPrice;
public BusinessBean(Integer fkPerson, String forename, String surname, String campName, String campPrice,
LocalDateTime campArrive, String locationName, BigDecimal paid) {
LocalDateTime campArrive, String locationName, BigDecimal paid, BigDecimal requiredPrice) {
super();
this.fkPerson = fkPerson;
this.forename = forename;
@ -34,6 +35,7 @@ public class BusinessBean implements Serializable {
this.locationName = locationName;
this.paid = paid;
this.changed = false;
this.requiredPrice = requiredPrice;
}
/**
@ -103,4 +105,18 @@ public class BusinessBean implements Serializable {
public boolean isChanged() {
return changed;
}
/**
* @return the requiredPrice
*/
public BigDecimal getRequiredPrice() {
return requiredPrice;
}
/**
* @param requiredPrice the requiredPrice to set
*/
public void setRequiredPrice(BigDecimal requiredPrice) {
this.requiredPrice = requiredPrice;
}
}

View File

@ -16,7 +16,7 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DSLContext;
import org.jooq.Record4;
import org.jooq.Record8;
import org.jooq.Record9;
import org.jooq.SelectConditionStep;
import org.jooq.SelectSeekStep1;
import org.jooq.UpdateConditionStep;
@ -80,7 +80,7 @@ public class BusinessRepository {
* @return a list of business beans; an empty one at least
*/
public List<BusinessBean> getAllRegistrations(String username) {
SelectConditionStep<Record8<Integer, String, String, String, String, LocalDateTime, String, BigDecimal>> sql = jooq
SelectConditionStep<Record9<Integer, String, String, String, String, LocalDateTime, String, BigDecimal, BigDecimal>> sql = jooq
// @formatter:off
.select(T_PERSON.PK,
T_PERSON.FORENAME,
@ -89,7 +89,8 @@ public class BusinessRepository {
T_CAMP.PRICE,
T_CAMP.ARRIVE,
T_LOCATION.NAME,
T_PERSON.PAID)
T_PERSON.PAID,
T_PERSON.REQUIRED_PRICE)
.from(T_PERSON)
.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_PERSON.FK_CAMP))
.leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION))
@ -99,7 +100,7 @@ public class BusinessRepository {
// @formatter:on
LOGGER.debug(sql.toString());
List<BusinessBean> list = new ArrayList<>();
for (Record8<Integer, String, String, String, String, LocalDateTime, String, BigDecimal> r : sql.fetch()) {
for (Record9<Integer, String, String, String, String, LocalDateTime, String, BigDecimal, BigDecimal> r : sql.fetch()) {
Integer fkPerson = r.get(T_PERSON.PK);
String forename = r.get(T_PERSON.FORENAME);
String surname = r.get(T_PERSON.SURNAME);
@ -108,7 +109,8 @@ public class BusinessRepository {
LocalDateTime campArrive = r.get(T_CAMP.ARRIVE);
String locationName = r.get(T_CAMP.NAME);
BigDecimal paid = r.get(T_PERSON.PAID);
list.add(new BusinessBean(fkPerson, forename, surname, campName, campPrice, campArrive, locationName, paid));
BigDecimal requiredPrice = r.get(T_PERSON.REQUIRED_PRICE);
list.add(new BusinessBean(fkPerson, forename, surname, campName, campPrice, campArrive, locationName, paid, requiredPrice));
}
return list;
}

View File

@ -2,7 +2,6 @@ package de.jottyfan.camporganizer.module.business.privileges.impl;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
*
@ -22,16 +21,6 @@ public class ProfileBean implements Serializable {
return new StringBuilder().append(forename).append(" ").append(surname).toString();
}
public String dropdown() {
StringBuilder buf = new StringBuilder();
buf.append(forename).append(" ");
buf.append(surname).append(" (");
buf.append(username).append(", ");
buf.append(duedate == null ? "" : duedate.format(DateTimeFormatter.ofPattern("dd.MM.yyyy")));
buf.append(")");
return buf.toString();
}
@Override
public String toString() {
StringBuilder buf = new StringBuilder();

View File

@ -74,6 +74,10 @@ public class BookingBean implements Serializable {
return EnumCamprole.feeder.equals(camprole);
}
public Boolean isObserver() {
return EnumCamprole.observer.equals(camprole);
}
/**
* @return the forename
*/

View File

@ -47,6 +47,8 @@ public class BookingBean implements Serializable, Comparable<BookingBean> {
return "Leiter";
} else if (EnumCamprole.feeder.getLiteral().equals(role)) {
return "Küchenteam";
} else if (EnumCamprole.observer.getLiteral().equals(role)) {
return "Mitarbeiterkind";
} else {
return role;
}

View File

@ -62,10 +62,32 @@
</div>
<div class="row mb-2">
<label for="inputCountries" class="col-sm-2 col-form-label">Ferien in</label>
<div class="col-sm-10"><!-- TODO: input helper for finding Bundesland by typing -->
<span class="error" th:each="error : ${#fields.errors('countries')}">[[${error}]]<br /></span> <textarea id="inputCountries" type="text" th:field="*{countries}"
th:class="${'form-control ' + (#fields.hasErrors('countries') ? 'inputerror' : '')}"></textarea>
<div class="col-sm-10">
<span class="error" th:each="error : ${#fields.errors('countriesList')}">[[${error}]]<br /></span>
<select id="inputCountries" th:field="*{countriesList}" th:class="${'form-select ' + (#fields.hasErrors('countriesList') ? 'inputerror' : '')}" multiple="multiple">
<option value="Baden-Württemberg">Baden-Württemberg</option>
<option value="Bayern">Bayern</option>
<option value="Berlin">Berlin</option>
<option value="Brandenburg">Brandenburg</option>
<option value="Bremen">Bremen</option>
<option value="Hamburg">Hamburg</option>
<option value="Hessen">Hessen</option>
<option value="Mecklenburg-Vorpommern">Mecklenburg-Vorpommern</option>
<option value="Niedersachsen">Niedersachsen</option>
<option value="Nordrhein-Westfalen">Nordrhein-Westfalen</option>
<option value="Rheinland-Pfalz">Rheinland-Pfalz</option>
<option value="Saarland">Saarland</option>
<option value="Sachsen">Sachsen</option>
<option value="Sachsen-Anhalt">Sachsen-Anhalt</option>
<option value="Schleswig-Holstein">Schleswig-Holstein</option>
<option value="Thüringen">Thüringen</option>
</select>
</div>
<script type="text/javascript">
$(document).ready(function(){
$("#inputCountries").select2();
});
</script>
</div>
<div class="row mb-2">
<label for="inputDoc" class="col-sm-2 col-form-label">Bestätigung</label>
@ -97,7 +119,13 @@
</script>
</div>
</div>
<!-- TODO: lock sales - boolean - Kassenschluss -->
<div class="row mb-2">
<label for="inputLockSales" class="col-sm-2 col-form-label">Kassenschluss</label>
<div class="col-sm-10">
<input id="lockSales" type="checkbox" name="lockSales" th:checked="*{lockSales}" />
<label for="lockSales">Abrechnung abgeschlossen</label>
</div>
</div>
<div class="row mb-2">
<div class="col-sm-2"></div>
<div class="col-sm-10">

View File

@ -23,6 +23,7 @@
<span th:if="${r.literal == 'teacher'}" class="roleflag">Mitarbeiter</span>
<span th:if="${r.literal == 'director'}" class="roleflag">Leiter</span>
<span th:if="${r.literal == 'feeder'}" class="roleflag">Küche</span>
<span th:if="${r.literal == 'observer'}" class="roleflag">Mitarbeiterkind</span>
</th:block></td>
<td><a th:href="@{/document/{id}(id=${d.pk})}"><i class="fas fa-download"></i></a></td>
<td><span th:text="${d.filetype.literal}" th:if="${d.filetype}"></span></td>

View File

@ -34,7 +34,8 @@
<option value="student">Teilnehmer</option>
<option value="teacher">Mitarbeiter</option>
<option value="director">Leiter</option>
<option value="feeder">Küche</option>
<option value="feeder">Küchenteam</option>
<option value="observer">Mitarbeiterkind</option>
</select>
</div>
</div>

View File

@ -40,12 +40,16 @@
<td th:text="${booker.accept == null ? '' : (booker.accept ? 'Ja' : 'abgelehnt')}"></td>
</tr>
<tr>
<th>Preis</th>
<th>Freizeitpreis</th>
<td th:text="${booker.price}" />
</tr>
<tr>
<th>Kontostand</th>
<td><span th:text="${#numbers.formatDecimal(booker.paid, 1, 2) + ' €'}" th:if="${booker.paid != null}"></span>
<td><span th:text="${#numbers.formatDecimal(booker.paid, 1, 2) + ' €'}" th:if="${booker.paid != null}"></span></td>
</tr>
<tr style="display: none"><!-- insert field not yet implemented -->
<th>zu zahlen</th>
<td><span th:text="${#numbers.formatDecimal(booker.requiredPrice, 1, 2) + ' €'}" th:if="${booker.requiredPrice != null}"></span></td>
</tr>
</tbody>
</table>

View File

@ -91,6 +91,7 @@
<option value="teacher">Mitarbeiter</option>
<option value="director">Leiter</option>
<option value="feeder">Küchenteam</option>
<option value="observer">Mitarbeiterkind</option>
</select>
</div>
</div>

View File

@ -83,7 +83,7 @@
<div class="row mb-2">
<div class="col-sm-2">Rolle:</div>
<span class="col-sm-10"> <span th:if="${b.isTeacher()}">Mitarbeiter</span> <span th:if="${b.isStudent()}">Teilnehmer</span> <span th:if="${b.isDirector()}">Leiter</span> <span
th:if="${b.isFeeder()}">Küchenteam</span>
th:if="${b.isFeeder()}">Küchenteam</span> <span th:if="${b.isObserver()}">Mitarbeiterkind</span>
</span>
</div>
<div class="row mb-2">

View File

@ -74,6 +74,7 @@
<option value="teacher">Mitarbeiter</option>
<option value="feeder">Küchenteam</option>
<option value="director">Leiter</option>
<option value="observer">Mitarbeiterkind</option>
</select>
</div>
</div>

View File

@ -108,9 +108,9 @@
<li><a th:href="@{/admin/mail}" class="dropdown-item menufont">Testmail</a></li>
<li><a th:href="@{/admin/document}" class="dropdown-item menufont">Dokumente</a></li>
<li><a th:href="@{/admin/location}" class="dropdown-item menufont">Freizeitheime</a></li>
<!-- TODO: implementation not yet finished
<!-- TODO: implementation not yet finished -->
<li><a th:href="@{/admin/camp}" class="dropdown-item menufont">Freizeiten</a>
-->
<!-- -->
</ul>
</div>
</li>