From e53c1e087268a5cf871211df7dc6806aba360d7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20F=C3=BCrderer?= Date: Fri, 5 Jun 2020 18:45:25 +0200 Subject: [PATCH] Allow the user to create manual bookings --- .../AccountingController.java | 7 +- .../ManualAccountingController.java | 259 ++++++++++++++++++ .../customers/CustomersIndexController.java | 4 +- .../suppliers/SupplierIndexController.java | 4 +- .../intern/accounting/addManual.html | 42 +-- 5 files changed, 285 insertions(+), 31 deletions(-) rename prototype/src/main/java/org/hso/ecommerce/controller/intern/{ => accounting}/AccountingController.java (98%) create mode 100644 prototype/src/main/java/org/hso/ecommerce/controller/intern/accounting/ManualAccountingController.java diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/intern/AccountingController.java b/prototype/src/main/java/org/hso/ecommerce/controller/intern/accounting/AccountingController.java similarity index 98% rename from prototype/src/main/java/org/hso/ecommerce/controller/intern/AccountingController.java rename to prototype/src/main/java/org/hso/ecommerce/controller/intern/accounting/AccountingController.java index b425452..367995b 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/intern/AccountingController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/intern/accounting/AccountingController.java @@ -1,4 +1,4 @@ -package org.hso.ecommerce.controller.intern; +package org.hso.ecommerce.controller.intern.accounting; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -221,9 +221,4 @@ public class AccountingController { request.setAttribute("bookings", result.bookings); return "intern/accounting/main"; } - - @GetMapping("/intern/accounting/addManual") - public String accountingAddManual() { - return "intern/accounting/addManual"; - } } diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/intern/accounting/ManualAccountingController.java b/prototype/src/main/java/org/hso/ecommerce/controller/intern/accounting/ManualAccountingController.java new file mode 100644 index 0000000..5376e25 --- /dev/null +++ b/prototype/src/main/java/org/hso/ecommerce/controller/intern/accounting/ManualAccountingController.java @@ -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"; + } + +} diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/intern/customers/CustomersIndexController.java b/prototype/src/main/java/org/hso/ecommerce/controller/intern/customers/CustomersIndexController.java index a27d407..cbda950 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/intern/customers/CustomersIndexController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/intern/customers/CustomersIndexController.java @@ -4,8 +4,8 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; -import org.hso.ecommerce.controller.intern.AccountingController; -import org.hso.ecommerce.controller.intern.AccountingController.ShortTemplateBookingResult; +import org.hso.ecommerce.controller.intern.accounting.AccountingController; +import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult; import org.hso.ecommerce.entities.booking.Booking; import org.hso.ecommerce.repos.booking.BookingRepository; import org.springframework.beans.factory.annotation.Autowired; diff --git a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierIndexController.java b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierIndexController.java index 20c29f3..500843f 100644 --- a/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierIndexController.java +++ b/prototype/src/main/java/org/hso/ecommerce/controller/intern/suppliers/SupplierIndexController.java @@ -4,8 +4,8 @@ import java.util.List; import javax.servlet.http.HttpServletRequest; -import org.hso.ecommerce.controller.intern.AccountingController; -import org.hso.ecommerce.controller.intern.AccountingController.ShortTemplateBookingResult; +import org.hso.ecommerce.controller.intern.accounting.AccountingController; +import org.hso.ecommerce.controller.intern.accounting.AccountingController.ShortTemplateBookingResult; import org.hso.ecommerce.entities.booking.Booking; import org.hso.ecommerce.repos.booking.BookingRepository; import org.springframework.beans.factory.annotation.Autowired; diff --git a/prototype/src/main/resources/templates/intern/accounting/addManual.html b/prototype/src/main/resources/templates/intern/accounting/addManual.html index d872206..bed16ca 100644 --- a/prototype/src/main/resources/templates/intern/accounting/addManual.html +++ b/prototype/src/main/resources/templates/intern/accounting/addManual.html @@ -20,10 +20,10 @@
-
+
-  EUR +  EUR
@@ -31,26 +31,26 @@
- +
- +
- +
- + - +
- + - +
@@ -59,26 +59,26 @@
- +
- +
- +
- + - +
- + - +
@@ -87,13 +87,13 @@
- - + +
- - - + + +