Skip to content

Commit

Permalink
Merge pull request #47 from taco-official/KL-131/상품에-평점-필드-추가
Browse files Browse the repository at this point in the history
feat(KL-131): add rating field to product
  • Loading branch information
ohhamma authored Aug 15, 2024
2 parents 3965515 + 35933f0 commit aca6e93
Show file tree
Hide file tree
Showing 20 changed files with 284 additions and 21 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package taco.klkl.domain.product.converter;

import java.math.BigDecimal;

import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import taco.klkl.domain.product.domain.Rating;

@Converter(autoApply = true)
public class RatingConverter implements AttributeConverter<Rating, BigDecimal> {

@Override
public BigDecimal convertToDatabaseColumn(final Rating attribute) {
if (attribute == null) {
return null;
}
return BigDecimal.valueOf(attribute.getValue());
}

@Override
public Rating convertToEntityAttribute(final BigDecimal dbData) {
if (dbData == null) {
return null;
}
return Rating.from(dbData.doubleValue());
}
}
18 changes: 17 additions & 1 deletion src/main/java/taco/klkl/domain/product/domain/Product.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
Expand All @@ -23,6 +24,7 @@
import lombok.NoArgsConstructor;
import taco.klkl.domain.category.domain.Filter;
import taco.klkl.domain.category.domain.Subcategory;
import taco.klkl.domain.product.converter.RatingConverter;
import taco.klkl.domain.region.domain.City;
import taco.klkl.domain.region.domain.Currency;
import taco.klkl.domain.user.domain.User;
Expand Down Expand Up @@ -76,6 +78,15 @@ public class Product {
@ColumnDefault(DefaultConstants.DEFAULT_INT_STRING)
private Integer likeCount;

@Convert(converter = RatingConverter.class)
@Column(
name = "rating",
precision = 3,
scale = 1,
nullable = false
)
private Rating rating;

@ManyToOne(
fetch = FetchType.LAZY,
optional = false
Expand Down Expand Up @@ -145,6 +156,7 @@ private Product(
final String description,
final String address,
final Integer price,
final Rating rating,
final User user,
final City city,
final Subcategory subcategory,
Expand All @@ -154,6 +166,7 @@ private Product(
this.description = description;
this.address = address;
this.price = price;
this.rating = rating;
this.user = user;
this.city = city;
this.subcategory = subcategory;
Expand All @@ -167,19 +180,21 @@ public static Product of(
final String description,
final String address,
final Integer price,
final Rating rating,
final User user,
final City city,
final Subcategory subcategory,
final Currency currency
) {
return new Product(name, description, address, price, user, city, subcategory, currency);
return new Product(name, description, address, price, rating, user, city, subcategory, currency);
}

public void update(
final String name,
final String description,
final String address,
final Integer price,
final Rating rating,
final City city,
final Subcategory subcategory,
final Currency currency
Expand All @@ -188,6 +203,7 @@ public void update(
this.description = description;
this.address = address;
this.price = price;
this.rating = rating;
this.city = city;
this.subcategory = subcategory;
this.currency = currency;
Expand Down
34 changes: 34 additions & 0 deletions src/main/java/taco/klkl/domain/product/domain/Rating.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package taco.klkl.domain.product.domain;

import java.util.Arrays;

import lombok.Getter;
import taco.klkl.domain.product.exception.RatingNotFoundException;

@Getter
public enum Rating {
ZERO_FIVE(0.5),
ONE(1.0),
ONE_FIVE(1.5),
TWO(2.0),
TWO_FIVE(2.5),
THREE(3.0),
THREE_FIVE(3.5),
FOUR(4.0),
FOUR_FIVE(4.5),
FIVE(5.0),
;

private final double value;

Rating(double value) {
this.value = value;
}

public static Rating from(final double value) {
return Arrays.stream(Rating.values())
.filter(r -> r.value == value)
.findFirst()
.orElseThrow(RatingNotFoundException::new);
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
package taco.klkl.domain.product.dto.request;

import static taco.klkl.global.common.constants.ProductConstants.*;
import static taco.klkl.global.common.constants.ProductValidationMessages.*;

import java.util.Set;

import jakarta.validation.constraints.DecimalMax;
import jakarta.validation.constraints.DecimalMin;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.PositiveOrZero;
import jakarta.validation.constraints.Size;
import taco.klkl.global.common.constants.ProductConstants;
import taco.klkl.global.common.constants.ProductValidationMessages;

/**
* TODO: 상품필터속성 추가 해야함 (상품필터속성 테이블 개발 후)
Expand All @@ -21,31 +25,36 @@
* @param currencyId
*/
public record ProductCreateUpdateRequestDto(
@NotNull(message = ProductValidationMessages.NAME_NOT_NULL)
@NotBlank(message = ProductValidationMessages.NAME_NOT_BLANK)
@Size(max = ProductConstants.NAME_MAX_LENGTH, message = ProductValidationMessages.NAME_SIZE)
@NotNull(message = NAME_NOT_NULL)
@NotBlank(message = NAME_NOT_BLANK)
@Size(max = ProductConstants.NAME_MAX_LENGTH, message = NAME_SIZE)
String name,

@NotNull(message = ProductValidationMessages.DESCRIPTION_NOT_NULL)
@NotBlank(message = ProductValidationMessages.DESCRIPTION_NOT_BLANK)
@Size(max = ProductConstants.DESCRIPTION_MAX_LENGTH, message = ProductValidationMessages.DESCRIPTION_SIZE)
@NotNull(message = DESCRIPTION_NOT_NULL)
@NotBlank(message = DESCRIPTION_NOT_BLANK)
@Size(max = ProductConstants.DESCRIPTION_MAX_LENGTH, message = DESCRIPTION_SIZE)
String description,

@NotNull(message = ProductValidationMessages.ADDRESS_NOT_NULL)
@Size(max = ProductConstants.ADDRESS_MAX_LENGTH, message = ProductValidationMessages.ADDRESS_SIZE)
@NotNull(message = ADDRESS_NOT_NULL)
@Size(max = ProductConstants.ADDRESS_MAX_LENGTH, message = ADDRESS_SIZE)
String address,

@NotNull(message = ProductValidationMessages.PRICE_NOT_NULL)
@PositiveOrZero(message = ProductValidationMessages.PRICE_POSITIVE_OR_ZERO)
@NotNull(message = PRICE_NOT_NULL)
@PositiveOrZero(message = PRICE_POSITIVE_OR_ZERO)
Integer price,

@NotNull(message = ProductValidationMessages.CITY_ID_NOT_NULL)
@NotNull(message = RATING_NOT_NULL)
@DecimalMin(value = RATING_MIN_VALUE, message = RATING_UNDER_MIN)
@DecimalMax(value = RATING_MAX_VALUE, message = RATING_OVER_MAX)
Double rating,

@NotNull(message = CITY_ID_NOT_NULL)
Long cityId,

@NotNull(message = ProductValidationMessages.SUBCATEGORY_ID_NOT_NULL)
@NotNull(message = SUBCATEGORY_ID_NOT_NULL)
Long subcategoryId,

@NotNull(message = ProductValidationMessages.CURRENCY_ID_NOT_NULL)
@NotNull(message = CURRENCY_ID_NOT_NULL)
Long currencyId,

Set<Long> filterIds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
* @param address
* @param price
* @param likeCount
* @param rating
* @param user
* @param city
* @param subcategory
Expand All @@ -35,8 +36,9 @@ public record ProductDetailResponseDto(
String name,
String description,
String address,
int price,
int likeCount,
Integer price,
Integer likeCount,
Double rating,
UserDetailResponseDto user,
CityResponseDto city,
SubcategoryResponseDto subcategory,
Expand All @@ -61,6 +63,7 @@ public static ProductDetailResponseDto from(Product product) {
product.getAddress(),
product.getPrice(),
product.getLikeCount(),
product.getRating().getValue(),
UserDetailResponseDto.from(product.getUser()),
CityResponseDto.from(product.getCity()),
SubcategoryResponseDto.from(product.getSubcategory()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@
* @param id
* @param name
* @param likeCount
* @param rating
* @param countryName
* @param categoryName
*/
public record ProductSimpleResponseDto(
Long id,
String name,
int likeCount,
Integer likeCount,
Double rating,
String countryName,
String categoryName,
Set<FilterResponseDto> filters
Expand All @@ -35,6 +37,7 @@ public static ProductSimpleResponseDto from(Product product) {
product.getId(),
product.getName(),
product.getLikeCount(),
product.getRating().getValue(),
product.getCity().getCountry().getName().getKoreanName(),
product.getSubcategory().getCategory().getName().getKoreanName(),
filters
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package taco.klkl.domain.product.exception;

import taco.klkl.global.error.exception.CustomException;
import taco.klkl.global.error.exception.ErrorCode;

public class RatingNotFoundException extends CustomException {
public RatingNotFoundException() {
super(ErrorCode.RATING_NOT_FOUND);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import taco.klkl.domain.product.domain.Product;
import taco.klkl.domain.product.domain.QProduct;
import taco.klkl.domain.product.domain.QProductFilter;
import taco.klkl.domain.product.domain.Rating;
import taco.klkl.domain.product.dto.request.ProductCreateUpdateRequestDto;
import taco.klkl.domain.product.dto.request.ProductFilterOptionsDto;
import taco.klkl.domain.product.dto.response.ProductDetailResponseDto;
Expand Down Expand Up @@ -153,6 +154,7 @@ private Set<Filter> getFiltersByFilterIds(final Set<Long> filterIds) {
}

private Product createProductEntity(final ProductCreateUpdateRequestDto createRequest) {
final Rating rating = Rating.from(createRequest.rating());
final User user = userUtil.findTestUser();
final City city = getCityEntity(createRequest.cityId());
final Subcategory subcategory = getSubcategoryEntity(createRequest.subcategoryId());
Expand All @@ -163,6 +165,7 @@ private Product createProductEntity(final ProductCreateUpdateRequestDto createRe
createRequest.description(),
createRequest.address(),
createRequest.price(),
rating,
user,
city,
subcategory,
Expand All @@ -171,6 +174,7 @@ private Product createProductEntity(final ProductCreateUpdateRequestDto createRe
}

private void updateProductEntity(final Product product, final ProductCreateUpdateRequestDto updateRequest) {
final Rating rating = Rating.from(updateRequest.rating());
final City city = getCityEntity(updateRequest.cityId());
final Subcategory subcategory = getSubcategoryEntity(updateRequest.subcategoryId());
final Currency currency = getCurrencyEntity(updateRequest.currencyId());
Expand All @@ -180,6 +184,7 @@ private void updateProductEntity(final Product product, final ProductCreateUpdat
updateRequest.description(),
updateRequest.address(),
updateRequest.price(),
rating,
city,
subcategory,
currency
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ public final class ProductConstants {
public static final int DESCRIPTION_MAX_LENGTH = 2000;
public static final int ADDRESS_MAX_LENGTH = 100;

public static final String RATING_MIN_VALUE = "0.5";
public static final String RATING_MAX_VALUE = "5.0";

private ProductConstants() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ public final class ProductValidationMessages {
public static final String PRICE_NOT_NULL = "가격은 필수 항목입니다.";
public static final String PRICE_POSITIVE_OR_ZERO = "가격은 0 이상이어야 합니다.";

public static final String RATING_NOT_NULL = "평점은 필수 항목입니다.";
public static final String RATING_UNDER_MIN = "평점은 0.5점보다 낮을 수 없습니다.";
public static final String RATING_OVER_MAX = "평점은 5.0점보다 높을 수 없습니다";

public static final String CITY_ID_NOT_NULL = "도시 ID는 필수 항목입니다.";
public static final String SUBCATEGORY_ID_NOT_NULL = "상품 소분류 ID는 필수 항목입니다.";
public static final String CURRENCY_ID_NOT_NULL = "통화 ID는 필수 항목입니다.";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public enum ErrorCode {
// Product
PRODUCT_NOT_FOUND(HttpStatus.NOT_FOUND, "C020", "존재하지 않는 상품입니다."),
INVALID_CITY_IDS(HttpStatus.BAD_REQUEST, "C021", "선택한 도시들은 동일한 국가에 속하지 않습니다."),
RATING_NOT_FOUND(HttpStatus.NOT_FOUND, "C022", "존재하지 않는 평점입니다."),

// Like

Expand Down
6 changes: 3 additions & 3 deletions src/main/resources/database/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -129,11 +129,11 @@ VALUES
/* Notification */

/* Product */
INSERT INTO Product(product_id, user_id, name, description, address, price,
INSERT INTO Product(product_id, user_id, name, description, address, price, rating,
city_id, subcategory_id, currency_id, created_at)
VALUES
(101, 1, '곤약젤리', '탱글탱글 맛있는 곤약젤리', '신사이바시 메가돈키호테', 1000, 414, 311, 438, now()),
(390, 1, '왕족발 보쌈 과자', '맛있는 왕족발 보쌈 과자', '상하이 장충동', 3000, 422, 311, 439, now());
(101, 1, '곤약젤리', '탱글탱글 맛있는 곤약젤리', '신사이바시 메가돈키호테', 1000, 5.0, 414, 311, 438, now()),
(390, 1, '왕족발 보쌈 과자', '맛있는 왕족발 보쌈 과자', '상하이 장충동', 3000, 4.5, 422, 311, 439, now());

/* Comment */
INSERT INTO Comment(comment_id, product_id, user_id, content, created_at)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import taco.klkl.domain.comment.exception.CommentProductNotMatch;
import taco.klkl.domain.comment.service.CommentService;
import taco.klkl.domain.product.domain.Product;
import taco.klkl.domain.product.domain.Rating;
import taco.klkl.domain.product.exception.ProductNotFoundException;
import taco.klkl.domain.product.service.ProductService;
import taco.klkl.domain.region.domain.City;
Expand Down Expand Up @@ -105,6 +106,7 @@ public class CommentControllerTest {
"description",
"address",
1000,
Rating.FIVE,
user,
city,
subcategory,
Expand Down
Loading

0 comments on commit aca6e93

Please sign in to comment.