package org.hso.ecommerce.controller.intern.accounting; 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.BookingRepository; 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 java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; @Controller public class AccountingController { @Autowired private BookingRepository bookingRepository = null; /** * A description used to render the html template for the overview of all bookings */ static class TemplateBooking { public String datetime; public String amount; public String source; public String sourceAddr; public String sourceBalance; public String destination; public String destinationAddr; public String destinationBalance; public String reason; public String reference; public String referenceAddr; } /** * A description used to render the html template for bookings on a specific account */ public static class ShortTemplateBooking { public String datetime; public String amount; public String source; public String sourceAddr; public String balance; public String reason; public String reference; public String referenceAddr; } public static class ShortTemplateBookingResult { public final String balance; public final List bookings; public ShortTemplateBookingResult(String balance, List bookings) { this.balance = balance; this.bookings = bookings; } } /** * Used to check which side of the booking (source or destination) is the account we are currently looking at. */ public interface AccountFilter { boolean matches(BookingAccountEntry account); } /** * Renders template information for the bookings of one specific account. * * @param bookings The (already fetched) booking entities to display * @param currentAccount A filter matching the account that is to be displayed * @return A collection result containing the final balance and all booking entries. */ public ShortTemplateBookingResult buildShortTemplate(List bookings, AccountFilter currentAccount) { List templateBookings = new ArrayList<>(); for (Booking booking : bookings) { ShortTemplateBooking tb = new ShortTemplateBooking(); tb.datetime = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(booking.created); tb.reason = booking.reason.comment; tb.reference = describeReference(booking.reason); tb.referenceAddr = linkToReference(booking.reason); if (booking.destination != null && currentAccount.matches(booking.destination)) { // Money was transferred onto the account we are looking at. tb.amount = fmtEuro(booking.amountCent); if (booking.source != null) { tb.source = describeAccount(booking.source); tb.sourceAddr = linkAddrOfAccount(booking.source); } else { tb.source = "-"; tb.sourceAddr = null; } tb.balance = fmtEuro(booking.destination.newSumCent); } else if (booking.source != null && currentAccount.matches(booking.source)) { // Money was transferred away from the account we are looking at. tb.amount = fmtEuro(-booking.amountCent); // Negative because of the transfer away if (booking.destination != null) { tb.source = describeAccount(booking.destination); // 'source' means 'the other account' in this case tb.sourceAddr = linkAddrOfAccount(booking.destination); } else { tb.source = "-"; tb.sourceAddr = null; } tb.balance = fmtEuro(booking.source.newSumCent); } else { throw new RuntimeException( "This booking should not appear in this list, because neither source nor destination is the account we are looking at."); } templateBookings.add(tb); } String balance = templateBookings.isEmpty() ? fmtEuro(0) : templateBookings.get(0).balance; return new ShortTemplateBookingResult(balance, templateBookings); } public static String fmtEuro(long amountCent) { return String.format("%.2f EUR", amountCent / 100.0); } private String describeAccount(BookingAccountEntry account) { if (account.isMainAccount) { return "Hauptkonto"; } else if (account.isVATAccount) { return "Mehrwertsteuer"; } else if (account.supplierAccount != null) { return "Lieferant " + account.supplierAccount.id; } else if (account.userAccount != null) { return "Kunde " + account.userAccount.id; } else { return "- unbekannt -"; } } private String linkAddrOfAccount(BookingAccountEntry account) { if (account.isMainAccount) { return "/intern/accounting/main"; } else if (account.isVATAccount) { return "/intern/accounting/vat"; } else if (account.supplierAccount != null) { return "/intern/suppliers/" + account.supplierAccount.id; } else if (account.userAccount != null) { return "/intern/customers/" + account.userAccount.id; } else { return null; } } private String describeReference(BookingReason reason) { if (reason.customerOrder != null) { return reason.customerOrder.id + ""; } else if (reason.customerPayment != null) { return "Bezahlung mit Kreditkarte " + reason.customerPayment.payment.creditCardNumber; } else if (reason.supplierOrder != null) { return "Lieferanten-Bestellung " + reason.supplierOrder.supplier.name; } else if (reason.supplierPayment != null) { return "Lieferanten-Zahlung " + reason.supplierPayment.name; } else { return "-"; } } private String linkToReference(BookingReason reason) { if (reason.customerOrder != null) { return "/intern/customerOrders/" + reason.customerOrder.id; } else if (reason.supplierPayment != null) { return "/intern/suppliers/#q=" + reason.supplierPayment.id; } else if (reason.supplierOrder != null) { return "/intern/supplierOrders/#q=" + reason.supplierOrder.id; } else { return null; } } @GetMapping("/intern/accounting/") public String accounting(Model model) { List bookings = bookingRepository.allBookingsReverseChronologically(); List templateBookings = new ArrayList<>(); for (Booking booking : bookings) { TemplateBooking tb = new TemplateBooking(); tb.datetime = new SimpleDateFormat("dd.MM.yyyy HH:mm").format(booking.created); tb.amount = fmtEuro(booking.amountCent); if (booking.source != null) { tb.source = describeAccount(booking.source); tb.sourceAddr = linkAddrOfAccount(booking.source); tb.sourceBalance = fmtEuro(booking.source.newSumCent); } else { tb.source = "-"; tb.sourceAddr = null; tb.sourceBalance = "-"; } if (booking.destination != null) { tb.destination = describeAccount(booking.destination); tb.destinationAddr = linkAddrOfAccount(booking.destination); tb.destinationBalance = fmtEuro(booking.destination.newSumCent); } else { tb.destination = "-"; tb.destinationAddr = null; tb.destinationBalance = "-"; } tb.reason = booking.reason.comment; tb.reference = describeReference(booking.reason); tb.referenceAddr = linkToReference(booking.reason); templateBookings.add(tb); } model.addAttribute("bookings", templateBookings); return "intern/accounting/index"; } @GetMapping("/intern/accounting/vat") public String accountingVat(Model model) { List bookings = bookingRepository.vatBookingsReverseChronologically(); ShortTemplateBookingResult result = buildShortTemplate(bookings, account -> account.isVATAccount); model.addAttribute("balance", result.balance); model.addAttribute("bookings", result.bookings); return "intern/accounting/vat"; } @GetMapping("/intern/accounting/main") public String accountingIntern(Model model) { List bookings = bookingRepository.mainBookingsReverseChronologically(); ShortTemplateBookingResult result = buildShortTemplate(bookings, account -> account.isMainAccount); model.addAttribute("balance", result.balance); model.addAttribute("bookings", result.bookings); return "intern/accounting/main"; } }