Compare commits
	
		
			1 Commits
		
	
	
		
			outlay
			...
			ae9e2018a8
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | ae9e2018a8 | 
| @@ -8,7 +8,7 @@ plugins { | |||||||
| } | } | ||||||
|  |  | ||||||
| group = 'de.jottyfan.camporganizer' | group = 'de.jottyfan.camporganizer' | ||||||
| version = '0.8.5' | version = '0.8.6' | ||||||
|  |  | ||||||
| description = """CampOrganizer2""" | description = """CampOrganizer2""" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,10 @@ package de.jottyfan.camporganizer.module.business.outlay; | |||||||
| import java.security.Principal; | import java.security.Principal; | ||||||
|  |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
|  | import org.springframework.core.io.InputStreamResource; | ||||||
|  | import org.springframework.core.io.Resource; | ||||||
|  | import org.springframework.http.MediaType; | ||||||
|  | import org.springframework.http.ResponseEntity; | ||||||
| import org.springframework.stereotype.Controller; | import org.springframework.stereotype.Controller; | ||||||
| import org.springframework.ui.Model; | import org.springframework.ui.Model; | ||||||
| import org.springframework.validation.BindingResult; | import org.springframework.validation.BindingResult; | ||||||
| @@ -15,6 +19,7 @@ import de.jottyfan.camporganizer.module.business.outlay.model.OutlayBean; | |||||||
| import de.jottyfan.camporganizer.module.camplist.CommonController; | import de.jottyfan.camporganizer.module.camplist.CommonController; | ||||||
| import jakarta.annotation.security.RolesAllowed; | import jakarta.annotation.security.RolesAllowed; | ||||||
| import jakarta.validation.Valid; | import jakarta.validation.Valid; | ||||||
|  | import jakarta.ws.rs.core.HttpHeaders; | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * |  * | ||||||
| @@ -30,7 +35,8 @@ public class OutlayController extends CommonController { | |||||||
|  |  | ||||||
| 	@GetMapping("/business/outlay") | 	@GetMapping("/business/outlay") | ||||||
| 	public String getOutlayDashboard(Model model, Principal principal) { | 	public String getOutlayDashboard(Model model, Principal principal) { | ||||||
| 		model.addAttribute("list", service.getListOfUser(super.getCurrentUser(principal))); | 		model.addAttribute("list", service.getListOf(super.getCurrentUser(principal), null)); | ||||||
|  | 		model.addAttribute("camps", service.getAllCamps()); | ||||||
| 		return "/business/outlay/list"; | 		return "/business/outlay/list"; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -63,4 +69,19 @@ public class OutlayController extends CommonController { | |||||||
| 		service.deleteIfAllowedFor(super.getCurrentUser(principal), id); | 		service.deleteIfAllowedFor(super.getCurrentUser(principal), id); | ||||||
| 		return "redirect:/business/outlay"; | 		return "redirect:/business/outlay"; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	@GetMapping("/business/outlay/summary/{campid}") | ||||||
|  | 	public String getSummaryOfCamp(@PathVariable("campid") Integer campId, Model model, Principal principal) { | ||||||
|  | 		model.addAttribute("campid", campId); | ||||||
|  | 		model.addAttribute("list", service.getListOf(null, campId)); | ||||||
|  | 		return "/business/outlay/summary"; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@GetMapping("/business/outlay/download/{campid}") | ||||||
|  | 	public ResponseEntity<Resource> generateCsv(@PathVariable("campid") Integer campId) { | ||||||
|  | 		String filename = String.format("rechnung_camp_%d.csv", campId); | ||||||
|  | 		InputStreamResource file = new InputStreamResource(service.getCsv(campId)); | ||||||
|  | 		return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + filename) | ||||||
|  | 				.contentType(MediaType.parseMediaType("application/csv")).body(file); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -16,11 +16,12 @@ import org.jooq.DSLContext; | |||||||
| import org.jooq.DeleteConditionStep; | import org.jooq.DeleteConditionStep; | ||||||
| import org.jooq.InsertValuesStep8; | import org.jooq.InsertValuesStep8; | ||||||
| import org.jooq.Record10; | import org.jooq.Record10; | ||||||
|  | import org.jooq.Record11; | ||||||
| import org.jooq.Record4; | import org.jooq.Record4; | ||||||
| import org.jooq.Record7; |  | ||||||
| import org.jooq.SelectConditionStep; | import org.jooq.SelectConditionStep; | ||||||
| import org.jooq.SelectSeekStep1; | import org.jooq.SelectSeekStep1; | ||||||
| import org.jooq.UpdateConditionStep; | import org.jooq.UpdateConditionStep; | ||||||
|  | import org.jooq.impl.DSL; | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| import org.springframework.stereotype.Repository; | import org.springframework.stereotype.Repository; | ||||||
| import org.springframework.transaction.annotation.Transactional; | import org.springframework.transaction.annotation.Transactional; | ||||||
| @@ -68,8 +69,8 @@ public class OutlayRepository { | |||||||
| 		return list; | 		return list; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public List<OutlayBean> getListOf(String username) { | 	public List<OutlayBean> getListOf(String username, Integer campId) { | ||||||
| 		SelectConditionStep<Record7<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime>> sql = jooq | 		SelectConditionStep<Record11<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime, String, String, String, String>> sql = jooq | ||||||
| 		// @formatter:off | 		// @formatter:off | ||||||
| 			.select(T_SALES.PK, | 			.select(T_SALES.PK, | ||||||
| 					    T_SALES.TRADER, | 					    T_SALES.TRADER, | ||||||
| @@ -77,26 +78,35 @@ public class OutlayRepository { | |||||||
| 					    T_CAMP.ARRIVE, | 					    T_CAMP.ARRIVE, | ||||||
| 					    T_LOCATION.NAME, | 					    T_LOCATION.NAME, | ||||||
| 					    T_SALES.CASH, | 					    T_SALES.CASH, | ||||||
| 					    T_SALES.BUYDATE) | 					    T_SALES.BUYDATE, | ||||||
|  | 					    T_SALES.PROVIDER, | ||||||
|  | 					    T_SALES.RECIPENUMBER, | ||||||
|  | 					    T_SALES.INCREDIENTS, | ||||||
|  | 					    T_SALES.RECIPENOTE) | ||||||
| 			.from(T_SALES) | 			.from(T_SALES) | ||||||
| 			.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_SALES.FK_CAMP)) | 			.leftJoin(T_CAMP).on(T_CAMP.PK.eq(T_SALES.FK_CAMP)) | ||||||
| 			.leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION)) | 			.leftJoin(T_LOCATION).on(T_LOCATION.PK.eq(T_CAMP.FK_LOCATION)) | ||||||
| 			.where(T_SALES.PROVIDER.eq(username)); | 			.where(username == null ? DSL.trueCondition() : T_SALES.PROVIDER.eq(username)) | ||||||
|  | 			.and(campId == null ? DSL.trueCondition() : T_SALES.FK_CAMP.eq(campId)); | ||||||
| 		// @formatter:on | 		// @formatter:on | ||||||
| 		LOGGER.trace(sql); | 		LOGGER.trace(sql); | ||||||
| 		List<OutlayBean> list = new ArrayList<>(); | 		List<OutlayBean> list = new ArrayList<>(); | ||||||
| 		Iterator<Record7<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime>> i = sql.fetch() | 		Iterator<Record11<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime, String, String, String, String>> i = sql.fetch() | ||||||
| 				.iterator(); | 				.iterator(); | ||||||
| 		while (i.hasNext()) { | 		while (i.hasNext()) { | ||||||
| 			Record7<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime> r = i.next(); | 			Record11<Integer, String, String, LocalDateTime, String, BigDecimal, LocalDateTime, String, String, String, String> r = i.next(); | ||||||
| 			String campname = String | 			String campname = String | ||||||
| 					.format("%s %s %d", r.get(T_CAMP.NAME), r.get(T_LOCATION.NAME), r.get(T_CAMP.ARRIVE).getYear()).trim(); | 					.format("%s %s %d", r.get(T_CAMP.NAME), r.get(T_LOCATION.NAME), r.get(T_CAMP.ARRIVE).getYear()).trim(); | ||||||
| 			OutlayBean bean = new OutlayBean(); | 			OutlayBean bean = new OutlayBean(); | ||||||
| 			bean.setId(r.get(T_SALES.PK)); | 			bean.setId(r.get(T_SALES.PK)); | ||||||
| 			bean.setTrader(r.get(T_SALES.TRADER)); | 			bean.setTrader(r.get(T_SALES.TRADER)); | ||||||
| 			bean.setCampname(campname); | 			bean.setCampname(campname); | ||||||
|  | 			bean.setProvider(r.get(T_SALES.PROVIDER)); | ||||||
| 			bean.setCash(r.get(T_SALES.CASH)); | 			bean.setCash(r.get(T_SALES.CASH)); | ||||||
| 			bean.setBuydate(r.get(T_SALES.BUYDATE)); | 			bean.setBuydate(r.get(T_SALES.BUYDATE)); | ||||||
|  | 			bean.setRecipenumber(r.get(T_SALES.RECIPENUMBER)); | ||||||
|  | 			bean.setIngredients(r.get(T_SALES.INCREDIENTS)); | ||||||
|  | 			bean.setRecipenote(r.get(T_SALES.RECIPENOTE)); | ||||||
| 			list.add(bean); | 			list.add(bean); | ||||||
| 		} | 		} | ||||||
| 		return list; | 		return list; | ||||||
|   | |||||||
| @@ -1,5 +1,7 @@ | |||||||
| package de.jottyfan.camporganizer.module.business.outlay; | package de.jottyfan.camporganizer.module.business.outlay; | ||||||
|  |  | ||||||
|  | import java.io.ByteArrayInputStream; | ||||||
|  | import java.io.InputStream; | ||||||
| import java.util.List; | import java.util.List; | ||||||
|  |  | ||||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||||
| @@ -20,8 +22,8 @@ public class OutlayService { | |||||||
| 	@Autowired | 	@Autowired | ||||||
| 	private OutlayRepository repository; | 	private OutlayRepository repository; | ||||||
|  |  | ||||||
| 	public List<OutlayBean> getListOfUser(String username) { | 	public List<OutlayBean> getListOf(String username, Integer campId) { | ||||||
| 		return repository.getListOf(username); | 		return repository.getListOf(username, campId); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	public List<CampBean> getAllCamps() { | 	public List<CampBean> getAllCamps() { | ||||||
| @@ -43,4 +45,13 @@ public class OutlayService { | |||||||
| 	public void deleteIfAllowedFor(String username, Integer id) { | 	public void deleteIfAllowedFor(String username, Integer id) { | ||||||
| 		repository.deleteBeanIfAllowedFor(username, id); | 		repository.deleteBeanIfAllowedFor(username, id); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	public InputStream getCsv(Integer campId) { | ||||||
|  | 		List<OutlayBean> list = repository.getListOf(null, campId); | ||||||
|  | 		StringBuilder buf = new StringBuilder("Beleg-Nummer;Einkauf bei;Freizeit;bezahlt von;Betrag;Bestandteile;Rechnungsdatum\n"); | ||||||
|  | 		for (OutlayBean bean : list) { | ||||||
|  | 			buf.append(bean.toCsvLine()); | ||||||
|  | 		} | ||||||
|  | 		return new ByteArrayInputStream(buf.toString().getBytes()); | ||||||
|  | 	} | ||||||
| } | } | ||||||
|   | |||||||
| @@ -2,7 +2,9 @@ package de.jottyfan.camporganizer.module.business.outlay.model; | |||||||
|  |  | ||||||
| import java.io.Serializable; | import java.io.Serializable; | ||||||
| import java.math.BigDecimal; | import java.math.BigDecimal; | ||||||
|  | import java.text.NumberFormat; | ||||||
| import java.time.LocalDateTime; | import java.time.LocalDateTime; | ||||||
|  | import java.util.Locale; | ||||||
|  |  | ||||||
| import org.springframework.format.annotation.DateTimeFormat; | import org.springframework.format.annotation.DateTimeFormat; | ||||||
|  |  | ||||||
| @@ -38,6 +40,26 @@ public class OutlayBean implements Serializable { | |||||||
| 		return this; | 		return this; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
|  | 	private static final String quoted(String s) { | ||||||
|  | 		return s == null ? "" : String.format("\"%s\"", s.replace("\"", "'")); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	private static final String cashed(BigDecimal money) { | ||||||
|  | 		return money == null ? "" :  String.format("%s €", NumberFormat.getNumberInstance(Locale.GERMAN).format(money)); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	public String toCsvLine() { | ||||||
|  | 		StringBuilder buf = new StringBuilder(); | ||||||
|  | 		buf.append(recipenumber).append(";"); | ||||||
|  | 		buf.append(quoted(trader)).append(";"); | ||||||
|  | 		buf.append(quoted(campname)).append(";"); | ||||||
|  | 		buf.append(quoted(provider)).append(";"); | ||||||
|  | 		buf.append(cashed(cash)).append(";"); | ||||||
|  | 		buf.append(quoted(ingredients)).append(";"); | ||||||
|  | 		buf.append(buydate).append("\n"); | ||||||
|  | 		return buf.toString(); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	/** | 	/** | ||||||
| 	 * @return the id | 	 * @return the id | ||||||
| 	 */ | 	 */ | ||||||
|   | |||||||
| @@ -31,6 +31,11 @@ | |||||||
| 						</tr> | 						</tr> | ||||||
| 					</tfoot> | 					</tfoot> | ||||||
| 				</table> | 				</table> | ||||||
|  | 				<div class="row"> | ||||||
|  | 				  <div class="col" th:each="c : ${camps}"> | ||||||
|  | 				    <a th:href="@{/business/outlay/summary/{id}(id=${c.id})}" class="btn btn-outline-primary" th:text="${c.campname}"></a> | ||||||
|  | 				  </div> | ||||||
|  | 				</div> | ||||||
| 				<script> | 				<script> | ||||||
| 					$(document).ready(function() { | 					$(document).ready(function() { | ||||||
| 						$("#table").DataTable({ | 						$("#table").DataTable({ | ||||||
|   | |||||||
							
								
								
									
										53
									
								
								src/main/resources/templates/business/outlay/summary.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/main/resources/templates/business/outlay/summary.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | |||||||
|  | <!DOCTYPE html> | ||||||
|  | <html xmlns:th="http://www.thymeleaf.org" layout:decorate="~{template}" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" xmlns:sec="http://www.thymeleaf.org/extras/spring-security"> | ||||||
|  | <head> | ||||||
|  | <title>Camp Organizer Business</title> | ||||||
|  | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | 	<th:block layout:fragment="content"> | ||||||
|  | 		<div class="mainpage"> | ||||||
|  | 			<div class="container" style="max-width: 100%" sec:authorize="hasRole('business_outlay')"> | ||||||
|  | 				<table id="table" class="table table-striped"> | ||||||
|  | 					<thead> | ||||||
|  | 						<tr> | ||||||
|  | 							<th>Kassenzettelnummer</th> | ||||||
|  | 							<th>Händler / Shop</th> | ||||||
|  | 							<th>Freizeit</th> | ||||||
|  | 							<th>Auslegender</th> | ||||||
|  | 							<th>Betrag</th> | ||||||
|  | 							<th>Tag / Uhrzeit</th> | ||||||
|  | 							<th>Kurzbeschreibung</th> | ||||||
|  | 							<th>Bemerkungen</th> | ||||||
|  | 						</tr> | ||||||
|  | 					</thead> | ||||||
|  | 					<tbody> | ||||||
|  | 						<tr th:each="o : ${list}"> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${o.recipenumber}"></a></td> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${o.trader}"></a></td> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${o.campname}"></a></td> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${o.provider}"></a></td> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${#numbers.formatDecimal(o.cash, 1, 2, 'COMMA')} + ' €'"></a></td> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${#temporals.format(o.buydate, 'dd.MM.yyyy, HH:mm.ss')}"></a></td> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${o.ingredients}"></a></td> | ||||||
|  | 							<td><a th:href="@{/business/outlay/edit/{id}(id=${o.id})}" th:text="${o.recipenote}"></a></td> | ||||||
|  | 						</tr> | ||||||
|  | 					</tbody> | ||||||
|  | 					<tfoot> | ||||||
|  | 						<tr> | ||||||
|  | 							<td colspan="8"><a th:href="@{/business/outlay/download/{campid}(campid=${campid})}" class="btn btn-outline-primary form-control">herunterladen</a></td> | ||||||
|  | 						</tr> | ||||||
|  | 					</tfoot> | ||||||
|  | 				</table> | ||||||
|  | 				<script> | ||||||
|  | 					$(document).ready(function() { | ||||||
|  | 						$("#table").DataTable({ | ||||||
|  | 							language : locale_de | ||||||
|  | 						}); | ||||||
|  | 					}); | ||||||
|  | 				</script> | ||||||
|  | 			</div> | ||||||
|  | 		</div> | ||||||
|  | 	</th:block> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
		Reference in New Issue
	
	Block a user