Skip to content

Commit 523054f

Browse files
committed
refactor: price-> VO(Money)로 변경, DB 레벨 제약을 위한 @column 추가
1 parent b20ba68 commit 523054f

16 files changed

Lines changed: 107 additions & 51 deletions

File tree

apps/commerce-api/src/main/java/com/loopers/application/order/OrderInfo.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.loopers.application.order;
22

3+
import com.loopers.domain.money.Money;
34
import com.loopers.domain.order.Order;
45
import com.loopers.domain.order.OrderItem;
56
import java.util.List;
@@ -20,7 +21,7 @@ public static OrderInfo from(Order order) {
2021
);
2122
}
2223

23-
public record OrderItemInfo(Long productId, int quantity, long price) {
24+
public record OrderItemInfo(Long productId, int quantity, Money price) {
2425

2526
public static OrderItemInfo from(OrderItem item) {
2627
return new OrderItemInfo(

apps/commerce-api/src/main/java/com/loopers/application/product/ProductInfo.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package com.loopers.application.product;
22

3+
import com.loopers.domain.money.Money;
34
import com.loopers.domain.product.Product;
45

56
public record ProductInfo(
67
Long id,
78
String name,
8-
long price,
9+
Money price,
910
String brandName
1011
) {
1112
public static ProductInfo from(Product product) {

apps/commerce-api/src/main/java/com/loopers/domain/like/Like.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.loopers.domain.BaseEntity;
44
import com.loopers.support.error.CoreException;
55
import com.loopers.support.error.ErrorType;
6+
import jakarta.persistence.Column;
67
import jakarta.persistence.Entity;
78
import jakarta.persistence.Table;
89
import jakarta.persistence.UniqueConstraint;
@@ -15,7 +16,10 @@
1516
)
1617
})
1718
public class Like extends BaseEntity {
19+
@Column(nullable = false)
1820
private Long userId;
21+
22+
@Column(nullable = false)
1923
private Long productId;
2024

2125
protected Like() {}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.loopers.domain.money;
2+
3+
import com.loopers.support.error.CoreException;
4+
import com.loopers.support.error.ErrorType;
5+
import jakarta.persistence.Embeddable;
6+
import lombok.AccessLevel;
7+
import lombok.EqualsAndHashCode;
8+
import lombok.NoArgsConstructor;
9+
10+
@Embeddable
11+
@EqualsAndHashCode
12+
@NoArgsConstructor(access = AccessLevel.PROTECTED)
13+
public class Money {
14+
15+
private Long value;
16+
17+
public Money(Long value) {
18+
if (value == null) {
19+
throw new CoreException(ErrorType.BAD_REQUEST);
20+
}
21+
if (value < 0) {
22+
throw new CoreException(ErrorType.BAD_REQUEST);
23+
}
24+
this.value = value;
25+
}
26+
27+
public Long getValue() {
28+
return value;
29+
}
30+
}

apps/commerce-api/src/main/java/com/loopers/domain/order/Order.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.loopers.support.error.CoreException;
66
import com.loopers.support.error.ErrorType;
77
import jakarta.persistence.CascadeType;
8+
import jakarta.persistence.Column;
89
import jakarta.persistence.Entity;
910
import jakarta.persistence.JoinColumn;
1011
import jakarta.persistence.OneToMany;
@@ -15,6 +16,7 @@
1516
@Table(name = "orders")
1617
public class Order extends BaseEntity {
1718

19+
@Column(nullable = false)
1820
private Long userId;
1921

2022
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)

apps/commerce-api/src/main/java/com/loopers/domain/order/OrderItem.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.loopers.domain.order;
22

33
import com.loopers.domain.BaseEntity;
4+
import com.loopers.domain.money.Money;
45
import com.loopers.domain.product.Product;
56
import jakarta.persistence.Entity;
67
import jakarta.persistence.Table;
@@ -11,7 +12,7 @@ public class OrderItem extends BaseEntity {
1112

1213
private Long productId;
1314
private Integer quantity;
14-
private Long price;
15+
private Money price;
1516

1617
protected OrderItem() {
1718
}
@@ -26,7 +27,7 @@ public OrderItem(Product product, int quantity) {
2627
}
2728

2829
public long calculateAmount() {
29-
return price * quantity;
30+
return price.getValue() * quantity;
3031
}
3132

3233
public Long getProductId() {
@@ -37,7 +38,7 @@ public Integer getQuantity() {
3738
return quantity;
3839
}
3940

40-
public Long getPrice() {
41+
public Money getPrice() {
4142
return price;
4243
}
4344
}

apps/commerce-api/src/main/java/com/loopers/domain/order/OrderService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public long calculateTotal(List<Product> products, List<OrderItemRequest> items)
3838

3939
for (OrderItemRequest item : items) {
4040
Product p = productMap.get(item.productId());
41-
total += p.getPrice() * item.quantity();
41+
total += p.getPrice().getValue() * item.quantity();
4242
}
4343
return total;
4444
}

apps/commerce-api/src/main/java/com/loopers/domain/product/Product.java

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,38 @@
11
package com.loopers.domain.product;
22

33
import com.loopers.domain.BaseEntity;
4+
import com.loopers.domain.money.Money;
45
import com.loopers.support.error.CoreException;
56
import com.loopers.support.error.ErrorType;
7+
import jakarta.persistence.Column;
8+
import jakarta.persistence.Embedded;
69
import jakarta.persistence.Entity;
710
import jakarta.persistence.Table;
811

912
@Entity
1013
@Table(name = "product")
1114
public class Product extends BaseEntity {
1215

16+
@Column(nullable = false)
1317
private Long brandId;
18+
19+
@Column(nullable = false)
1420
private String name;
21+
22+
@Column(nullable = false)
1523
private String description;
16-
private long price;
24+
25+
@Column(nullable = false)
26+
@Embedded
27+
private Money price;
28+
29+
@Column()
1730
private int stock;
1831

1932
protected Product() {
2033
}
2134

22-
public Product(Long brandId, String name, String description, long price, int stock) {
35+
public Product(Long brandId, String name, String description, Money price, int stock) {
2336
if (brandId == null) {
2437
throw new CoreException(ErrorType.BAD_REQUEST, "상품의 브랜드를 등록해야 합니다.");
2538
}
@@ -32,10 +45,6 @@ public Product(Long brandId, String name, String description, long price, int st
3245
throw new CoreException(ErrorType.BAD_REQUEST, "상품의 설명을 등록해야 합니다.");
3346
}
3447

35-
if (price < 0) {
36-
throw new CoreException(ErrorType.BAD_REQUEST, "상품의 가격은 음수가 될 수 없습니다.");
37-
}
38-
3948
if (stock < 0) {
4049
throw new CoreException(ErrorType.BAD_REQUEST, "상품의 재고는 음수가 될 수 없습니다.");
4150
}
@@ -59,7 +68,7 @@ public String getDescription() {
5968
return description;
6069
}
6170

62-
public long getPrice() {
71+
public Money getPrice() {
6372
return price;
6473
}
6574

apps/commerce-api/src/test/java/com/loopers/application/brand/BrandFacadeIntegrationTest.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import com.loopers.domain.brand.Brand;
77
import com.loopers.domain.brand.BrandRepository;
8+
import com.loopers.domain.money.Money;
89
import com.loopers.domain.product.Product;
910
import com.loopers.domain.product.ProductRepository;
1011
import com.loopers.support.error.CoreException;
@@ -52,9 +53,9 @@ void return_brandInfo_whenBrandAndProductsExist() {
5253
// arrange
5354
Brand brand = brandRepository.save(new Brand("Nike", "Just Do It."));
5455

55-
productRepository.save(new Product(brand.getId(), "Air Max", "설명1", 150000, 10));
56-
productRepository.save(new Product(brand.getId(), "Air Force", "설명2", 130000, 10));
57-
productRepository.save(new Product(brand.getId(), "Jordan", "설명3", 200000, 10));
56+
productRepository.save(new Product(brand.getId(), "Air Max", "설명1", new Money(150000L), 10));
57+
productRepository.save(new Product(brand.getId(), "Air Force", "설명2", new Money(130000L), 10));
58+
productRepository.save(new Product(brand.getId(), "Jordan", "설명3", new Money(200000L), 10));
5859

5960
Pageable pageable = PageRequest.of(0, 2, Sort.by(Sort.Direction.DESC, "createdAt"));
6061

apps/commerce-api/src/test/java/com/loopers/application/like/LikeFacadeIntegrationTest.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import static org.junit.jupiter.api.Assertions.assertAll;
55

66
import com.loopers.domain.like.LikeRepository;
7+
import com.loopers.domain.money.Money;
78
import com.loopers.domain.product.Product;
89
import com.loopers.domain.product.ProductRepository;
910
import com.loopers.domain.user.User;
@@ -51,7 +52,7 @@ class LikeProduct {
5152
void like_success_whenFirstLike() {
5253
// arrange
5354
User user = userRepository.save(new User("userA", "a@email.com", "2025-11-11", Gender.MALE));
54-
Product product = productRepository.save(new Product(1L, "상품A", "설명", 10000, 100));
55+
Product product = productRepository.save(new Product(1L, "상품A", "설명", new Money(10000L), 100));
5556

5657
// act
5758
LikeInfo result = likeFacade.like(user.getId(), product.getId());
@@ -72,7 +73,7 @@ void like_success_whenSecondLike() {
7273
// arrange
7374
User user1 = userRepository.save(new User("userA", "a@email.com", "2025-11-11", Gender.MALE));
7475
User user2 = userRepository.save(new User("userB", "b@email.com", "2025-11-11", Gender.FEMALE));
75-
Product product = productRepository.save(new Product(1L, "상품A", "설명", 10000, 100));
76+
Product product = productRepository.save(new Product(1L, "상품A", "설명", new Money(10000L), 100));
7677

7778
likeFacade.like(user1.getId(), product.getId());
7879

@@ -95,7 +96,7 @@ void like_success_whenSecondLike() {
9596
void like_idempotent_whenDuplicateRequest() {
9697
// arrange
9798
User user = userRepository.save(new User("userA", "a@email.com", "2025-11-11", Gender.MALE));
98-
Product product = productRepository.save(new Product(1L, "상품A", "설명", 10000, 100));
99+
Product product = productRepository.save(new Product(1L, "상품A", "설명", new Money(10000L), 100));
99100

100101
likeFacade.like(user.getId(), product.getId());
101102
assertThat(likeRepository.countByProductId(product.getId())).isEqualTo(1);
@@ -121,7 +122,7 @@ class UnlikeProduct {
121122
void unlike_success_and_returns_updated_count() {
122123
// arrange
123124
User user = userRepository.save(new User("userA", "a@email.com", "2025-11-11", Gender.MALE));
124-
Product product = productRepository.save(new Product(1L, "상품A", "설명", 10000, 100));
125+
Product product = productRepository.save(new Product(1L, "상품A", "설명", new Money(10000L), 100));
125126

126127
likeFacade.like(user.getId(), product.getId());
127128
assertThat(likeRepository.countByProductId(product.getId())).isEqualTo(1);

0 commit comments

Comments
 (0)