Port Round 2 to Java (OrderBook): 14 tests total green, START state preserved

This commit is contained in:
2026-10-01 13:38:42 +01:00
parent f927998149
commit 2831b8c3f9
5 changed files with 259 additions and 0 deletions
@@ -0,0 +1,42 @@
package orderbookdomain;
import java.time.Instant;
public class Order {
private final int id;
private final String customer;
private OrderStatus status;
private Instant finalizedAt;
Order(int id, String customer) {
this.id = id;
this.customer = customer;
this.status = OrderStatus.PENDING;
}
public int getId() {
return id;
}
public String getCustomer() {
return customer;
}
public OrderStatus getStatus() {
return status;
}
public Instant getFinalizedAt() {
return finalizedAt;
}
void setStatus(OrderStatus status) {
this.status = status;
}
void setFinalizedAt(Instant finalizedAt) {
this.finalizedAt = finalizedAt;
}
}
@@ -0,0 +1,81 @@
package orderbookdomain;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OrderBook {
private final Duration paymentWindow;
private final Map<Integer, Order> ordersById = new HashMap<>();
private int nextId = 1;
public OrderBook() {
this(Duration.ofDays(14));
}
public OrderBook(Duration paymentWindow) {
this.paymentWindow = paymentWindow;
}
public List<Order> getOrders() {
return List.copyOf(ordersById.values());
}
public Order openOrder(String customer) {
Order order = new Order(nextId++, customer);
ordersById.put(order.getId(), order);
return order;
}
public Order getOrder(int orderId) {
Order order = ordersById.get(orderId);
if (order == null) {
throw new IllegalStateException("Unknown order id " + orderId + ".");
}
return order;
}
public void finalizeOrder(int orderId, Instant finalizedAt) {
Order order = getOrder(orderId);
requireStatus(order, OrderStatus.PENDING, "finalize");
order.setStatus(OrderStatus.WAITING_FOR_PAYMENT);
order.setFinalizedAt(finalizedAt);
}
public void payOrder(int orderId, Instant paidAt) {
Order order = getOrder(orderId);
requireStatus(order, OrderStatus.WAITING_FOR_PAYMENT, "pay");
if (Duration.between(order.getFinalizedAt(), paidAt).compareTo(paymentWindow) > 0) {
order.setStatus(OrderStatus.CANCELLED);
throw new IllegalStateException(
"Payment for order " + orderId + " arrived after the payment window; the order was cancelled.");
}
order.setStatus(OrderStatus.FULFILLING);
}
public void shipOrder(int orderId) {
Order order = getOrder(orderId);
requireStatus(order, OrderStatus.FULFILLING, "ship");
order.setStatus(OrderStatus.DELIVERED);
}
public void cancelOrder(int orderId) {
Order order = getOrder(orderId);
if (order.getStatus() != OrderStatus.PENDING && order.getStatus() != OrderStatus.WAITING_FOR_PAYMENT) {
throw new IllegalStateException(
"Cannot cancel order " + orderId + " in status " + order.getStatus() + ".");
}
order.setStatus(OrderStatus.CANCELLED);
}
private static void requireStatus(Order order, OrderStatus expected, String action) {
if (order.getStatus() != expected) {
throw new IllegalStateException(
"Cannot " + action + " order " + order.getId() + " in status " + order.getStatus()
+ " (expected " + expected + ").");
}
}
}
@@ -0,0 +1,9 @@
package orderbookdomain;
public enum OrderStatus {
PENDING,
WAITING_FOR_PAYMENT,
FULFILLING,
DELIVERED,
CANCELLED
}