210 lines
7.1 KiB
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;
|
|
}
|
|
}
|
|
}
|