This repository has been archived on 2020-08-02. You can view files and clone it, but cannot push or open issues or pull requests.
e-commerce/web_backend/src/main/java/org/hso/ecommerce/action/shop/CreateOrderAction.java

210 lines
7.1 KiB
Java

package org.hso.ecommerce.action.shop;
import org.hso.ecommerce.action.booking.CreateBookingAction;
import org.hso.ecommerce.entities.booking.*;
import org.hso.ecommerce.entities.shop.Address;
import org.hso.ecommerce.entities.shop.Article;
import org.hso.ecommerce.entities.shop.CustomerOrder;
import org.hso.ecommerce.entities.shop.CustomerOrderPosition;
import org.hso.ecommerce.entities.user.User;
import org.hso.ecommerce.entities.warehouse.WarehouseBooking;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPosition;
import org.hso.ecommerce.entities.warehouse.WarehouseBookingPositionSlotEntry;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
public class CreateOrderAction {
private User user;
Address destination;
private int expectedTotalGrossCent;
private int totalNetCent;
private int totalVatCent;
private PaymentMethod method;
private BookingAccountEntry latestUserBooking;
private BookingAccountEntry latestVatBooking;
private BookingAccountEntry latestMainBooking;
private List<OrderItem> orderItems = new ArrayList<>();
public CreateOrderAction(
User user,
int expectedTotalGrossCent,
Address destination,
PaymentMethod method,
BookingAccountEntry latestUserBooking,
BookingAccountEntry latestVatBooking,
BookingAccountEntry latestMainBooking
) {
this.user = user;
this.expectedTotalGrossCent = expectedTotalGrossCent;
this.destination = destination;
this.method = method;
this.latestUserBooking = latestUserBooking;
assert latestUserBooking.userAccount.id == user.id;
this.latestVatBooking = latestVatBooking;
assert latestVatBooking.isVATAccount;
this.latestMainBooking = latestMainBooking;
assert latestMainBooking.isMainAccount;
}
public void addArticle(Article article, int quantity, List<WarehouseBookingPositionSlotEntry> availableSlots) {
for (WarehouseBookingPositionSlotEntry slot : availableSlots) {
assert slot.article.id == article.id;
}
orderItems.add(new OrderItem(article, availableSlots, quantity));
totalNetCent += article.shopPricePerUnitNetCent * quantity;
totalVatCent += article.getVat() * quantity;
}
public Result finish() throws ArticleNotInStockException {
CustomerOrder order = createOrder();
CustomerPayment payment = createPayment();
List<Booking> bookingList = new ArrayList<>();
Booking purchaseBooking = new CreateBookingAction(
latestUserBooking, latestMainBooking, new BookingReason(order), order.totalGrossCent).finish();
Booking paymentBooking = new CreateBookingAction(
null, purchaseBooking.source /* userAccount */, new BookingReason(payment), order.totalGrossCent).finish();
Booking vatBooking = new CreateBookingAction(
purchaseBooking.destination /* mainAccount */, latestVatBooking, new BookingReason(order), order.totalVatCent).finish();
bookingList.add(purchaseBooking);
bookingList.add(paymentBooking);
bookingList.add(vatBooking);
WarehouseBooking warehouseBooking = createWarehouseBooking(order);
return new Result(
order,
warehouseBooking,
bookingList
);
}
private WarehouseBooking createWarehouseBooking(CustomerOrder order) throws ArticleNotInStockException {
WarehouseBooking booking = new WarehouseBooking();
booking.created = new Timestamp(new Date().getTime());
booking.reason = new BookingReason(order);
for (OrderItem item : orderItems) {
int needed = item.quantity;
// Sort for most empty slot first;
item.availableSlots.sort(Comparator.comparingInt(a -> a.newSumSlot));
for (WarehouseBookingPositionSlotEntry slot : item.availableSlots) {
if (slot.newSumSlot == 0) {
continue;
}
int remove = Math.min(slot.newSumSlot, needed);
needed -= remove;
WarehouseBookingPosition bookingPosition = new WarehouseBookingPosition();
bookingPosition.article = item.article;
bookingPosition.amount = -remove;
bookingPosition.slotEntry = slot.copyAddAmount(-remove, item.article);
bookingPosition.booking = booking;
booking.positions.add(bookingPosition);
if (needed == 0) {
break;
}
}
if (needed > 0) {
throw new ArticleNotInStockException(item.article);
}
}
return booking;
}
private CustomerPayment createPayment() {
CustomerPayment payment = new CustomerPayment();
payment.amountCent = totalNetCent + totalVatCent;
payment.payment = method;
return payment;
}
private CustomerOrder createOrder() {
assert totalNetCent + totalVatCent == expectedTotalGrossCent;
CustomerOrder customerOrder = new CustomerOrder();
customerOrder.customer = user;
customerOrder.destination = destination;
for (OrderItem item : orderItems) {
CustomerOrderPosition position = new CustomerOrderPosition();
position.article = item.article;
position.pricePerUnit = item.article.shopPricePerUnitNetCent;
position.quantity = item.quantity;
position.order = customerOrder;
customerOrder.positions.add(position);
}
customerOrder.created = new Timestamp(new Date().getTime());
customerOrder.totalNetCent = totalNetCent;
customerOrder.totalVatCent = totalVatCent;
customerOrder.totalGrossCent = totalNetCent + totalVatCent;
return customerOrder;
}
public static class Result {
public final CustomerOrder customerOrder;
public final WarehouseBooking warehouseBooking;
public final List<Booking> bookings;
Result(CustomerOrder customerOrder, WarehouseBooking warehouseBooking, List<Booking> bookings) {
this.customerOrder = customerOrder;
this.warehouseBooking = warehouseBooking;
this.bookings = bookings;
}
}
private static class OrderItem {
List<WarehouseBookingPositionSlotEntry> availableSlots;
int quantity;
Article article;
public OrderItem(Article article, List<WarehouseBookingPositionSlotEntry> availableSlots, int quantity) {
this.article = article;
this.availableSlots = availableSlots;
this.quantity = quantity;
}
}
public static class ArticleNotInStockException extends Exception {
private Article article;
public ArticleNotInStockException(Article article) {
super("The quantity of article '" + article.title + "' is not in stock.");
this.article = article;
}
public Article getArticle() {
return article;
}
}
}