restrict business camp overview by current year

This commit is contained in:
Jottyfan
2025-07-19 20:29:23 +02:00
parent 27c1669ed3
commit 30c2bd5fc0
9 changed files with 74 additions and 25 deletions

View File

@@ -12,6 +12,13 @@
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17/"/>
<classpathentry kind="con" path="org.eclipse.jst.j2ee.internal.web.container"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer">

View File

@@ -1,8 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project-modules id="moduleCoreId" project-version="1.5.0">
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="CampOrganizer2">
<property name="context-root" value="CampOrganizer2"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/resources"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="src/main/java"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/java"/>
</wb-module>
</project-modules>

View File

@@ -8,7 +8,7 @@ plugins {
}
group = 'de.jottyfan.camporganizer'
version = '0.9.7'
version = '0.9.8'
description = """CampOrganizer2"""

View File

@@ -1,10 +1,11 @@
package de.jottyfan.camporganizer.module.business.bookings;
import jakarta.annotation.security.RolesAllowed;
import java.time.LocalDate;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.RequestParam;
import de.jottyfan.camporganizer.module.business.bookings.model.AddPaymentBean;
import de.jottyfan.camporganizer.module.business.bookings.model.BookerBean;
import de.jottyfan.camporganizer.module.camplist.CommonController;
import jakarta.annotation.security.RolesAllowed;
/**
*
@@ -29,21 +31,23 @@ public class BookingsController extends CommonController {
@Autowired
private BookingsService bookingsService;
@GetMapping("/business/bookings")
@GetMapping("/business/bookings/{year}")
@RolesAllowed({"business_booking"})
public String getBookings(Model model) {
model.addAttribute("bookers", bookingsService.getBookers(getCurrentUser()));
public String getBookings(Model model, @Nullable @PathVariable("year") Integer year) {
model.addAttribute("bookers", bookingsService.getBookers(getCurrentUser(), year));
model.addAttribute("addBean", new AddPaymentBean());
model.addAttribute("year", LocalDate.now().getYear());
model.addAttribute("years", bookingsService.getAllCampYears());
return "business/bookings";
}
@GetMapping("/business/bookings/{id}")
@GetMapping("/business/bookings_by_id/{id}")
@RolesAllowed({"business_booking"})
public String getBooking(Model model, @PathVariable("id") Integer id) {
BookerBean bean = bookingsService.getBooker(id, getCurrentUser());
model.addAttribute("booker", bean);
model.addAttribute("addBean", new AddPaymentBean());
return bean == null ? getBookings(model) : "business/booker";
return bean == null ? getBookings(model, LocalDate.now().getYear()) : "business/booker";
}
@PostMapping("/business/bookings/payment/{id}")
@@ -54,13 +58,13 @@ public class BookingsController extends CommonController {
return getBooking(model, id);
}
@PostMapping("/business/bookings/listpayment/{id}")
@PostMapping("/business/bookings/listpayment/{id}/{year}")
@RolesAllowed({"business_booking"})
public String addListPayment(Model model, @ModelAttribute("bean") AddPaymentBean bean, @PathVariable("id") Integer id, @RequestParam(defaultValue = "") String search) {
public String addListPayment(Model model, @ModelAttribute("bean") AddPaymentBean bean, @PathVariable("id") Integer id, @PathVariable("year") Integer year, @RequestParam(defaultValue = "") String search) {
Double payment = bean.getPayment();
bookingsService.addPayment(id, payment);
LOGGER.debug("search is {}", search);
model.addAttribute("search", search);
return getBookings(model);
return getBookings(model, year);
}
}

View File

@@ -15,11 +15,14 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jooq.DSLContext;
import org.jooq.Record;
import org.jooq.Record1;
import org.jooq.Record10;
import org.jooq.Record13;
import org.jooq.SelectConditionStep;
import org.jooq.SelectSeekStep1;
import org.jooq.SelectSeekStep4;
import org.jooq.UpdateConditionStep;
import org.jooq.impl.DSL;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@@ -49,10 +52,11 @@ public class BookingsRepository {
* get a list of all registered persons that have booked the camp
*
* @param username the name of the current user in this session
* @param year the year of the camp; may be null
*
* @return a list of bookings; an empty one at least
*/
public List<BookerBean> getBookings(String username) {
public List<BookerBean> getBookings(String username, Integer year) {
SelectSeekStep4<Record10<Integer, EnumProgress, BigDecimal, String, String, EnumCamprole, EnumSex, LocalDateTime, String, Double>, EnumCamprole, EnumSex, String, String> sql = jooq
// @formatter:off
.select(T_PERSON.PK, T_PERSON.PROGRESS, T_PERSON.PAID, T_PERSON.FORENAME, T_PERSON.SURNAME, T_PERSON.CAMPROLE, T_PERSON.SEX, T_PERSON.CREATED, V_CAMP.NAME, V_CAMP.YEAR)
@@ -61,6 +65,7 @@ public class BookingsRepository {
.leftJoin(T_CAMPPROFILE).on(T_CAMPPROFILE.FK_CAMP.eq(T_PERSON.FK_CAMP)).and(T_CAMPPROFILE.MODULE.eq(EnumModule.business))
.leftJoin(T_PROFILE).on(T_PROFILE.PK.eq(T_CAMPPROFILE.FK_PROFILE))
.where(T_PROFILE.USERNAME.eq(username))
.and(year != null ? V_CAMP.YEAR.eq(year.doubleValue()) : DSL.trueCondition())
.orderBy(T_PERSON.CAMPROLE, T_PERSON.SEX, T_PERSON.SURNAME, T_PERSON.FORENAME);
// @formatter:on
LOGGER.trace(sql);
@@ -168,4 +173,20 @@ public class BookingsRepository {
LOGGER.trace(sql);
return sql.execute();
}
/**
* get an ordered list of all camp years found in the database
*
* @return the list of camp years
*/
public List<Integer> getAllCampYears() {
SelectSeekStep1<Record1<Double>, Double> sql = jooq
// @formatter:off
.selectDistinct(V_CAMP.YEAR)
.from(V_CAMP)
.orderBy(V_CAMP.YEAR);
// @formatter:on
LOGGER.trace(sql);
return sql.fetchInto(Integer.class);
}
}

View File

@@ -18,8 +18,8 @@ public class BookingsService {
@Autowired
private BookingsRepository bookingsGateway;
public List<BookerBean> getBookers(String username) {
return bookingsGateway.getBookings(username);
public List<BookerBean> getBookers(String username, Integer year) {
return bookingsGateway.getBookings(username, year);
}
public BookerBean getBooker(Integer id, String username) {
@@ -29,4 +29,8 @@ public class BookingsService {
public Integer addPayment(Integer id, Double payment) {
return bookingsGateway.addPayment(id, payment);
}
public List<Integer> getAllCampYears() {
return bookingsGateway.getAllCampYears();
}
}

View File

@@ -8,7 +8,14 @@
<th:block layout:fragment="content">
<div class="mainpage">
<div class="card" sec:authorize="hasRole('business_booking')">
<div class="card-header">Angemeldete Personen</div>
<div class="card-header d-flex justify-content-between">
<div>Angemeldete Personen</div>
<div>im Jahr
<span class="ml-2" th:each="y : ${years}">
<a th:class="${year == y ? '' : 'tablelink'}" th:href="@{/business/bookings/{year}(year=${y})}" th:text="${y}"></a>
</span>
</div>
</div>
<div class="card-body">
<table id="bookers" class="table table-striped">
<thead>
@@ -25,12 +32,12 @@
<tbody>
<th:block th:each="b : ${bookers}">
<tr>
<td class="middled"><a class="tablelink" th:href="@{/business/bookings/{id}(id=${b.pk})}" title="bearbeiten" th:text="${b.name}"></a></td>
<td class="middled"><a class="tablelink" th:href="@{/business/bookings_by_id/{id}(id=${b.pk})}" title="bearbeiten" th:text="${b.name}"></a></td>
<td class="middled" th:text="${b.sex}"></td>
<td class="middled" th:text="${b.camp}"></td>
<td class="middled" th:text="${b.role}"></td>
<td class="middled">
<form action="#" th:action="@{'/business/bookings/listpayment/' + ${b.pk}}" th:object="${addBean}" method="post">
<form action="#" th:action="@{'/business/bookings/listpayment/{id}/{year}(id=${b.pk},year=${year})'}" th:object="${addBean}" method="post">
<input th:id="'searchfield' + ${b.pk}" type="hidden" th:name="search" />
<div class="container">
<div class="row">

View File

@@ -70,7 +70,7 @@
<tbody>
<th:block th:each="b : ${bookers}">
<tr>
<td><a class="tablelink" th:href="@{/business/bookings/{id}(id=${b.pk})}" title="bearbeiten" th:text="${b.name}"></a></td>
<td><a class="tablelink" th:href="@{/business/bookings_by_id/{id}(id=${b.pk})}" title="bearbeiten" th:text="${b.name}"></a></td>
<td th:text="${b.sex}"></td>
<td th:text="${b.role}"></td>
<td><span th:text="${#numbers.formatDecimal(b.paid, 1, 2) + ' €'}" th:if="${b.paid != null}"></span></td>

View File

@@ -79,7 +79,7 @@
<a class="nav-link dropdown-toggle btn-icon-silent menufont" href="#" id="navbarDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">Abrechnung</a>
<ul class="dropdown-menu">
<li><a th:href="@{/business}" class="dropdown-item menufont">Freizeitübersicht</a></li>
<li><a th:href="@{/business/bookings}" class="dropdown-item menufont" sec:authorize="hasRole('business_booking')">Buchungsübersicht</a></li>
<li><a th:href="@{/business/bookings/{year}(year=${#dates.format(new java.util.Date(), 'yyyy')})}" class="dropdown-item menufont" sec:authorize="hasRole('business_booking')">Buchungsübersicht</a></li>
<li><a th:href="@{/business/outlay}" class="dropdown-item menufont" sec:authorize="hasRole('business_outlay')">Auslagen / Rechnungen</a>
<li><a th:href="@{/business/privileges}" class="dropdown-item menufont" sec:authorize="hasRole('admin')">Nutzerverwaltung</a></li>
</ul>