BAEL-2275: Add OrderItem
This commit is contained in:
parent
fbd2c58844
commit
3cde05a6ed
|
@ -7,7 +7,7 @@ import org.springframework.context.annotation.PropertySource;
|
|||
@SpringBootApplication
|
||||
@PropertySource(value = { "classpath:ddd-layers.properties" })
|
||||
public class DomainLayerApplication {
|
||||
public static void main(String[] args) {
|
||||
public static void main(final String[] args) {
|
||||
SpringApplication.run(DomainLayerApplication.class, args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/orders")
|
||||
public class OrderController {
|
||||
|
@ -33,8 +35,8 @@ public class OrderController {
|
|||
}
|
||||
|
||||
@DeleteMapping(value = "/{id}/products", consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
|
||||
void deleteProduct(@PathVariable final ObjectId id, @RequestParam final String name) {
|
||||
orderService.deleteProduct(id, name);
|
||||
void deleteProduct(@PathVariable final ObjectId id, @RequestParam final UUID productId) {
|
||||
orderService.deleteProduct(id, productId);
|
||||
}
|
||||
|
||||
@PostMapping("/{id}/complete")
|
||||
|
|
|
@ -10,7 +10,7 @@ public class CreateOrderRequest {
|
|||
@NotNull private Product product;
|
||||
|
||||
@JsonCreator
|
||||
public CreateOrderRequest(@JsonProperty("product") @NotNull Product product) {
|
||||
public CreateOrderRequest(@JsonProperty("product") @NotNull final Product product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ import org.bson.types.ObjectId;
|
|||
public class CreateOrderResponse {
|
||||
private final String id;
|
||||
|
||||
public CreateOrderResponse(String id) {
|
||||
public CreateOrderResponse(final String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
package com.baeldung.ddd.layers.domain;
|
||||
|
||||
class DomainException extends RuntimeException {
|
||||
DomainException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -1,22 +1,22 @@
|
|||
package com.baeldung.ddd.layers.domain;
|
||||
|
||||
import com.baeldung.ddd.layers.domain.exception.DomainException;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Order {
|
||||
private final ObjectId id;
|
||||
private OrderStatus status;
|
||||
private List<Product> products;
|
||||
private List<OrderItem> orderItems;
|
||||
private BigDecimal price;
|
||||
|
||||
public Order(final ObjectId id, final Product product) {
|
||||
this.id = id;
|
||||
this.products = new ArrayList<>(Collections.singletonList(product));
|
||||
this.orderItems = new ArrayList<>(Collections.singletonList(new OrderItem(product)));
|
||||
this.status = OrderStatus.CREATED;
|
||||
this.price = product.getPrice();
|
||||
}
|
||||
|
@ -26,29 +26,30 @@ public class Order {
|
|||
this.status = OrderStatus.COMPLETED;
|
||||
}
|
||||
|
||||
public void addProduct(final Product product) {
|
||||
public void addOrder(final Product product) {
|
||||
validateState();
|
||||
validateProduct(product);
|
||||
products.add(product);
|
||||
orderItems.add(new OrderItem(product));
|
||||
price = price.add(product.getPrice());
|
||||
}
|
||||
|
||||
public void removeProduct(final String name) {
|
||||
public void removeOrder(final UUID id) {
|
||||
validateState();
|
||||
final Product product = getProduct(name);
|
||||
products.remove(product);
|
||||
final OrderItem orderItem = getOrderItem(id);
|
||||
orderItems.remove(orderItem);
|
||||
|
||||
price = price.subtract(product.getPrice());
|
||||
price = price.subtract(orderItem.getPrice());
|
||||
}
|
||||
|
||||
private Product getProduct(String name) {
|
||||
return products
|
||||
private OrderItem getOrderItem(final UUID id) {
|
||||
return orderItems
|
||||
.stream()
|
||||
.filter(product -> product
|
||||
.getName()
|
||||
.equals(name))
|
||||
.filter(orderItem -> orderItem
|
||||
.getProduct()
|
||||
.getId()
|
||||
.equals(id))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new DomainException("Product with " + name + " doesn't exist."));
|
||||
.orElseThrow(() -> new DomainException("Product with " + id + " doesn't exist."));
|
||||
}
|
||||
|
||||
private void validateState() {
|
||||
|
@ -71,11 +72,11 @@ public class Order {
|
|||
return status;
|
||||
}
|
||||
|
||||
public List<Product> getProducts() {
|
||||
return Collections.unmodifiableList(products);
|
||||
}
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public List<OrderItem> getOrderItems() {
|
||||
return orderItems;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
package com.baeldung.ddd.layers.domain;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
|
||||
public class OrderItem {
|
||||
private final Product product;
|
||||
|
||||
public OrderItem(final Product product) {
|
||||
this.product = product;
|
||||
}
|
||||
|
||||
public BigDecimal getPrice() {
|
||||
return product.getPrice();
|
||||
}
|
||||
|
||||
public Product getProduct() {
|
||||
return product;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
OrderItem orderItem = (OrderItem) o;
|
||||
return Objects.equals(product, orderItem.product);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(product);
|
||||
}
|
||||
}
|
|
@ -5,13 +5,16 @@ import com.fasterxml.jackson.annotation.JsonProperty;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class Product {
|
||||
private final UUID id;
|
||||
private final BigDecimal price;
|
||||
private final String name;
|
||||
|
||||
@JsonCreator
|
||||
public Product(@JsonProperty("price") final BigDecimal price, @JsonProperty("name") final String name) {
|
||||
public Product(@JsonProperty("id") final UUID id, @JsonProperty("price") final BigDecimal price, @JsonProperty("name") final String name) {
|
||||
this.id = id;
|
||||
this.price = price;
|
||||
this.name = name;
|
||||
}
|
||||
|
@ -24,20 +27,20 @@ public class Product {
|
|||
return name;
|
||||
}
|
||||
|
||||
public UUID getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
final Product product = (Product) o;
|
||||
return Objects.equals(price, product.price) && Objects.equals(name, product.name);
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
Product product = (Product) o;
|
||||
return Objects.equals(id, product.id) && Objects.equals(price, product.price) && Objects.equals(name, product.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(price, name);
|
||||
return Objects.hash(id, price, name);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
package com.baeldung.ddd.layers.domain.exception;
|
||||
|
||||
public class DomainException extends RuntimeException {
|
||||
public DomainException(final String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
|
@ -5,11 +5,13 @@ import com.baeldung.ddd.layers.domain.Product;
|
|||
import com.baeldung.ddd.layers.domain.repository.OrderRepository;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class DomainOrderService implements OrderService {
|
||||
|
||||
private final OrderRepository orderRepository;
|
||||
|
||||
public DomainOrderService(OrderRepository orderRepository) {
|
||||
public DomainOrderService(final OrderRepository orderRepository) {
|
||||
this.orderRepository = orderRepository;
|
||||
}
|
||||
|
||||
|
@ -22,15 +24,15 @@ public class DomainOrderService implements OrderService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addProduct(ObjectId id, Product product) {
|
||||
public void addProduct(final ObjectId id, final Product product) {
|
||||
final Order order = getOrder(id);
|
||||
order.addProduct(product);
|
||||
order.addOrder(product);
|
||||
|
||||
orderRepository.save(order);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeOrder(ObjectId id) {
|
||||
public void completeOrder(final ObjectId id) {
|
||||
final Order order = getOrder(id);
|
||||
order.complete();
|
||||
|
||||
|
@ -38,9 +40,9 @@ public class DomainOrderService implements OrderService {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void deleteProduct(ObjectId id, String name) {
|
||||
public void deleteProduct(final ObjectId id, final UUID productId) {
|
||||
final Order order = getOrder(id);
|
||||
order.removeProduct(name);
|
||||
order.removeOrder(productId);
|
||||
|
||||
orderRepository.save(order);
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@ package com.baeldung.ddd.layers.domain.service;
|
|||
import com.baeldung.ddd.layers.domain.Product;
|
||||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public interface OrderService {
|
||||
ObjectId createOrder(final Product product);
|
||||
|
||||
|
@ -10,5 +12,5 @@ public interface OrderService {
|
|||
|
||||
void completeOrder(ObjectId id);
|
||||
|
||||
void deleteProduct(ObjectId id, String name);
|
||||
void deleteProduct(ObjectId id, UUID productId);
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.springframework.context.annotation.Configuration;
|
|||
|
||||
@Configuration
|
||||
@ComponentScan(basePackageClasses = DomainLayerApplication.class)
|
||||
public class DomainConfiguration {
|
||||
public class BeanConfiguration {
|
||||
|
||||
@Bean
|
||||
OrderService orderService(final OrderRepository orderRepository) {
|
|
@ -3,10 +3,11 @@ package com.baeldung.ddd.layers.domain;
|
|||
import org.bson.types.ObjectId;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.UUID;
|
||||
|
||||
public class OrderProvider {
|
||||
public static Order getCreatedOrder() {
|
||||
return new Order(ObjectId.get(), new Product(BigDecimal.TEN, "productName"));
|
||||
return new Order(ObjectId.get(), new Product(UUID.randomUUID(), BigDecimal.TEN, "productName"));
|
||||
}
|
||||
|
||||
public static Order getCompletedOrder() {
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
package com.baeldung.ddd.layers.domain;
|
||||
|
||||
import com.baeldung.ddd.layers.domain.exception.DomainException;
|
||||
import org.bson.types.ObjectId;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.function.Executable;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Arrays;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
|
@ -25,22 +23,26 @@ class OrderUnitTest {
|
|||
@Test
|
||||
void shouldAddProduct_thenUpdatePrice() {
|
||||
final Order order = OrderProvider.getCreatedOrder();
|
||||
final int orderOriginalProductSize = order.getProducts().size();
|
||||
final int orderOriginalProductSize = order
|
||||
.getOrderItems()
|
||||
.size();
|
||||
final BigDecimal orderOriginalPrice = order.getPrice();
|
||||
final Product productToAdd = new Product(new BigDecimal("20"), "secondProduct");
|
||||
final Product productToAdd = new Product(UUID.randomUUID(), new BigDecimal("20"), "secondProduct");
|
||||
|
||||
order.addProduct(productToAdd);
|
||||
order.addOrder(productToAdd);
|
||||
|
||||
assertEquals(orderOriginalProductSize + 1, order.getProducts().size());
|
||||
assertEquals(orderOriginalProductSize + 1, order
|
||||
.getOrderItems()
|
||||
.size());
|
||||
assertEquals(orderOriginalPrice.add(productToAdd.getPrice()), order.getPrice());
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddProduct_thenThrowException() {
|
||||
final Order order = OrderProvider.getCompletedOrder();
|
||||
final Product productToAdd = new Product(new BigDecimal("20"), "secondProduct");
|
||||
final Product productToAdd = new Product(UUID.randomUUID(), new BigDecimal("20"), "secondProduct");
|
||||
|
||||
final Executable executable = () -> order.addProduct(productToAdd);
|
||||
final Executable executable = () -> order.addOrder(productToAdd);
|
||||
|
||||
Assertions.assertThrows(DomainException.class, executable);
|
||||
}
|
||||
|
@ -49,9 +51,15 @@ class OrderUnitTest {
|
|||
void shouldRemoveProduct_thenUpdatePrice() {
|
||||
final Order order = OrderProvider.getCreatedOrder();
|
||||
|
||||
order.removeProduct(order.getProducts().get(0).getName());
|
||||
order.removeOrder(order
|
||||
.getOrderItems()
|
||||
.get(0)
|
||||
.getProduct()
|
||||
.getId());
|
||||
|
||||
assertEquals(0, order.getProducts().size());
|
||||
assertEquals(0, order
|
||||
.getOrderItems()
|
||||
.size());
|
||||
assertEquals(BigDecimal.ZERO, order.getPrice());
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import org.junit.jupiter.api.function.Executable;
|
|||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
@ -30,7 +31,7 @@ class DomainOrderServiceUnitTest {
|
|||
|
||||
@Test
|
||||
void shouldCreateOrder_thenSaveIt() {
|
||||
final Product product = new Product(BigDecimal.TEN, "productName");
|
||||
final Product product = new Product(UUID.randomUUID(), BigDecimal.TEN, "productName");
|
||||
|
||||
final ObjectId id = tested.createOrder(product);
|
||||
|
||||
|
@ -41,18 +42,18 @@ class DomainOrderServiceUnitTest {
|
|||
@Test
|
||||
void shouldAddProduct_thenSaveOrder() {
|
||||
final Order order = spy(OrderProvider.getCreatedOrder());
|
||||
final Product product = new Product(BigDecimal.TEN, "test");
|
||||
final Product product = new Product(UUID.randomUUID(), BigDecimal.TEN, "test");
|
||||
when(orderRepository.findById(order.getId())).thenReturn(Optional.of(order));
|
||||
|
||||
tested.addProduct(order.getId(), product);
|
||||
|
||||
verify(orderRepository).save(order);
|
||||
verify(order).addProduct(product);
|
||||
verify(order).addOrder(product);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldAddProduct_thenThrowException() {
|
||||
final Product product = new Product(BigDecimal.TEN, "test");
|
||||
final Product product = new Product(UUID.randomUUID(), BigDecimal.TEN, "test");
|
||||
final ObjectId id = ObjectId.get();
|
||||
when(orderRepository.findById(id)).thenReturn(Optional.empty());
|
||||
|
||||
|
@ -76,15 +77,16 @@ class DomainOrderServiceUnitTest {
|
|||
@Test
|
||||
void shouldDeleteProduct_thenSaveOrder() {
|
||||
final Order order = spy(OrderProvider.getCreatedOrder());
|
||||
final String productName = order
|
||||
.getProducts()
|
||||
final UUID productId = order
|
||||
.getOrderItems()
|
||||
.get(0)
|
||||
.getName();
|
||||
.getProduct()
|
||||
.getId();
|
||||
when(orderRepository.findById(order.getId())).thenReturn(Optional.of(order));
|
||||
|
||||
tested.deleteProduct(order.getId(), productName);
|
||||
tested.deleteProduct(order.getId(), productId);
|
||||
|
||||
verify(orderRepository).save(order);
|
||||
verify(order).removeProduct(productName);
|
||||
verify(order).removeOrder(productId);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue