Allow the user to create manual bookings
This commit is contained in:
parent
0061d25082
commit
e53c1e0872
@ -1,4 +1,4 @@
|
|||||||
package org.hso.ecommerce.controller.intern;
|
package org.hso.ecommerce.controller.intern.accounting;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -221,9 +221,4 @@ public class AccountingController {
|
|||||||
request.setAttribute("bookings", result.bookings);
|
request.setAttribute("bookings", result.bookings);
|
||||||
return "intern/accounting/main";
|
return "intern/accounting/main";
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/intern/accounting/addManual")
|
|
||||||
public String accountingAddManual() {
|
|
||||||
return "intern/accounting/addManual";
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -0,0 +1,259 @@
|
|||||||
|
package org.hso.ecommerce.controller.intern.accounting;
|
||||||
|
|
||||||
|
import org.hso.ecommerce.action.booking.CreateBookingAction;
|
||||||
|
import org.hso.ecommerce.entities.booking.Booking;
|
||||||
|
import org.hso.ecommerce.entities.booking.BookingAccountEntry;
|
||||||
|
import org.hso.ecommerce.entities.booking.BookingReason;
|
||||||
|
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
|
||||||
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||||
|
import org.hso.ecommerce.repos.supplier.SupplierRepository;
|
||||||
|
import org.hso.ecommerce.repos.user.UserRepository;
|
||||||
|
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.PostMapping;
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public class ManualAccountingController {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final BookingRepository bookingRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final BookingAccountEntryRepository bookingAccountEntryRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final UserRepository userRepository = null;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
final SupplierRepository supplierRepository = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collection for the form values used to create a manual booking
|
||||||
|
*/
|
||||||
|
public static class ManualAccounting {
|
||||||
|
String amount;
|
||||||
|
String source;
|
||||||
|
String sourceCustomer;
|
||||||
|
String sourceSupplier;
|
||||||
|
String destination;
|
||||||
|
String destinationCustomer;
|
||||||
|
String destinationSupplier;
|
||||||
|
String reason;
|
||||||
|
String reasonText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default constructor with default values for the form
|
||||||
|
*/
|
||||||
|
public ManualAccounting() {
|
||||||
|
amount = "0.00";
|
||||||
|
reason = "Manual";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getAmount() {
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAmount(String amount) {
|
||||||
|
this.amount = amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSource() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSource(String source) {
|
||||||
|
this.source = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceCustomer() {
|
||||||
|
return sourceCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceCustomer(String sourceCustomer) {
|
||||||
|
this.sourceCustomer = sourceCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getSourceSupplier() {
|
||||||
|
return sourceSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSourceSupplier(String sourceSupplier) {
|
||||||
|
this.sourceSupplier = sourceSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDestination() {
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestination(String destination) {
|
||||||
|
this.destination = destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDestinationCustomer() {
|
||||||
|
return destinationCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationCustomer(String destinationCustomer) {
|
||||||
|
this.destinationCustomer = destinationCustomer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDestinationSupplier() {
|
||||||
|
return destinationSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDestinationSupplier(String destinationSupplier) {
|
||||||
|
this.destinationSupplier = destinationSupplier;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReason() {
|
||||||
|
return reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReason(String reason) {
|
||||||
|
this.reason = reason;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getReasonText() {
|
||||||
|
return reasonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReasonText(String reasonText) {
|
||||||
|
this.reasonText = reasonText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An exception to represent errors that can be shown to the user
|
||||||
|
*/
|
||||||
|
public static class InvalidFormDataException extends Exception {
|
||||||
|
public InvalidFormDataException(String msg) {
|
||||||
|
super(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean sameAccountBothSides(ManualAccounting formData) {
|
||||||
|
// No need to check for NumberFormatException because the numbers were already parsed before.
|
||||||
|
if (!formData.getSource().equals(formData.getDestination())) {
|
||||||
|
return false;
|
||||||
|
} else if (formData.getSource().equals("Cust")
|
||||||
|
&& Long.parseLong(formData.getSourceCustomer()) != Long.parseLong(formData.getDestinationCustomer())) {
|
||||||
|
return false;
|
||||||
|
} else if (formData.getSource().equals("Sup")
|
||||||
|
&& Long.parseLong(formData.getSourceSupplier()) != Long.parseLong(formData.getDestinationSupplier())) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Booking createBooking(ManualAccounting formData) throws InvalidFormDataException {
|
||||||
|
if (formData.getSource() == null) {
|
||||||
|
throw new InvalidFormDataException("Bitte wählen Sie ein Quellkonto aus.");
|
||||||
|
} else if (formData.getDestination() == null) {
|
||||||
|
throw new InvalidFormDataException("Bitte wählen Sie ein Zielkonto aus.");
|
||||||
|
}
|
||||||
|
BookingAccountEntry source = getAccountFromFormData(formData.getSource(), formData.getSourceCustomer(),
|
||||||
|
formData.getSourceSupplier());
|
||||||
|
BookingAccountEntry destination = getAccountFromFormData(formData.getDestination(),
|
||||||
|
formData.getDestinationCustomer(), formData.getDestinationSupplier());
|
||||||
|
|
||||||
|
if (sameAccountBothSides(formData)) {
|
||||||
|
throw new InvalidFormDataException("Quell- und Zielkonto dürfen nicht das selbe sein.");
|
||||||
|
}
|
||||||
|
|
||||||
|
double doubleAmount;
|
||||||
|
try {
|
||||||
|
doubleAmount = Double.parseDouble(formData.amount);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidFormDataException("Der angegebene Betrag ist ungültig.");
|
||||||
|
}
|
||||||
|
int amountCent = (int) Math.round(doubleAmount * 100);
|
||||||
|
|
||||||
|
BookingReason reason = new BookingReason();
|
||||||
|
if (formData.getReason().equals("Start")) {
|
||||||
|
reason.isStartBooking = true;
|
||||||
|
} else if (formData.getReason().equals("Manual")) {
|
||||||
|
reason.isManuel = true;
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Invalid form value for the booking reason: " + formData.getReason());
|
||||||
|
}
|
||||||
|
reason.comment = formData.reasonText;
|
||||||
|
|
||||||
|
CreateBookingAction action = new CreateBookingAction(source, destination, reason, amountCent);
|
||||||
|
return action.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the corresponding account based on user-input
|
||||||
|
*
|
||||||
|
* @param account The chosen value on the radio buttons
|
||||||
|
* @param customer The given customer id from the corresponding text field
|
||||||
|
* @param supplier the given supplier id from the corresponding text field
|
||||||
|
* @return The account entry that can be used to create the new booking
|
||||||
|
* @throws InvalidFormDataException If the user provided incorrect data in any way
|
||||||
|
*/
|
||||||
|
private BookingAccountEntry getAccountFromFormData(String account, String customer, String supplier)
|
||||||
|
throws InvalidFormDataException {
|
||||||
|
if (account.equals("None")) {
|
||||||
|
return null;
|
||||||
|
} else if (account.equals("Main")) {
|
||||||
|
return bookingAccountEntryRepository.getByMain().orElseGet(BookingAccountEntry::newMain);
|
||||||
|
} else if (account.equals("Vat")) {
|
||||||
|
return bookingAccountEntryRepository.getByVat().orElseGet(BookingAccountEntry::newVat);
|
||||||
|
} else if (account.equals("Cust")) {
|
||||||
|
long userId;
|
||||||
|
try {
|
||||||
|
userId = Long.parseLong(customer);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidFormDataException("Die angegebene Kunden-Nr. ist ungültig.");
|
||||||
|
}
|
||||||
|
return bookingAccountEntryRepository.getByUser(userId).or(() -> {
|
||||||
|
return userRepository.findById(userId).map((user) -> BookingAccountEntry.newUser(user));
|
||||||
|
}).orElseThrow(() -> {
|
||||||
|
return new InvalidFormDataException("Der Kunde Nr. " + userId + " konnte nicht gefunden werden.");
|
||||||
|
});
|
||||||
|
} else if (account.equals("Sup")) {
|
||||||
|
long supplierId;
|
||||||
|
try {
|
||||||
|
supplierId = Long.parseLong(supplier);
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
throw new InvalidFormDataException("Die angegebene Lieferanten-Nr. ist ungültig.");
|
||||||
|
}
|
||||||
|
return bookingAccountEntryRepository.getBySupplier(supplierId).or(() -> {
|
||||||
|
return supplierRepository.findById(supplierId).map((sup) -> BookingAccountEntry.newSupplier(sup));
|
||||||
|
}).orElseThrow(() -> {
|
||||||
|
return new InvalidFormDataException(
|
||||||
|
"Der Lieferant Nr. " + supplierId + " konnte nicht gefunden werden.");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("Invalid form value for an account: " + account);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/intern/accounting/addManual")
|
||||||
|
public String accountingAddManual(Model model) {
|
||||||
|
model.addAttribute("form_vals", new ManualAccounting());
|
||||||
|
return "intern/accounting/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/intern/accounting/addManual")
|
||||||
|
public String accountingAddManualSubmit(Model model, @ModelAttribute ManualAccounting formData) {
|
||||||
|
Booking booking;
|
||||||
|
try {
|
||||||
|
booking = createBooking(formData);
|
||||||
|
bookingRepository.save(booking);
|
||||||
|
model.addAttribute("info", "Die Buchung wurde erfolgreich erstellt.");
|
||||||
|
model.addAttribute("form_vals", new ManualAccounting()); // Reply with empty form on success
|
||||||
|
} catch (InvalidFormDataException e) {
|
||||||
|
model.addAttribute("error", e.getMessage());
|
||||||
|
model.addAttribute("form_vals", formData);
|
||||||
|
}
|
||||||
|
return "intern/accounting/addManual";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -4,8 +4,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.hso.ecommerce.controller.intern.AccountingController;
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
|
||||||
import org.hso.ecommerce.controller.intern.AccountingController.ShortTemplateBookingResult;
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult;
|
||||||
import org.hso.ecommerce.entities.booking.Booking;
|
import org.hso.ecommerce.entities.booking.Booking;
|
||||||
import org.hso.ecommerce.repos.booking.BookingRepository;
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -4,8 +4,8 @@ import java.util.List;
|
|||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.hso.ecommerce.controller.intern.AccountingController;
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController;
|
||||||
import org.hso.ecommerce.controller.intern.AccountingController.ShortTemplateBookingResult;
|
import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult;
|
||||||
import org.hso.ecommerce.entities.booking.Booking;
|
import org.hso.ecommerce.entities.booking.Booking;
|
||||||
import org.hso.ecommerce.repos.booking.BookingRepository;
|
import org.hso.ecommerce.repos.booking.BookingRepository;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
<main class="sidebar-layout content-width">
|
<main class="sidebar-layout content-width">
|
||||||
<nav th:replace="fragments/intern :: sidebar"></nav>
|
<nav th:replace="fragments/intern :: sidebar"></nav>
|
||||||
<div class="content-width">
|
<div class="content-width">
|
||||||
<form class="detailgrid">
|
<form th:action="@{/intern/accounting/addManual}" th:object="${form_vals}" method="post" class="detailgrid">
|
||||||
<div class="s">
|
<div class="s">
|
||||||
<label for="amount">Betrag</label>
|
<label for="amount">Betrag</label>
|
||||||
<input type="number" step="0.01" name="amount" value="0.00"/> EUR
|
<input type="number" step="0.01" th:field="*{amount}" /> EUR
|
||||||
</div>
|
</div>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
|
|
||||||
@ -31,26 +31,26 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="source">Von Konto:</label>
|
<label for="source">Von Konto:</label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-no" name="destination" value="None" required>
|
<input type="radio" id="s-no" th:field="*{source}" value="None" required>
|
||||||
<label for="s-no">Kein Konto</label>
|
<label for="s-no">Kein Konto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-main" name="destination" value="Main" required>
|
<input type="radio" id="s-main" th:field="*{source}" value="Main" required>
|
||||||
<label for="s-main">Hauptkonto</label>
|
<label for="s-main">Hauptkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-vat" name="destination" value="Vat" required>
|
<input type="radio" id="s-vat" th:field="*{source}" value="Vat" required>
|
||||||
<label for="s-vat">Mehrwertsteuerkonto</label>
|
<label for="s-vat">Mehrwertsteuerkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-cust" name="destination" value="Cust" required>
|
<input type="radio" id="s-cust" th:field="*{source}" value="Cust" required>
|
||||||
<label for="s-cust">Kundenkonto</label>
|
<label for="s-cust">Kundenkonto</label>
|
||||||
<input placeholder="Kunden Nr." type="text" name="destination-customer" value=""/>
|
<input placeholder="Kunden Nr." type="text" th:field="*{sourceCustomer}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="s-sup" name="destination" value="Sup" required>
|
<input type="radio" id="s-sup" th:field="*{source}" value="Sup" required>
|
||||||
<label for="s-sup">Lieferanten Konto</label>
|
<label for="s-sup">Lieferanten Konto</label>
|
||||||
<input placeholder="Lieferanten Nr." type="text" name="destination-sup" value=""/>
|
<input placeholder="Lieferanten Nr." type="text" th:field="*{sourceSupplier}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
@ -59,26 +59,26 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="destination">Nach Konto:</label>
|
<label for="destination">Nach Konto:</label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-no" name="destination" value="None" required>
|
<input type="radio" id="d-no" th:field="*{destination}" value="None" required>
|
||||||
<label for="d-no">Kein Konto</label>
|
<label for="d-no">Kein Konto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-main" name="destination" value="Main" required>
|
<input type="radio" id="d-main" th:field="*{destination}" value="Main" required>
|
||||||
<label for="d-main">Hauptkonto</label>
|
<label for="d-main">Hauptkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-vat" name="destination" value="Vat" required>
|
<input type="radio" id="d-vat" th:field="*{destination}" value="Vat" required>
|
||||||
<label for="d-vat">Mehrwertsteuerkonto</label>
|
<label for="d-vat">Mehrwertsteuerkonto</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-cust" name="destination" value="Cus" required>
|
<input type="radio" id="d-cust" th:field="*{destination}" value="Cust" required>
|
||||||
<label for="d-cust">Kundenkonto</label>
|
<label for="d-cust">Kundenkonto</label>
|
||||||
<input placeholder="Kunden Nr." type="text" name="destination-customer" value=""/>
|
<input placeholder="Kunden Nr." type="text" th:field="*{destinationCustomer}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" id="d-sup" name="destination" value="Sup" required>
|
<input type="radio" id="d-sup" th:field="*{destination}" value="Sup" required>
|
||||||
<label for="d-sup">Lieferanten Konto</label>
|
<label for="d-sup">Lieferanten Konto</label>
|
||||||
<input placeholder="Lieferanten Nr." type="text" name="destination-sup" value=""/>
|
<input placeholder="Lieferanten Nr." type="text" th:field="*{destinationSupplier}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
@ -87,13 +87,13 @@
|
|||||||
<fieldset>
|
<fieldset>
|
||||||
<label for="reason">Buchungsgrund:</label>
|
<label for="reason">Buchungsgrund:</label>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" name="reason" value="Start">
|
<input type="radio" id="r-start" th:field="*{reason}" value="Start">
|
||||||
<label for="d-sup">Startbuchung</label>
|
<label for="r-start">Startbuchung</label>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<input type="radio" name="reason" value="Manual" checked>
|
<input type="radio" id="r-manual" th:field="*{reason}" value="Manual">
|
||||||
<label for="d-sup">Manuell</label>
|
<label for="r-manual">Manuell</label>
|
||||||
<input placeholder="Grund" class="full-width" type="text" name="reason-man" value=""/>
|
<input placeholder="Grund" class="full-width" type="text" th:field="*{reasonText}" value=""/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user