Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

점주 가게 등록 #18

Merged
merged 49 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
c487fd5
[feat] 기능 요구사항에 맞게 Store 도메인 엔티티의 인스턴스 필드 반영
june-777 Aug 11, 2024
5daebb3
[feat] 가게 이름 검증 기능
june-777 Aug 11, 2024
f86bafe
[feat] 가게 주소 검증 기능
june-777 Aug 11, 2024
999e0f4
[feat] 가게 최소 주문 금액 검증 기능
june-777 Aug 11, 2024
a962988
[feat] 가게 이용 시간 검증 기능
june-777 Aug 11, 2024
328e78f
[feat] 가게 주소 임베디드 타입 정의
june-777 Aug 11, 2024
48c2e7f
[feat] 가게 이용 시간 임베디드 타입 정의
june-777 Aug 11, 2024
d3a40f4
[feat] 가게 카테고리 도메인 엔티티 정의
june-777 Aug 11, 2024
6df364c
[feat] 시간 정보를 제공하는 DateTimeProvider 인터페이스 정의
june-777 Aug 11, 2024
4a7be13
[feat] 고정 시간을 반환하는 DateTimeProvider 테스트용 구현체
june-777 Aug 11, 2024
835ad62
[feat] 현재 시간을 반환하는 DateTimeProvider 프로덕션용 구현체
june-777 Aug 11, 2024
fe3110f
[feat] DateTimeProvider 구현체인 CurrentDateTime 를 Bean 객체로 설정
june-777 Aug 11, 2024
1e8885a
[test] Store 도메인 객체 생성 테스트 - 가게 최소 주문 가격
june-777 Aug 11, 2024
aa47da4
[test] Store 도메인 객체 생성 테스트 - 가게 이용 시간
june-777 Aug 11, 2024
7791f9a
[test] Store 도메인 객체 생성 테스트 - 가게 이름
june-777 Aug 11, 2024
2999605
[feat] Store (가게) 도메인 관련 커스텀 예외 정의
june-777 Aug 11, 2024
6a4f101
[feat] 가게 카테고리 생성자 추가
june-777 Aug 11, 2024
c766739
[feat] StoreRepository JPA 인터페이스 정의
june-777 Aug 11, 2024
bc5b954
[test] StoreRepository 가게 저장 기능 테스트
june-777 Aug 11, 2024
bdef77a
[feat] StoreCategoryRepository JPA 인터페이스 정의
june-777 Aug 11, 2024
3575f1d
[test] 가게 카테고리 이름으로 조회하는 기능 테스트
june-777 Aug 11, 2024
df6a123
[feat] VendorRepository JPA 인터페이스 정의
june-777 Aug 11, 2024
3f2609e
[feat] 가게 생성을 담당하는 서비스 클래스 구현
june-777 Aug 11, 2024
3224a6d
[feat] 가게 등록 요청 DTO
june-777 Aug 11, 2024
9b7911c
[test] 가게 등록 서비스 메서드 단위 테스트
june-777 Aug 11, 2024
790b465
[fix] Order 엔티티의 테이블 이름을 Orders 로 명시
june-777 Aug 11, 2024
9c4a77d
[feat] 인메모리 H2 DB 및 jpa yaml 설정
june-777 Aug 11, 2024
680283f
[refactor] 불필요한 static 키워드 제거
june-777 Aug 11, 2024
876e3fb
[refactor] 가게 등록 요청 DTO 패키지 이동
june-777 Aug 11, 2024
020ffbf
[feat] 가게와 관련된 예외를 명시하는 ErrorCode Enum 정의
june-777 Aug 11, 2024
1f697f5
[refactor] StoreException 을 생성할 때, 가게 관련 ErrorCode Enum 을 생성자 매개변수로 사…
june-777 Aug 11, 2024
3e5a748
[test] 가게 등록 서비스 예외 검증을 예외 메시지로 구체적인 검증
june-777 Aug 11, 2024
bd08a15
[test] 가게 생성 예외 검증을 예외 메시지로 구체적인 검증
june-777 Aug 11, 2024
4160efd
[fix] Long, LocalDateTime 데이터 타입에 대한 Bean Validation 수정
june-777 Aug 11, 2024
fc53788
[feat] Store 가게 API 컨트롤러 구현
june-777 Aug 11, 2024
6ae068b
[feat] Store 예외 핸들러 구현
june-777 Aug 11, 2024
8822290
[test] Store 가게 API 컨트롤러 단위 테스트
june-777 Aug 11, 2024
79fa970
[merge] resolve merge conflict
june-777 Aug 13, 2024
be5b145
[feat] Bean Validation 예외 메시지 구체화
june-777 Aug 13, 2024
38a1299
[fix] requestDTO 오타 수정
june-777 Aug 13, 2024
191bed5
[test] 병합 과정에서 구현된 Vendor 객체에 맞게 테스트 코드 수정 및 테스트
june-777 Aug 13, 2024
c64baf9
[test] 병합 과정에서 구현된 SessionResolver 맞게 테스트 코드 모킹 추가 및 테스트
june-777 Aug 13, 2024
6e088ca
[feat] SessionArgumentResolver 컴포넌트 등록 및 WebConfiguration 설정 추가
june-777 Aug 13, 2024
2696f11
[refactor] SessionArgumentResolver 구현에 맞게 컨트롤러 메서드 시그니쳐 수정
june-777 Aug 13, 2024
5c3ce74
[refactor] yaml 파일로 환경설정 대체
june-777 Aug 13, 2024
d1a9cbf
Merge remote-tracking branch 'origin/main' into feature/june-777_점주가게등록
june-777 Aug 14, 2024
c81b9d4
[feat] 컨트롤러 단위 테스트에 MockBean 애노테이션 추가
june-777 Aug 14, 2024
a76a39c
[fix] 중복된 클래스 삭제
june-777 Aug 14, 2024
a52b1c8
[style] 라인 포맷팅, import 정리
june-777 Aug 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/main/java/camp/woowak/lab/infra/config/InfraConfiguration.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package camp.woowak.lab.infra.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import camp.woowak.lab.infra.date.CurrentDateTime;
import camp.woowak.lab.infra.date.DateTimeProvider;

@Configuration
public class InfraConfiguration {

@Bean
public DateTimeProvider dateTimeProvider() {
return new CurrentDateTime();
}

}
12 changes: 12 additions & 0 deletions src/main/java/camp/woowak/lab/infra/date/CurrentDateTime.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package camp.woowak.lab.infra.date;

import java.time.LocalDateTime;

public class CurrentDateTime implements DateTimeProvider {

@Override
public LocalDateTime now() {
return LocalDateTime.now();
}

}
20 changes: 20 additions & 0 deletions src/main/java/camp/woowak/lab/infra/date/DateTimeProvider.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package camp.woowak.lab.infra.date;

import java.time.LocalDateTime;

/**
* <h3> 인터페이스 도입 배경 </h3>
* 메서드 내부 구현에 LocalDateTime.now 직접 사용하는 등 제어할 수 없는 영역을 인터페이스로 분리하여 제어 가능하도록 함 <br>
* 날짜로 인해 테스트 어려운 코드를 테스트 용이하도록 하기 위함
*
* <h4> Production Level </h4>
* 구현체: CurrentDateTime
*
* <h4> Test Level</h4>
* 구현체: FixedDateTime
*/
public interface DateTimeProvider {

LocalDateTime now();

}
27 changes: 19 additions & 8 deletions src/main/java/camp/woowak/lab/order/domain/Order.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,26 @@

import camp.woowak.lab.customer.domain.Customer;
import camp.woowak.lab.store.domain.Store;
import jakarta.persistence.*;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;

@Entity
@Table(name = "Orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Customer requester;
@ManyToOne(fetch = FetchType.LAZY)
private Store store;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
private Customer requester;

@ManyToOne(fetch = FetchType.LAZY)
private Store store;

}
64 changes: 58 additions & 6 deletions src/main/java/camp/woowak/lab/store/domain/Store.java
Original file line number Diff line number Diff line change
@@ -1,13 +1,65 @@
package camp.woowak.lab.store.domain;

import java.time.LocalDateTime;

import camp.woowak.lab.vendor.domain.Vendor;
import jakarta.persistence.*;
import jakarta.persistence.Column;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToOne;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Store {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
private Vendor owner;

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "vendor_id", nullable = false)
private Vendor owner;

@OneToOne
@JoinColumn(name = "store_category_id", nullable = false)
private StoreCategory storeCategory;

@Column(nullable = false)
private String name;

// TODO: 위치 정보에 대한 요구사항 논의 후 수정 예정.
// i.g) 송파구로 특정, 도시 정보로 특정 등 요구사항이 정의되어야 엔티티 설계를 진행할 수 있음
@Embedded
private StoreAddress storeAddress;

@Column(nullable = false)
private String phoneNumber;

@Column(nullable = false)
private Integer minOrderPrice;

@Embedded
private StoreTime storeTime;

public Store(Vendor owner, StoreCategory storeCategory, String name, String address, String phoneNumber,
Integer minOrderPrice, LocalDateTime startTime, LocalDateTime endTime
) {
StoreValidator.validate(name, address, minOrderPrice, startTime, endTime);
this.owner = owner;
this.storeCategory = storeCategory;
this.name = name;
this.storeAddress = new StoreAddress(address);
this.phoneNumber = phoneNumber;
this.minOrderPrice = minOrderPrice;
this.storeTime = new StoreTime(startTime, endTime);
}

}
21 changes: 21 additions & 0 deletions src/main/java/camp/woowak/lab/store/domain/StoreAddress.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package camp.woowak.lab.store.domain;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class StoreAddress {

public static final String DEFAULT_DISTRICT = "송파";

@Column(nullable = false)
private String district;

public StoreAddress(final String district) {
this.district = district;
}

}
24 changes: 24 additions & 0 deletions src/main/java/camp/woowak/lab/store/domain/StoreCategory.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package camp.woowak.lab.store.domain;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class StoreCategory {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;

public StoreCategory(String name) {
this.name = name;
}

}
25 changes: 25 additions & 0 deletions src/main/java/camp/woowak/lab/store/domain/StoreTime.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package camp.woowak.lab.store.domain;

import java.time.LocalDateTime;

import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

@Embeddable
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class StoreTime {

@Column(nullable = false)
private LocalDateTime startTime;

@Column(nullable = false)
private LocalDateTime endTime;

public StoreTime(final LocalDateTime startTime, final LocalDateTime endTime) {
this.startTime = startTime;
this.endTime = endTime;
}

}
79 changes: 79 additions & 0 deletions src/main/java/camp/woowak/lab/store/domain/StoreValidator.java
kimhyun5u marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package camp.woowak.lab.store.domain;

import static camp.woowak.lab.store.exception.StoreException.ErrorCode.*;

import java.time.LocalDateTime;

import camp.woowak.lab.store.exception.StoreException;

public class StoreValidator {

private static final int UNIT_OF_MIN_ORDER_PRICE = 1000;

private static final int MIN_ORDER_PRICE = 5000;

private static final int MIN_NAME_LENGTH = 2;
private static final int MAX_NAME_LENGTH = 10;

public static void validate(final String name, final String address, final Integer minOrderPrice,
final LocalDateTime startTime, final LocalDateTime endTime
) {
validateName(name);
validateAddress(address);
validateMinOrderPrice(minOrderPrice);
validateUnitOrderPrice(minOrderPrice);
validateTime(startTime, endTime);
}

private static void validateName(final String name) {
if (MIN_NAME_LENGTH <= name.length() && name.length() <= MAX_NAME_LENGTH) {
return;
}
throw new StoreException(INVALID_NAME_RANGE);
}

// TODO: 가게 위치 비즈니스 요구사항 구체화하면, 주소 검증 로직 수정 예정
private static void validateAddress(final String address) {
if (StoreAddress.DEFAULT_DISTRICT.equals(address)) {
return;
}
throw new StoreException(INVALID_ADDRESS);
}

private static void validateMinOrderPrice(final Integer minOrderPrice) {
if (minOrderPrice < MIN_ORDER_PRICE) {
throw new StoreException(INVALID_MIN_ORDER_PRICE);
}
}

private static void validateUnitOrderPrice(final Integer minOrderPrice) {
if (minOrderPrice % UNIT_OF_MIN_ORDER_PRICE != 0) {
throw new StoreException(INVALID_UNIT_OF_MIN_ORDER_PRICE);
}
}

private static void validateTime(final LocalDateTime startTime,
final LocalDateTime endTime
) {
if (isInvalidStoreTimeUnit(startTime)) {
throw new StoreException(INVALID_TIME_UNIT);
}

if (isInvalidStoreTimeUnit(endTime)) {
throw new StoreException(INVALID_TIME_UNIT);
}

if (endTime.isBefore(startTime)) {
throw new StoreException(INVALID_TIME);
}

if (startTime.isEqual(endTime)) {
throw new StoreException(INVALID_TIME);
}
}

private static boolean isInvalidStoreTimeUnit(final LocalDateTime target) {
return target.getSecond() != 0 || target.getNano() != 0;
}

}
38 changes: 38 additions & 0 deletions src/main/java/camp/woowak/lab/store/exception/StoreException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package camp.woowak.lab.store.exception;

import lombok.Getter;

@Getter
public class StoreException extends RuntimeException {

private final ErrorCode errorCode;

public StoreException(final ErrorCode errorCode) {
super(errorCode.getMessage());
this.errorCode = errorCode;
}

@Getter
public enum ErrorCode {

INVALID_NAME_RANGE("가게 이름은 2글자 ~ 10글자 이어야합니다."),

INVALID_ADDRESS("가게 주소는 송파구만 가능합니다."),

INVALID_MIN_ORDER_PRICE("최소 주문 금액은 5,000원 이상이어야 합니다."),
INVALID_UNIT_OF_MIN_ORDER_PRICE("최소 주문 금액은 1,000원 단위이어야 합니다."),

INVALID_TIME_UNIT("가게 시작 시간은 분 단위까지 가능합니다"),
INVALID_TIME("가게 시작 시간은 종료 시간보다 이전이어야 합니다"),

INVALID_STORE_CATEGORY("존재하지 않는 가게 카테고리입니다.");

private final String message;

ErrorCode(String message) {
this.message = message;
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package camp.woowak.lab.store.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import camp.woowak.lab.store.domain.StoreCategory;

public interface StoreCategoryRepository extends JpaRepository<StoreCategory, Long> {

Optional<StoreCategory> findByName(String name);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package camp.woowak.lab.store.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import camp.woowak.lab.store.domain.Store;

public interface StoreRepository extends JpaRepository<Store, Long> {
}
Loading