refactor: reformat code

This commit is contained in:
shinmj
2021-12-30 13:56:05 +09:00
parent c62eb513e4
commit 64a3877619
55 changed files with 1586 additions and 1305 deletions

View File

@@ -1,29 +1,32 @@
package org.egovframe.cloud.reservechecksevice.api.reserve;
package org.egovframe.cloud.reservechecksevice.api;
import java.time.LocalDate;
import javax.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.*;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Category;
import org.egovframe.cloud.reservechecksevice.service.reserve.ReserveService;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveCancelRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveListResponseDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveResponseDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveSaveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.service.ReserveService;
import org.springframework.core.env.Environment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Mono;
import javax.validation.Valid;
/**
* org.egovframe.cloud.reservechecksevice.api.reserve.ReserveApiController
* org.egovframe.cloud.reservechecksevice.api.ReserveApiController
* <p>
* 예약 확인 rest controller class
*

View File

@@ -1,14 +1,13 @@
package org.egovframe.cloud.reservechecksevice.api.reserve.dto;
package org.egovframe.cloud.reservechecksevice.api.dto;
import javax.validation.constraints.NotBlank;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
/**
* org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveCancelRequestDto
* org.egovframe.cloud.reservechecksevice.api.dto.ReserveCancelRequestDto
* <p>
* 예약 취소 요청 dto class
*

View File

@@ -1,15 +1,14 @@
package org.egovframe.cloud.reservechecksevice.api.reserve.dto;
package org.egovframe.cloud.reservechecksevice.api.dto;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Reserve;
import java.time.LocalDateTime;
import org.egovframe.cloud.reservechecksevice.domain.Reserve;
/**
* org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveListResponseDto
* org.egovframe.cloud.reservechecksevice.api.dto.ReserveListResponseDto
* <p>
* 예약 목록 응답 dto class
*

View File

@@ -1,11 +1,11 @@
package org.egovframe.cloud.reservechecksevice.api.reserve.dto;
package org.egovframe.cloud.reservechecksevice.api.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.egovframe.cloud.common.dto.RequestDto;
/**
* org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveRequestDto
* org.egovframe.cloud.reservechecksevice.api.dto.ReserveRequestDto
* <p>
* 얘약 목록 요청 dto class
*

View File

@@ -1,17 +1,15 @@
package org.egovframe.cloud.reservechecksevice.api.reserve.dto;
package org.egovframe.cloud.reservechecksevice.api.dto;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemRelationResponseDto;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Reserve;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import org.egovframe.cloud.reservechecksevice.domain.Reserve;
/**
* org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveResponseDto
* org.egovframe.cloud.reservechecksevice.api.dto.ReserveResponseDto
* <p>
* 예약 확인(신청) 응답 dto class
*

View File

@@ -1,20 +1,18 @@
package org.egovframe.cloud.reservechecksevice.api.reserve.dto;
package org.egovframe.cloud.reservechecksevice.api.dto;
import java.time.LocalDateTime;
import java.util.UUID;
import javax.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.With;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Reserve;
import org.egovframe.cloud.reservechecksevice.domain.Reserve;
import org.egovframe.cloud.reservechecksevice.validator.annotation.ReserveSaveValid;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveSaveRequestDto
* org.egovframe.cloud.reservechecksevice.api.dto.ReserveSaveRequestDto
* <p>
* 예약 신청 요청 dto class
*
@@ -77,6 +75,11 @@ public class ReserveSaveRequestDto {
this.userEmail = userEmail;
}
public Reserve createNewReserve() {
this.reserveId = String.valueOf(UUID.randomUUID());
return toEntity();
}
public Reserve toEntity() {
Reserve reserve = Reserve.builder()
.reserveId(this.reserveId)

View File

@@ -1,16 +1,15 @@
package org.egovframe.cloud.reservechecksevice.api.reserve.dto;
package org.egovframe.cloud.reservechecksevice.api.dto;
import java.time.LocalDateTime;
import javax.validation.constraints.NotNull;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.egovframe.cloud.reservechecksevice.validator.annotation.ReserveSaveValid;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
/**
* org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveUpdateRequestDto
* org.egovframe.cloud.reservechecksevice.api.dto.ReserveUpdateRequestDto
* <p>
* 예약 신청 정보 수정 요청 dto class
*

View File

@@ -6,7 +6,6 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import reactivefeign.spring.config.ReactiveFeignClient;
import reactor.core.publisher.Mono;

View File

@@ -3,7 +3,6 @@ package org.egovframe.cloud.reservechecksevice.client;
import org.egovframe.cloud.reservechecksevice.client.dto.UserResponseDto;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import reactivefeign.spring.config.ReactiveFeignClient;
import reactor.core.publisher.Mono;

View File

@@ -1,16 +1,14 @@
package org.egovframe.cloud.reservechecksevice.client.dto;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.egovframe.cloud.reservechecksevice.domain.ReserveItem;
import org.egovframe.cloud.reservechecksevice.domain.location.Location;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveItem;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemRelationResponseDto

View File

@@ -1,13 +1,12 @@
package org.egovframe.cloud.reservechecksevice.client.dto;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveItem;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import org.egovframe.cloud.reservechecksevice.domain.ReserveItem;
/**
* org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemResponseDto
@@ -30,6 +29,8 @@ import java.time.LocalDateTime;
@NoArgsConstructor
@ToString
public class ReserveItemResponseDto {
private static final int MIN_QTY = 0;
private Long reserveItemId; // 예약 물품 id
private String reserveItemName; //예약 물품 명
private Long locationId;
@@ -90,4 +91,16 @@ public class ReserveItemResponseDto {
this.managerName = reserveItem.getManagerName();
this.managerContact = reserveItem.getManagerContact();
}
public boolean isPossibleQty(Integer max, Integer reserveQty) {
return (totalQty - max) >= reserveQty;
}
public boolean isPositiveInventory() {
return inventoryQty > MIN_QTY;
}
public boolean isPossibleInventoryQty(Integer reserveQty) {
return inventoryQty >= reserveQty;
}
}

View File

@@ -1,12 +1,10 @@
package org.egovframe.cloud.reservechecksevice.config;
import java.time.Duration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import java.time.Duration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* org.egovframe.cloud.portalservice.config.Resilience4JConfig

View File

@@ -1,10 +1,10 @@
package org.egovframe.cloud.reservechecksevice.domain.reserve;
package org.egovframe.cloud.reservechecksevice.domain;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* org.egovframe.cloud.reservechecksevice.domain.reserve.Category
* org.egovframe.cloud.reservechecksevice.domain.Category
*
* 예약 유형 enum class
*

View File

@@ -1,21 +1,23 @@
package org.egovframe.cloud.reservechecksevice.domain.reserve;
package org.egovframe.cloud.reservechecksevice.domain;
import lombok.*;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import lombok.With;
import org.egovframe.cloud.common.exception.BusinessMessageException;
import org.egovframe.cloud.reactive.domain.BaseEntity;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.client.dto.UserResponseDto;
import org.egovframe.cloud.reservechecksevice.domain.location.Location;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.time.LocalDateTime;
/**
* org.egovframe.cloud.reservechecksevice.domain.reserve.Reserve
* org.egovframe.cloud.reservechecksevice.domain.Reserve
*
* 예약 도메인 클래스
*
@@ -112,6 +114,10 @@ public class Reserve extends BaseEntity {
this.userEmail = userEmail;
}
public boolean isReserveUser(String userId) {
return this.userId.equals(userId);
}
/**
* 물품 정보 세팅
*
@@ -203,4 +209,26 @@ public class Reserve extends BaseEntity {
return this;
}
public boolean isDone() {
return ReserveStatus.DONE.isEquals(this.reserveStatusId);
}
public Reserve updateStatusCancel(String reason, String errorMessage) {
if (isDone()) {
throw new BusinessMessageException(errorMessage);
}
this.reserveStatusId = ReserveStatus.CANCEL.getKey();
this.reasonCancelContent = reason;
return this;
}
public boolean isEducation() {
return Category.EDUCATION.isEquals(this.getCategoryId());
}
public boolean isRequest() {
return ReserveStatus.REQUEST.isEquals(this.reserveStatusId);
}
}

View File

@@ -1,6 +1,10 @@
package org.egovframe.cloud.reservechecksevice.domain.reserve;
package org.egovframe.cloud.reservechecksevice.domain;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@@ -10,12 +14,6 @@ import org.egovframe.cloud.reservechecksevice.domain.location.Location;
import org.springframework.data.annotation.Id;
import org.springframework.data.annotation.Transient;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* org.egovframe.cloud.reserveitemservice.domain.reserveItem.ReserveItem

View File

@@ -1,9 +1,9 @@
package org.egovframe.cloud.reservechecksevice.domain.reserve;
package org.egovframe.cloud.reservechecksevice.domain;
import org.springframework.data.r2dbc.repository.R2dbcRepository;
/**
* org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveRepository
* org.egovframe.cloud.reservechecksevice.domain.ReserveRepository
*
* 예약 도메인 Repository interface
*

View File

@@ -1,15 +1,13 @@
package org.egovframe.cloud.reservechecksevice.domain.reserve;
package org.egovframe.cloud.reservechecksevice.domain;
import org.egovframe.cloud.common.dto.RequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveRequestDto;
import java.time.LocalDateTime;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveRequestDto;
import org.springframework.data.domain.Pageable;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
/**
* org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveRepositoryCustom
* org.egovframe.cloud.reservechecksevice.domain.ReserveRepositoryCustom
*
* 예약 도메인 custom Repository interface
*

View File

@@ -1,14 +1,15 @@
package org.egovframe.cloud.reservechecksevice.domain.reserve;
package org.egovframe.cloud.reservechecksevice.domain;
import static org.springframework.data.relational.core.query.Criteria.*;
import static org.springframework.data.relational.core.query.Criteria.where;
import java.time.LocalDate;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.reactor.circuitbreaker.operator.CircuitBreakerOperator;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveRequestDto;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveRequestDto;
import org.egovframe.cloud.reservechecksevice.client.ReserveItemServiceClient;
import org.egovframe.cloud.reservechecksevice.client.UserServiceClient;
import org.egovframe.cloud.reservechecksevice.client.dto.UserResponseDto;
@@ -18,16 +19,11 @@ import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.data.relational.core.query.Criteria;
import org.springframework.data.relational.core.query.Query;
import org.springframework.util.StringUtils;
import io.github.resilience4j.circuitbreaker.CircuitBreaker;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.reactor.circuitbreaker.operator.CircuitBreakerOperator;
import lombok.RequiredArgsConstructor;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveRepositoryImpl
* org.egovframe.cloud.reservechecksevice.domain.ReserveRepositoryImpl
*
* 예약 도메인 custom repository 구현 클래스
*

View File

@@ -1,10 +1,10 @@
package org.egovframe.cloud.reservechecksevice.domain.reserve;
package org.egovframe.cloud.reservechecksevice.domain;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
/**
* org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveStatus
* org.egovframe.cloud.reservechecksevice.domain.ReserveStatus
*
* 예약 상태 enum class
*

View File

@@ -0,0 +1,259 @@
package org.egovframe.cloud.reservechecksevice.domain;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.reactor.circuitbreaker.operator.CircuitBreakerOperator;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.stream.IntStream;
import javax.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.egovframe.cloud.common.exception.BusinessMessageException;
import org.egovframe.cloud.common.util.MessageUtil;
import org.egovframe.cloud.reservechecksevice.client.ReserveItemServiceClient;
import org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemResponseDto;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
@Component
@RequiredArgsConstructor
public class ReserveValidator {
private static final String CHECK_RESERVE_MEANS = "realtime";
private static final String RESERVE_ITEM_CIRCUIT_BREAKER_NAME = "reserve-item";
@Resource(
name = "messageUtil"
)
protected MessageUtil messageUtil;
private final ReserveRepository reserveRepository;
private final ReserveItemServiceClient reserveItemServiceClient;
private final CircuitBreakerRegistry circuitBreakerRegistry;
/**
* 공간 예약 시 예약 날짜에 다른 예약이 있는지 체크
*
* @param reserveItem
* @param reserve
* @return
*/
public Mono<Reserve> checkSpace(ReserveItemResponseDto reserveItem, Reserve reserve) {
return this.checkReserveDate(reserveItem, reserve)
.flatMap(isValid -> reserveRepository.findAllByReserveDateWithoutSelfCount(
reserve.getReserveId(),
reserveItem.getReserveItemId(),
reserve.getReserveStartDate(),
reserve.getReserveEndDate())
.flatMap(count -> {
if (count > 0) {
//"해당 날짜에는 예약할 수 없습니다."
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
return Mono.just(reserve);
})
);
}
/**
* 장비 예약 시 예약 날짜에 예약 가능한 재고 체크
*
* @param reserveItem
* @param reserve
* @return
*/
public Mono<Reserve> checkEquipment(ReserveItemResponseDto reserveItem, Reserve reserve) {
return this.checkReserveDate(reserveItem, reserve)
.flatMap(entity -> this.getMaxByReserveDateWithoutSelf(
entity.getReserveId(),
reserveItem.getReserveItemId(),
entity.getReserveStartDate(),
entity.getReserveEndDate())
.flatMap(max -> Mono.just((reserveItem.isPossibleQty(max, reserve.getReserveQty()))))
.flatMap(isValid -> {
if (isValid) {
return Mono.just(reserve);
}
//해당 날짜에 예약할 수 있는 재고수량이 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_count")));
})
);
}
/**
* 교육 예약 시 재고 체크
*
* @param reserveItem
* @param reserve
* @return
*/
public Mono<Reserve> checkEducation(ReserveItemResponseDto reserveItem, Reserve reserve) {
return Mono.just(reserveItem)
.flatMap(reserveItemResponseDto -> {
LocalDateTime now = LocalDateTime.now();
LocalDateTime startDate = reserveItemResponseDto.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItemResponseDto.getRequestStartDate() : reserveItemResponseDto.getOperationStartDate();
LocalDateTime endDate = reserveItemResponseDto.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItemResponseDto.getRequestEndDate() : reserveItemResponseDto.getOperationEndDate();
if (!(now.isAfter(startDate) && now.isBefore(endDate))) {
//해당 날짜에는 예약할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
if (!reserveItemResponseDto.isPositiveInventory()) {
//"예약이 마감되었습니다."
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_close")));
}
if (reserveItemResponseDto.isPossibleInventoryQty(reserve.getReserveQty())) {
//예약가능한 인원이 부족합니다. (남은 인원 : {0})
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_number_of_people", new Object[]{reserveItemResponseDto.getInventoryQty()})));
}
return Mono.just(reserve);
});
}
/**
* 예약물품에 대해 날짜별 예약된 수량 max 조회
*
* @param reserveItemId
* @param startDate
* @param endDate
* @return
*/
public Mono<Integer> getMaxByReserveDate(Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
Flux<Reserve> reserveFlux = reserveRepository.findAllByReserveDate(reserveItemId, startDate, endDate)
.switchIfEmpty(Flux.empty());
return countMax(reserveFlux, startDate, endDate);
}
/**
* 예약 물품 재고 및 예약 일자 체크
*
* @param reserve
* @return
*/
public Mono<Reserve> checkReserveItems(Reserve reserve) {
return reserveItemServiceClient.findById(reserve.getReserveItemId())
.transform(CircuitBreakerOperator
.of(circuitBreakerRegistry.circuitBreaker(RESERVE_ITEM_CIRCUIT_BREAKER_NAME)))
.onErrorResume(throwable -> Mono.empty())
.flatMap(reserveItemResponseDto -> {
// validation check
if (Category.SPACE.isEquals(reserveItemResponseDto.getCategoryId())) {
return checkSpace(reserveItemResponseDto, reserve);
}
if (Category.EQUIPMENT.isEquals(reserveItemResponseDto.getCategoryId())) {
return checkEquipment(reserveItemResponseDto, reserve);
}
if (Category.EDUCATION.isEquals(reserveItemResponseDto.getCategoryId())) {
return checkEducation(reserveItemResponseDto, reserve);
}
return Mono.just(reserve);
});
}
/**
* 예약 날짜 validation
*
* @param reserveItem
* @param reserve
* @return
*/
private Mono<Reserve> checkReserveDate(ReserveItemResponseDto reserveItem, Reserve reserve) {
LocalDateTime startDate = reserveItem.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItem.getRequestStartDate() : reserveItem.getOperationStartDate();
LocalDateTime endDate = reserveItem.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItem.getRequestEndDate() : reserveItem.getOperationEndDate();
if (reserve.getReserveStartDate().isBefore(startDate)) {
//{0}이 {1} 보다 빠릅니다. 시작일, 운영/예약 시작일
return Mono.error(new BusinessMessageException(getMessage("valid.to_be_fast.format", new Object[]{getMessage("common.start_date"),
getMessage("reserve_item.operation")+getMessage("reserve")+" "+getMessage("common.start_date")})));
}
if (reserve.getReserveEndDate().isAfter(endDate)) {
//{0}이 {1} 보다 늦습니다. 종료일, 운영/예약 종료일
return Mono.error(new BusinessMessageException(getMessage("valid.to_be_slow.format", new Object[]{getMessage("common.end_date"),
getMessage("reserve_item.operation")+getMessage("reserve")+" "+getMessage("common.end_date")})));
}
if (reserveItem.getIsPeriod()) {
long between = ChronoUnit.DAYS.between(reserve.getReserveStartDate(), reserve.getReserveEndDate());
if (reserveItem.getPeriodMaxCount() < between) {
//최대 예약 가능 일수보다 예약기간이 깁니다. (최대 예약 가능일 수 : {0})
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_period", new Object[]{reserveItem.getPeriodMaxCount()})));
}
}
return Mono.just(reserve);
}
/**
* 예약물품에 대해 날짜별 예약된 수량 max 조회
* 현 예약 건 제외
*
* @param reserveItemId
* @param startDate
* @param endDate
* @return
*/
private Mono<Integer> getMaxByReserveDateWithoutSelf(String reserveId, Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
Flux<Reserve> reserveFlux = reserveRepository.findAllByReserveDateWithoutSelf(reserveId, reserveItemId, startDate, endDate)
.switchIfEmpty(Flux.empty());
return countMax(reserveFlux, startDate, endDate);
}
/**
* get max
*
* @param reserveFlux
* @param startDate
* @param endDate
* @return
*/
private Mono<Integer> countMax(Flux<Reserve> reserveFlux, LocalDateTime startDate, LocalDateTime endDate) {
if (reserveFlux.equals(Flux.empty())) {
return Mono.just(0);
}
long between = ChronoUnit.DAYS.between(startDate, endDate);
if (between == 0) {
return reserveFlux.map(reserve -> {
if (startDate.isAfter(reserve.getReserveStartDate())
|| startDate.isBefore(reserve.getReserveEndDate())
|| startDate.isEqual(reserve.getReserveStartDate()) || startDate.isEqual(reserve.getReserveEndDate())) {
return reserve.getReserveQty();
}
return 0;
}).reduce(0, (x1, x2) -> x1 + x2);
}
return Flux.fromStream(IntStream.iterate(0, i -> i + 1)
.limit(between)
.mapToObj(i -> startDate.plusDays(i)))
.flatMap(localDateTime ->
reserveFlux.map(findReserve -> {
if (localDateTime.isAfter(findReserve.getReserveStartDate())
|| localDateTime.isBefore(findReserve.getReserveEndDate())
|| localDateTime.isEqual(findReserve.getReserveStartDate()) || localDateTime.isEqual(findReserve.getReserveEndDate())) {
return findReserve.getReserveQty();
}
return 0;
}).reduce(0, (x1, x2) -> x1 + x2))
.groupBy(integer -> integer)
.flatMap(group -> group.reduce((x1,x2) -> x1 > x2?x1:x2))
.last(0);
}
private String getMessage(String code) {
return this.messageUtil.getMessage(code);
}
private String getMessage(String code, Object[] args) {
return this.messageUtil.getMessage(code, args);
}
}

View File

@@ -1,12 +1,13 @@
package org.egovframe.cloud.reservechecksevice.domain.location;
import lombok.*;
import javax.validation.constraints.Size;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.ToString;
import org.egovframe.cloud.reactive.domain.BaseEntity;
import org.springframework.data.annotation.Id;
import org.springframework.data.relational.core.mapping.Column;
import org.springframework.data.relational.core.mapping.Table;
import javax.validation.constraints.Size;
/**
* org.egovframe.cloud.reserveitemservice.domain.location.Location

View File

@@ -0,0 +1,411 @@
package org.egovframe.cloud.reservechecksevice.service;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.reactor.circuitbreaker.operator.CircuitBreakerOperator;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.common.dto.AttachmentEntityMessage;
import org.egovframe.cloud.common.exception.BusinessMessageException;
import org.egovframe.cloud.reactive.service.ReactiveAbstractService;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveCancelRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveListResponseDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveResponseDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveSaveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.client.ReserveItemServiceClient;
import org.egovframe.cloud.reservechecksevice.domain.Reserve;
import org.egovframe.cloud.reservechecksevice.domain.ReserveRepository;
import org.egovframe.cloud.reservechecksevice.domain.ReserveStatus;
import org.egovframe.cloud.reservechecksevice.domain.ReserveValidator;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* org.egovframe.cloud.reservechecksevice.service.ReserveService
* <p>
* 예약 service 클래스
*
* @author 표준프레임워크센터 shinmj
* @version 1.0
* @since 2021/09/15
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2021/09/15 shinmj 최초 생성
* </pre>
*/
@Slf4j
@RequiredArgsConstructor
@Transactional
@Service
public class ReserveService extends ReactiveAbstractService {
private static final String RESERVE_ITEM_CIRCUIT_BREAKER_NAME = "reserve-item";
private final ReserveRepository reserveRepository;
private final ReserveItemServiceClient reserveItemServiceClient;
private final CircuitBreakerRegistry circuitBreakerRegistry;
private final StreamBridge streamBridge;
private final ReserveValidator validator;
/**
* 목록 조회
*
* @param requestDto
* @param pageable
* @return
*/
@Transactional(readOnly = true)
public Mono<Page<ReserveListResponseDto>> search(ReserveRequestDto requestDto,
Pageable pageable) {
return reserveRepository.search(requestDto, pageable)
.switchIfEmpty(Flux.empty())
.flatMap(this::convertReserveListResponseDto)
.collectList()
.zipWith(reserveRepository.searchCount(requestDto, pageable))
.flatMap(tuple -> Mono.just(new PageImpl<>(tuple.getT1(), pageable, tuple.getT2())));
}
/**
* 한건 조회 dto return
*
* @param reserveId
* @return
*/
@Transactional(readOnly = true)
public Mono<ReserveResponseDto> findReserveById(String reserveId) {
return reserveRepository.findReserveById(reserveId)
.switchIfEmpty(monoResponseStatusEntityNotFoundException(reserveId))
.flatMap(this::convertReserveResponseDto);
}
/**
* 사용자용 예약 목록 조회 (로그인 사용자의 예약정보만 조회)
*
* @param userId
* @param requestDto
* @param pageable
* @return
*/
@Transactional(readOnly = true)
public Mono<Page<ReserveListResponseDto>> searchForUser(String userId,
ReserveRequestDto requestDto, Pageable pageable) {
return reserveRepository.searchForUser(requestDto, pageable, userId)
.switchIfEmpty(Flux.empty())
.flatMap(this::convertReserveListResponseDto)
.collectList()
.zipWith(reserveRepository.searchCountForUser(requestDto, pageable, userId))
.flatMap(tuple -> Mono.just(new PageImpl<>(tuple.getT1(), pageable, tuple.getT2())));
}
/**
* 예약 정보 취소
*
* @param reserveId
* @param cancelRequestDto
* @return
*/
public Mono<Void> cancel(String reserveId, ReserveCancelRequestDto cancelRequestDto) {
return getIsAdmin().flatMap(isAdmin -> {
if (isAdmin) {
return reserveCancel(reserveId, cancelRequestDto);
}
return findById(reserveId)
.zipWith(getUserId())
.flatMap(tuple -> {
if (tuple.getT1().isReserveUser(tuple.getT2())) {
return Mono.just(tuple.getT1());
}
//해당 예약은 취소할 수 없습니다.
return Mono
.error(new BusinessMessageException(getMessage("valid.cant_cancel")));
})
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserve -> reserveCancel(reserveId, cancelRequestDto));
});
}
/**
* 예약 상태 취소로 변경
*
* @param reserveId
* @param cancelRequestDto
* @return
*/
private Mono<Void> reserveCancel(String reserveId, ReserveCancelRequestDto cancelRequestDto) {
return findById(reserveId)
.map(reserve ->
reserve.updateStatusCancel(cancelRequestDto.getReasonCancelContent(), getMessage("valid.cant_cancel_because_done")))
.flatMap(reserve -> Mono.just(reserve.conversionReserveQty()))
.flatMap(this::updateInventory)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserve -> Mono.just(reserve.conversionReserveQty()))
.flatMap(reserveRepository::save)
.then();
}
/**
* 예약 정보 승인
*
* @param reserveId
* @return
*/
public Mono<Void> approve(String reserveId) {
return getIsAdmin()
.flatMap(isAdmin -> {
if (isAdmin) {
return Mono.just(reserveId);
}
//관리자만 승인할 수 있습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.manager_approve")));
})
.onErrorResume(Mono::error)
.flatMap(this::checkApprove)
.onErrorResume(Mono::error)
.flatMap(reserveRepository::save).then();
}
/**
* 예약 정보 수정
*
* @param reserveId
* @return
*/
public Mono<Reserve> update(String reserveId, ReserveUpdateRequestDto updateRequestDto) {
return getIsAdmin().flatMap(isAdmin -> {
if (isAdmin) {
return updateReserve(reserveId, updateRequestDto);
}
return updateReserveForUser(reserveId, updateRequestDto);
});
}
/**
* 관리자 예약 신청 관리자의 경우 실시간이어도 이벤트 스트림 거치지 않고 바로 예약 처리
*
* @param saveRequestDto
* @return
*/
public Mono<ReserveResponseDto> create(ReserveSaveRequestDto saveRequestDto) {
return Mono.just(saveRequestDto)
.map(ReserveSaveRequestDto::createNewReserve)
.zipWith(getUserId())
.flatMap(tuple -> Mono.just(tuple.getT1().setCreatedInfo(LocalDateTime.now(), tuple.getT2())))
.flatMap(validator::checkReserveItems)
.onErrorResume(Mono::error)
.flatMap(this::updateInventory)
.onErrorResume(Mono::error)
.flatMap(reserveRepository::insert)
.flatMap(reserveRepository::loadRelations)
.doOnNext(reserve -> sendAttachmentEntityInfo(streamBridge,
AttachmentEntityMessage.builder()
.attachmentCode(reserve.getAttachmentCode())
.entityName(reserve.getClass().getName())
.entityId(reserve.getReserveId())
.build()))
.flatMap(this::convertReserveResponseDto);
}
/**
* 예약 물품별 기간안에 있는 예약된 수량 max 조회
*
* @param reserveItemId
* @param startDate
* @param endDate
* @return
*/
public Mono<Integer> countInventory(Long reserveItemId, LocalDateTime startDate,
LocalDateTime endDate) {
return reserveItemServiceClient.findById(reserveItemId)
.transform(CircuitBreakerOperator.of(circuitBreakerRegistry.circuitBreaker(RESERVE_ITEM_CIRCUIT_BREAKER_NAME)))
.onErrorResume(throwable -> Mono.empty())
.zipWith(validator.getMaxByReserveDate(reserveItemId, startDate, endDate))
.flatMap(tuple -> Mono.just(tuple.getT1().getTotalQty() - tuple.getT2()));
}
/**
* 승인 전 validate check 및 교육인 경우 재고 업데이트
*
* @param reserveId
* @return
*/
private Mono<Reserve> checkApprove(String reserveId) {
return findById(reserveId)
.flatMap(validator::checkReserveItems)
.onErrorResume(Mono::error)
.map(reserve -> reserve.updateStatus(ReserveStatus.APPROVE.getKey()))
.flatMap(this::updateInventory);
}
/**
* 사용자 예약 수정
*
* @param reserveId
* @param updateRequestDto
* @return
*/
private Mono<Reserve> updateReserveForUser(String reserveId,
ReserveUpdateRequestDto updateRequestDto) {
return findById(reserveId)
.zipWith(getUserId())
.map(tuple -> {
if (!tuple.getT1().isReserveUser(tuple.getT2())) {
//"해당 예약은 수정할 수 없습니다."
throw new BusinessMessageException(getMessage("valid.reserve_not_update"));
}
if (!tuple.getT1().isRequest()) {
//예약 신청 상태인 경우에만 수정 가능합니다.
throw new BusinessMessageException(getMessage("valid.reserve_not_update_status"));
}
return tuple.getT1().update(updateRequestDto);
})
.flatMap(validator::checkReserveItems)
.onErrorResume(Mono::error)
.flatMap(this::updateInventory)
.onErrorResume(Mono::error)
.flatMap(reserveRepository::save);
}
/**
* 관리자 예약 수정
*
* @param reserveId
* @param updateRequestDto
* @return
*/
private Mono<Reserve> updateReserve(String reserveId,
ReserveUpdateRequestDto updateRequestDto) {
return findById(reserveId)
.map(reserve -> {
if (!reserve.isRequest()) {
//예약 신청 상태인 경우에만 수정 가능합니다.
throw new BusinessMessageException(
getMessage("valid.reserve_not_update_status"));
}
return reserve.update(updateRequestDto);
})
.flatMap(validator::checkReserveItems)
.onErrorResume(Mono::error)
.flatMap(this::updateInventory)
.onErrorResume(Mono::error)
.flatMap(reserveRepository::save);
}
/**
* 예약 정보 저장 시 재고 변경
*
* @param reserve
* @return
*/
private Mono<Reserve> updateInventory(Reserve reserve) {
return Mono.just(reserve)
.flatMap(it -> {
if (it.isEducation()) {
return reserveItemServiceClient
.updateInventory(reserve.getReserveItemId(), reserve.getReserveQty())
.transform(CircuitBreakerOperator.of(circuitBreakerRegistry
.circuitBreaker(RESERVE_ITEM_CIRCUIT_BREAKER_NAME)))
.onErrorResume(throwable -> Mono.just(false))
.flatMap(isSuccess -> {
if (isSuccess) {
return Mono.just(reserve);
}
//재고 업데이트에 실패했습니다.
return Mono.error(new BusinessMessageException(getMessage("msg.inventory_failed")));
});
}
return Mono.just(it);
});
}
/**
* 한건 정보 조회 entity return
*
* @param reserveId
* @return
*/
private Mono<Reserve> findById(String reserveId) {
return reserveRepository.findById(reserveId)
.switchIfEmpty(monoResponseStatusEntityNotFoundException(reserveId));
}
/**
* entity -> dto 변환
*
* @param reserve
* @return
*/
private Mono<ReserveResponseDto> convertReserveResponseDto(Reserve reserve) {
return Mono.just(ReserveResponseDto.builder()
.entity(reserve)
.build());
}
/**
* entity -> 목록 dto 변환
*
* @param reserve
* @return
*/
private Mono<ReserveListResponseDto> convertReserveListResponseDto(Reserve reserve) {
return Mono.just(ReserveListResponseDto.builder()
.entity(reserve)
.build());
}
/**
* 현재 로그인 사용자가 관리자인지 체크
*
* @return
*/
private Mono<Boolean> getIsAdmin() {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getAuthorities)
.map(grantedAuthorities -> {
List<SimpleGrantedAuthority> authorities =
new ArrayList<>((Collection<? extends SimpleGrantedAuthority>) grantedAuthorities);
SimpleGrantedAuthority adminRole = new SimpleGrantedAuthority(Role.ADMIN.getKey());
return authorities.contains(adminRole);
});
}
/**
* 현재 로그인 사용자 id
*
* @return
*/
private Mono<String> getUserId() {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getPrincipal)
.map(String.class::cast);
}
}

View File

@@ -1,640 +0,0 @@
package org.egovframe.cloud.reservechecksevice.service.reserve;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.stream.IntStream;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.common.dto.AttachmentEntityMessage;
import org.egovframe.cloud.common.exception.BusinessMessageException;
import org.egovframe.cloud.reactive.service.ReactiveAbstractService;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveCancelRequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveListResponseDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveResponseDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveSaveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.client.ReserveItemServiceClient;
import org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemResponseDto;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Category;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Reserve;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveRepository;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveStatus;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.reactor.circuitbreaker.operator.CircuitBreakerOperator;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
/**
* org.egovframe.cloud.reservechecksevice.service.reserve.ReserveService
*
* 예약 service 클래스
*
* @author 표준프레임워크센터 shinmj
* @version 1.0
* @since 2021/09/15
*
* <pre>
* << 개정이력(Modification Information) >>
*
* 수정일 수정자 수정내용
* ---------- -------- ---------------------------
* 2021/09/15 shinmj 최초 생성
* </pre>
*/
@Slf4j
@RequiredArgsConstructor
@Transactional
@Service
public class ReserveService extends ReactiveAbstractService {
private static final String RESERVE_ITEM_CIRCUIT_BREAKER_NAME = "reserve-item";
private static final String CHECK_RESERVE_MEANS = "realtime";
private final ReserveRepository reserveRepository;
private final ReserveItemServiceClient reserveItemServiceClient;
private final CircuitBreakerRegistry circuitBreakerRegistry;
private final StreamBridge streamBridge;
/**
* entity -> dto 변환
*
* @param reserve
* @return
*/
private Mono<ReserveResponseDto> convertReserveResponseDto(Reserve reserve) {
return Mono.just(ReserveResponseDto.builder()
.entity(reserve)
.build());
}
/**
* entity -> 목록 dto 변환
*
* @param reserve
* @return
*/
private Mono<ReserveListResponseDto> convertReserveListResponseDto(Reserve reserve) {
return Mono.just(ReserveListResponseDto.builder()
.entity(reserve)
.build());
}
/**
* 현재 로그인 사용자가 관리자인지 체크
*
* @return
*/
private Mono<Boolean> getIsAdmin() {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getAuthorities)
.map(grantedAuthorities -> {
List<SimpleGrantedAuthority> authorities =
new ArrayList<>((Collection<? extends SimpleGrantedAuthority>) grantedAuthorities);
SimpleGrantedAuthority adminRole = new SimpleGrantedAuthority(Role.ADMIN.getKey());
return authorities.contains(adminRole);
});
}
/**
* 현재 로그인 사용자 id
*
* @return
*/
private Mono<String> getUserId() {
return ReactiveSecurityContextHolder.getContext()
.map(SecurityContext::getAuthentication)
.filter(Authentication::isAuthenticated)
.map(Authentication::getPrincipal)
.map(String.class::cast);
}
/**
* 목록 조회
*
* @param requestDto
* @param pageable
* @return
*/
@Transactional(readOnly = true)
public Mono<Page<ReserveListResponseDto>> search(ReserveRequestDto requestDto, Pageable pageable) {
return reserveRepository.search(requestDto, pageable)
.switchIfEmpty(Flux.empty())
.flatMap(this::convertReserveListResponseDto)
.collectList()
.zipWith(reserveRepository.searchCount(requestDto, pageable))
.flatMap(tuple -> Mono.just(new PageImpl<>(tuple.getT1(), pageable, tuple.getT2())));
}
/**
* 한건 조회 dto return
*
* @param reserveId
* @return
*/
@Transactional(readOnly = true)
public Mono<ReserveResponseDto> findReserveById(String reserveId) {
return reserveRepository.findReserveById(reserveId)
.switchIfEmpty(monoResponseStatusEntityNotFoundException(reserveId))
.flatMap(this::convertReserveResponseDto);
}
/**
* 사용자용 예약 목록 조회 (로그인 사용자의 예약정보만 조회)
*
* @param userId
* @param requestDto
* @param pageable
* @return
*/
@Transactional(readOnly = true)
public Mono<Page<ReserveListResponseDto>> searchForUser(String userId, ReserveRequestDto requestDto, Pageable pageable) {
return reserveRepository.searchForUser(requestDto, pageable, userId)
.switchIfEmpty(Flux.empty())
.flatMap(this::convertReserveListResponseDto)
.collectList()
.zipWith(reserveRepository.searchCountForUser(requestDto, pageable, userId))
.flatMap(tuple -> Mono.just(new PageImpl<>(tuple.getT1(), pageable, tuple.getT2())));
}
/**
* 예약 정보 취소
*
* @param reserveId
* @param cancelRequestDto
* @return
*/
public Mono<Void> cancel(String reserveId, ReserveCancelRequestDto cancelRequestDto) {
return getIsAdmin().flatMap(isAdmin -> {
if (isAdmin) {
return reserveCancel(reserveId, cancelRequestDto);
}
return findById(reserveId)
.zipWith(getUserId())
.flatMap(tuple -> {
if (tuple.getT1().getUserId().equals(tuple.getT2())) {
return Mono.just(tuple.getT1());
}
//해당 예약은 취소할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.cant_cancel")));
})
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserve -> reserveCancel(reserveId, cancelRequestDto));
});
}
/**
* 예약 상태 취소로 변경
*
* @param reserveId
* @param cancelRequestDto
* @return
*/
private Mono<Void> reserveCancel(String reserveId, ReserveCancelRequestDto cancelRequestDto) {
return findById(reserveId)
.map(reserve -> {
if (ReserveStatus.DONE.isEquals(reserve.getReserveStatusId())) {
//해당 예약은 이미 실행되어 취소할 수 없습니다.
throw new BusinessMessageException(getMessage("valid.cant_cancel_because_done"));
}else {
return reserve.updateStatus(ReserveStatus.CANCEL.getKey())
.updateReasonCancel(cancelRequestDto.getReasonCancelContent());
}
})
.flatMap(reserve -> Mono.just(reserve.conversionReserveQty()))
.flatMap(this::updateInventory)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserve -> Mono.just(reserve.conversionReserveQty()))
.flatMap(reserveRepository::save)
.then();
}
/**
* 예약 정보 승인
*
* @param reserveId
* @return
*/
public Mono<Void> approve(String reserveId) {
return getIsAdmin()
.flatMap(isAdmin -> {
if (isAdmin) {
return Mono.just(reserveId);
}
//관리자만 승인할 수 있습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.manager_approve")));
})
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(this::checkApprove)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserveRepository::save).then();
}
/**
* 승인 전 validate check 및 교육인 경우 재고 업데이트
*
* @param reserveId
* @return
*/
private Mono<Reserve> checkApprove(String reserveId) {
return findById(reserveId)
.flatMap(this::checkReserveItems)
.onErrorResume(throwable -> Mono.error(throwable))
.map(reserve -> reserve.updateStatus(ReserveStatus.APPROVE.getKey()))
.flatMap(this::updateInventory);
}
/**
* 예약 물품 재고 및 예약 일자 체크
*
* @param reserve
* @return
*/
private Mono<Reserve> checkReserveItems(Reserve reserve) {
return reserveItemServiceClient.findById(reserve.getReserveItemId())
.transform(CircuitBreakerOperator.of(circuitBreakerRegistry.circuitBreaker(RESERVE_ITEM_CIRCUIT_BREAKER_NAME)))
.onErrorResume(throwable -> Mono.empty())
.flatMap(reserveItemResponseDto -> {
// validation check
if (Category.SPACE.isEquals(reserveItemResponseDto.getCategoryId())) {
return this.checkSpace(reserveItemResponseDto, reserve);
}else if (Category.EQUIPMENT.isEquals(reserveItemResponseDto.getCategoryId())) {
return this.checkEquipment(reserveItemResponseDto, reserve);
}else if (Category.EDUCATION.isEquals(reserveItemResponseDto.getCategoryId())) {
return this.checkEducation(reserveItemResponseDto, reserve);
}
return Mono.just(reserve);
});
}
/**
* 예약 날짜 validation
*
* @param reserveItem
* @param reserve
* @return
*/
private Mono<Reserve> checkReserveDate(ReserveItemResponseDto reserveItem, Reserve reserve) {
LocalDateTime startDate = reserveItem.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItem.getRequestStartDate() : reserveItem.getOperationStartDate();
LocalDateTime endDate = reserveItem.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItem.getRequestEndDate() : reserveItem.getOperationEndDate();
if (reserve.getReserveStartDate().isBefore(startDate)) {
//{0}이 {1} 보다 빠릅니다. 시작일, 운영/예약 시작일
return Mono.error(new BusinessMessageException(getMessage("valid.to_be_fast.format", new Object[]{getMessage("common.start_date"),
getMessage("reserve_item.operation")+getMessage("reserve")+" "+getMessage("common.start_date")})));
}
if (reserve.getReserveEndDate().isAfter(endDate)) {
//{0}이 {1} 보다 늦습니다. 종료일, 운영/예약 종료일
return Mono.error(new BusinessMessageException(getMessage("valid.to_be_slow.format", new Object[]{getMessage("common.end_date"),
getMessage("reserve_item.operation")+getMessage("reserve")+" "+getMessage("common.end_date")})));
}
if (reserveItem.getIsPeriod()) {
long between = ChronoUnit.DAYS.between(reserve.getReserveStartDate(), reserve.getReserveEndDate());
if (reserveItem.getPeriodMaxCount() < between) {
//최대 예약 가능 일수보다 예약기간이 깁니다. (최대 예약 가능일 수 : {0})
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_period", new Object[]{reserveItem.getPeriodMaxCount()})));
}
}
return Mono.just(reserve);
}
/**
* 공간 예약 시 예약 날짜에 다른 예약이 있는지 체크
*
* @param reserveItem
* @param reserve
* @return
*/
private Mono<Reserve> checkSpace(ReserveItemResponseDto reserveItem, Reserve reserve) {
return this.checkReserveDate(reserveItem, reserve)
.flatMap(isValid -> reserveRepository.findAllByReserveDateWithoutSelfCount(
reserve.getReserveId(),
reserveItem.getReserveItemId(),
reserve.getReserveStartDate(),
reserve.getReserveEndDate())
.flatMap(count -> {
if (count > 0) {
//"해당 날짜에는 예약할 수 없습니다."
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
return Mono.just(reserve);
})
);
}
/**
* 장비 예약 시 예약 날짜에 예약 가능한 재고 체크
*
* @param reserveItem
* @param reserve
* @return
*/
private Mono<Reserve> checkEquipment(ReserveItemResponseDto reserveItem, Reserve reserve) {
return this.checkReserveDate(reserveItem, reserve)
.flatMap(entity -> this.getMaxByReserveDateWithoutSelf(
entity.getReserveId(),
reserveItem.getReserveItemId(),
entity.getReserveStartDate(),
entity.getReserveEndDate())
.flatMap(max -> {
if ((reserveItem.getTotalQty() - max) < reserve.getReserveQty()) {
return Mono.just(false);
}
return Mono.just(true);
})
.flatMap(isValid -> {
if (!isValid) {
//해당 날짜에 예약할 수 있는 재고수량이 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_count")));
}
return Mono.just(reserve);
})
);
}
/**
* 교육 예약 시 재고 체크
*
* @param reserveItem
* @param reserve
* @return
*/
private Mono<Reserve> checkEducation(ReserveItemResponseDto reserveItem, Reserve reserve) {
return Mono.just(reserveItem)
.flatMap(reserveItemResponseDto -> {
LocalDateTime now = LocalDateTime.now();
LocalDateTime startDate = reserveItemResponseDto.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItemResponseDto.getRequestStartDate() : reserveItemResponseDto.getOperationStartDate();
LocalDateTime endDate = reserveItemResponseDto.getReserveMeansId().equals(CHECK_RESERVE_MEANS) ?
reserveItemResponseDto.getRequestEndDate() : reserveItemResponseDto.getOperationEndDate();
if (!(now.isAfter(startDate) && now.isBefore(endDate))) {
//해당 날짜에는 예약할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
if (reserveItemResponseDto.getInventoryQty() <= 0) {
//"예약이 마감되었습니다."
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_close")));
}
if (reserveItemResponseDto.getInventoryQty() < reserve.getReserveQty()) {
//예약가능한 인원이 부족합니다. (남은 인원 : {0})
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_number_of_people", new Object[]{reserveItemResponseDto.getInventoryQty()})));
}
return Mono.just(reserve);
});
}
/**
* 예약 정보 수정
*
* @param reserveId
* @return
*/
public Mono<Reserve> update(String reserveId, ReserveUpdateRequestDto updateRequestDto) {
return getIsAdmin().flatMap(isAdmin -> {
if (isAdmin) {
return updateReserve(reserveId, updateRequestDto);
}
return updateReserveForUser(reserveId, updateRequestDto);
});
}
/**
* 사용자 예약 수정
*
* @param reserveId
* @param updateRequestDto
* @return
*/
private Mono<Reserve> updateReserveForUser(String reserveId, ReserveUpdateRequestDto updateRequestDto) {
return findById(reserveId)
.zipWith(getUserId())
.map(tuple -> {
if (!tuple.getT1().getUserId().equals(tuple.getT2())) {
//"해당 예약은 수정할 수 없습니다."
throw new BusinessMessageException(getMessage("valid.reserve_not_update"));
}
if (!ReserveStatus.REQUEST.getKey().equals(tuple.getT1().getReserveStatusId())) {
//예약 신청 상태인 경우에만 수정 가능합니다.
throw new BusinessMessageException(getMessage("valid.reserve_not_update_status"));
}
return tuple.getT1().update(updateRequestDto);
})
.flatMap(this::checkReserveItems)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(this::updateInventory)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserveRepository::save);
}
/**
* 관리자 예약 수정
*
* @param reserveId
* @param updateRequestDto
* @return
*/
private Mono<Reserve> updateReserve(String reserveId, ReserveUpdateRequestDto updateRequestDto) {
return findById(reserveId)
.map(reserve -> {
if (!ReserveStatus.REQUEST.getKey().equals(reserve.getReserveStatusId())) {
//예약 신청 상태인 경우에만 수정 가능합니다.
throw new BusinessMessageException(getMessage("valid.reserve_not_update_status"));
}
return reserve.update(updateRequestDto);
})
.flatMap(this::checkReserveItems)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(this::updateInventory)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserveRepository::save);
}
/**
* 한건 정보 조회 entity return
*
* @param reserveId
* @return
*/
private Mono<Reserve> findById(String reserveId) {
return reserveRepository.findById(reserveId)
.switchIfEmpty(monoResponseStatusEntityNotFoundException(reserveId));
}
/**
* 관리자 예약 신청
* 관리자의 경우 실시간이어도 이벤트 스트림 거치지 않고 바로 예약 처리
*
* @param saveRequestDto
* @return
*/
public Mono<ReserveResponseDto> create(ReserveSaveRequestDto saveRequestDto) {
return Mono.just(saveRequestDto)
.map(dto -> {
String uuid = UUID.randomUUID().toString();
dto.setReserveId(uuid);
return dto.toEntity();
})
.zipWith(getUserId())
.flatMap(tuple -> Mono.just(tuple.getT1().setCreatedInfo(LocalDateTime.now(), tuple.getT2())))
.flatMap(this::checkReserveItems)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(this::updateInventory)
.onErrorResume(throwable -> Mono.error(throwable))
.flatMap(reserveRepository::insert)
.flatMap(reserveRepository::loadRelations)
.doOnNext(reserve -> sendAttachmentEntityInfo(streamBridge,
AttachmentEntityMessage.builder()
.attachmentCode(reserve.getAttachmentCode())
.entityName(reserve.getClass().getName())
.entityId(reserve.getReserveId())
.build()))
.flatMap(this::convertReserveResponseDto);
}
/**
* 예약 정보 저장 시 재고 변경
*
* @param reserve
* @return
*/
private Mono<Reserve> updateInventory(Reserve reserve) {
return Mono.just(reserve)
.flatMap(reserve1 -> {
if (!Category.EDUCATION.isEquals(reserve1.getCategoryId())) {
return Mono.just(reserve1);
}
return reserveItemServiceClient.updateInventory(reserve.getReserveItemId(), reserve.getReserveQty())
.transform(CircuitBreakerOperator.of(circuitBreakerRegistry.circuitBreaker(RESERVE_ITEM_CIRCUIT_BREAKER_NAME)))
.onErrorResume(throwable -> Mono.just(false))
.flatMap(isSuccess -> {
if (isSuccess) {
return Mono.just(reserve);
}
//재고 업데이트에 실패했습니다.
return Mono.error(new BusinessMessageException(getMessage("msg.inventory_failed")));
});
});
}
/**
* 예약 물품별 기간안에 있는 예약된 수량 max 조회
*
* @param reserveItemId
* @param startDate
* @param endDate
* @return
*/
public Mono<Integer> countInventory(Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
return reserveItemServiceClient.findById(reserveItemId)
.transform(CircuitBreakerOperator.of(circuitBreakerRegistry.circuitBreaker(RESERVE_ITEM_CIRCUIT_BREAKER_NAME)))
.onErrorResume(throwable -> Mono.empty())
.zipWith(getMaxByReserveDate(reserveItemId, startDate, endDate))
.log("countinventory")
.flatMap(tuple -> Mono.just(tuple.getT1().getTotalQty() - tuple.getT2()));
}
/**
* 예약물품에 대해 날짜별 예약된 수량 max 조회
* 현 예약 건 제외
*
* @param reserveItemId
* @param startDate
* @param endDate
* @return
*/
private Mono<Integer> getMaxByReserveDateWithoutSelf(String reserveId, Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
Flux<Reserve> reserveFlux = reserveRepository.findAllByReserveDateWithoutSelf(reserveId, reserveItemId, startDate, endDate)
.switchIfEmpty(Flux.empty());
return countMax(reserveFlux, startDate, endDate);
}
/**
* 예약물품에 대해 날짜별 예약된 수량 max 조회
*
* @param reserveItemId
* @param startDate
* @param endDate
* @return
*/
private Mono<Integer> getMaxByReserveDate(Long reserveItemId, LocalDateTime startDate, LocalDateTime endDate) {
Flux<Reserve> reserveFlux = reserveRepository.findAllByReserveDate(reserveItemId, startDate, endDate)
.switchIfEmpty(Flux.empty());
return countMax(reserveFlux, startDate, endDate);
}
/**
* get max
*
* @param reserveFlux
* @param startDate
* @param endDate
* @return
*/
private Mono<Integer> countMax(Flux<Reserve> reserveFlux, LocalDateTime startDate, LocalDateTime endDate) {
if (reserveFlux.equals(Flux.empty())) {
return Mono.just(0);
}
long between = ChronoUnit.DAYS.between(startDate, endDate);
if (between == 0) {
return reserveFlux.map(reserve -> {
if (startDate.isAfter(reserve.getReserveStartDate())
|| startDate.isBefore(reserve.getReserveEndDate())
|| startDate.isEqual(reserve.getReserveStartDate()) || startDate.isEqual(reserve.getReserveEndDate())) {
return reserve.getReserveQty();
}
return 0;
}).reduce(0, (x1, x2) -> x1 + x2);
}
return Flux.fromStream(IntStream.iterate(0, i -> i + 1)
.limit(between)
.mapToObj(i -> startDate.plusDays(i)))
.flatMap(localDateTime ->
reserveFlux.map(findReserve -> {
if (localDateTime.isAfter(findReserve.getReserveStartDate())
|| localDateTime.isBefore(findReserve.getReserveEndDate())
|| localDateTime.isEqual(findReserve.getReserveStartDate()) || localDateTime.isEqual(findReserve.getReserveEndDate())) {
return findReserve.getReserveQty();
}
return 0;
}).reduce(0, (x1, x2) -> x1 + x2))
.groupBy(integer -> integer)
.flatMap(group -> group.reduce((x1,x2) -> x1 > x2?x1:x2))
.last(0);
}
}

View File

@@ -2,22 +2,19 @@ package org.egovframe.cloud.reservechecksevice.validator;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import javax.annotation.Resource;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.util.MessageUtil;
import org.egovframe.cloud.reservechecksevice.validator.annotation.ReserveSaveValid;
import org.springframework.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
/**
* org.egovframe.cloud.reservechecksevice.validator.ReserveSaveValidator
*
* <p>
* 예약 신청 시 validation check를 하기 위한 custom validator
*
* @author 표준프레임워크센터 shinmj
@@ -42,6 +39,7 @@ public class ReserveSaveValidator implements ConstraintValidator<ReserveSaveVali
protected MessageUtil messageUtil;
private String message;
private boolean fieldValid;
@Override
@@ -59,24 +57,28 @@ public class ReserveSaveValidator implements ConstraintValidator<ReserveSaveVali
@SneakyThrows
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
boolean fieldValid = true;
fieldValid = true;
String categoryId = String.valueOf(getFieldValue(value, "categoryId"));
if ("education".equals(categoryId)) {
//교육인 경우
//신청인원
fieldValid = checkReserveQty(value, context);
return checkReserveQty(value, context);
}
}else if ("equipment".equals(categoryId)) {
if ("equipment".equals(categoryId)) {
//장비인 경우
//신청일자(기간), 신청수량
fieldValid = checkReserveDate(value, context);
fieldValid = checkReserveQty(value, context);
}else if ("place".equals(categoryId)) {
return fieldValid;
}
if ("place".equals(categoryId)) {
//공간인 경우
//신청일자(기간)
fieldValid = checkReserveDate(value, context);
return checkReserveDate(value, context);
}
return fieldValid;
@@ -94,12 +96,14 @@ public class ReserveSaveValidator implements ConstraintValidator<ReserveSaveVali
if (isNull(value, "reserveQty")) {
context.disableDefaultConstraintViolation();
//예약 수량 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve")+" "+messageUtil.getMessage("reserve.count") + messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveQty")
.addConstraintViolation();
context.buildConstraintViolationWithTemplate(
messageUtil.getMessage("reserve") + " " + messageUtil.getMessage("reserve.count")
+ messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveQty")
.addConstraintViolation();
return false;
}
return true;
return fieldValid;
}
/**
@@ -115,31 +119,41 @@ public class ReserveSaveValidator implements ConstraintValidator<ReserveSaveVali
if (isNull(value, "reserveStartDate")) {
context.disableDefaultConstraintViolation();
// 예약 신청 시작일 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.request")+" "+messageUtil.getMessage("common.start_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveStartDate")
.addConstraintViolation();
context.buildConstraintViolationWithTemplate(
messageUtil.getMessage("reserve_item.request") + " " + messageUtil
.getMessage("common.start_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveStartDate")
.addConstraintViolation();
return false;
} else if (isNull(value, "reserveEndDate")) {
}
if (isNull(value, "reserveEndDate")) {
context.disableDefaultConstraintViolation();
// 예약 신청 종료일 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.request")+" "+messageUtil.getMessage("common.end_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveEndDate")
.addConstraintViolation();
context.buildConstraintViolationWithTemplate(
messageUtil.getMessage("reserve_item.request") + " " + messageUtil
.getMessage("common.end_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveEndDate")
.addConstraintViolation();
return false;
}else {
// 예약 시작일, 종료일 체크
LocalDateTime reserveStartDate = (LocalDateTime) getFieldValue(value, "reserveStartDate");
LocalDateTime reserveEndDate = (LocalDateTime) getFieldValue(value, "reserveEndDate");
if (reserveStartDate.isAfter(reserveEndDate)) {
context.disableDefaultConstraintViolation();
//시작일, 종료일, {0}이 {1}보다 늦습니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("valid.to_be_slow.format", new Object[]{messageUtil.getMessage("common.start_date"), messageUtil.getMessage("common.end_date")}))
.addPropertyNode("reserveStartDate")
.addConstraintViolation();
return false;
}
}
return true;
// 예약 시작일, 종료일 체크
LocalDateTime reserveStartDate = (LocalDateTime) getFieldValue(value, "reserveStartDate");
LocalDateTime reserveEndDate = (LocalDateTime) getFieldValue(value, "reserveEndDate");
if (reserveStartDate.isAfter(reserveEndDate)) {
context.disableDefaultConstraintViolation();
//시작일, 종료일, {0}이 {1}보다 늦습니다.
context.buildConstraintViolationWithTemplate(messageUtil
.getMessage("valid.to_be_slow.format",
new Object[]{messageUtil.getMessage("common.start_date"),
messageUtil.getMessage("common.end_date")}))
.addPropertyNode("reserveStartDate")
.addConstraintViolation();
return false;
}
return fieldValid;
}
/**
@@ -151,7 +165,8 @@ public class ReserveSaveValidator implements ConstraintValidator<ReserveSaveVali
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private Object getFieldValue(Object object, String fieldName) throws NoSuchFieldException, IllegalAccessException {
private Object getFieldValue(Object object, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Class<?> clazz = object.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
@@ -167,10 +182,12 @@ public class ReserveSaveValidator implements ConstraintValidator<ReserveSaveVali
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private boolean isNull(Object object, String fieldName) throws NoSuchFieldException, IllegalAccessException {
private boolean isNull(Object object, String fieldName)
throws NoSuchFieldException, IllegalAccessException {
Class<?> clazz = object.getClass();
Field field = clazz.getDeclaredField(fieldName);
field.setAccessible(true);
return field.get(object) == null || !StringUtils.hasLength(String.valueOf(field.get(object)));
return field.get(object) == null || !StringUtils
.hasLength(String.valueOf(field.get(object)));
}
}

View File

@@ -1,27 +1,26 @@
package org.egovframe.cloud.reservechecksevice.api;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assertions.*;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import java.time.LocalDateTime;
import org.egovframe.cloud.common.domain.Role;
import org.egovframe.cloud.common.exception.dto.ErrorCode;
import org.egovframe.cloud.common.exception.dto.ErrorResponse;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveCancelRequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveListResponseDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveSaveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.reserve.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveCancelRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveListResponseDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveSaveRequestDto;
import org.egovframe.cloud.reservechecksevice.api.dto.ReserveUpdateRequestDto;
import org.egovframe.cloud.reservechecksevice.client.ReserveItemServiceClient;
import org.egovframe.cloud.reservechecksevice.client.UserServiceClient;
import org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemRelationResponseDto;
import org.egovframe.cloud.reservechecksevice.client.dto.ReserveItemResponseDto;
import org.egovframe.cloud.reservechecksevice.client.dto.UserResponseDto;
import org.egovframe.cloud.reservechecksevice.domain.Reserve;
import org.egovframe.cloud.reservechecksevice.domain.ReserveItem;
import org.egovframe.cloud.reservechecksevice.domain.ReserveRepository;
import org.egovframe.cloud.reservechecksevice.domain.ReserveStatus;
import org.egovframe.cloud.reservechecksevice.domain.location.Location;
import org.egovframe.cloud.reservechecksevice.domain.reserve.Reserve;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveItem;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveRepository;
import org.egovframe.cloud.reservechecksevice.domain.reserve.ReserveStatus;
import org.egovframe.cloud.reservechecksevice.util.RestResponsePage;
import org.egovframe.cloud.reservechecksevice.util.WithCustomMockUser;
import org.junit.jupiter.api.AfterEach;
@@ -34,11 +33,9 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestPropertySource;
import org.springframework.test.web.reactive.server.WebTestClient;
import reactor.core.publisher.Mono;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@@ -59,8 +56,6 @@ public class ReserveApiControllerTest {
@Autowired
private WebTestClient webTestClient;
@Autowired
private R2dbcEntityTemplate entityTemplate;
private static final String API_URL = "/api/v1/reserves";
@@ -118,7 +113,7 @@ public class ReserveApiControllerTest {
}
@Test
public void 예약신청관리_목록_조회_성공() throws Exception {
public void 예약신청관리_목록_조회_성공() {
//given
BDDMockito.when(userServiceClient.findByUserId(ArgumentMatchers.anyString()))
.thenReturn(Mono.just(user));
@@ -146,7 +141,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 관리자_취소_성공() throws Exception {
public void 관리자_취소_성공() {
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
@@ -189,7 +184,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "test", role = Role.USER)
public void 다른사용자_예약_취소_실패() throws Exception {
public void 다른사용자_예약_취소_실패() {
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
.thenReturn(Mono.just(true));
Reserve saved = reserveRepository.insert(reserve).block();
@@ -209,7 +204,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 예약상태_완료_취소_실패() throws Exception {
public void 예약상태_완료_취소_실패() {
Reserve done = reserve.updateStatus(ReserveStatus.DONE.getKey());
Reserve saved = reserveRepository.insert(done).block();
assertNotNull(saved);
@@ -231,7 +226,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 관리자가_아닌_경우_승인_실패() throws Exception {
public void 관리자가_아닌_경우_승인_실패() {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
@@ -252,7 +247,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 예약승인_성공() throws Exception {
public void 예약승인_성공() {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
@@ -274,7 +269,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 예약승인_실패_재고부족() throws Exception {
public void 예약승인_실패_재고부족() {
ReserveItem failReserveItem = ReserveItem.builder()
.reserveItemId(1L)
.reserveItemName("test")
@@ -313,7 +308,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "admin", role = Role.ADMIN)
public void 관리자_예약정보_수정_성공() throws Exception {
public void 관리자_예약정보_수정_성공() {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
@@ -351,7 +346,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "test", role = Role.USER)
public void 다른사용자_예약정보_수정_실패() throws Exception {
public void 다른사용자_예약정보_수정_실패() {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
@@ -387,7 +382,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 사용자_예약정보_수정_성공() throws Exception {
public void 사용자_예약정보_수정_성공() {
Reserve saved = reserveRepository.insert(reserve).block();
assertNotNull(saved);
@@ -426,7 +421,7 @@ public class ReserveApiControllerTest {
@Test
@WithCustomMockUser(userId = "user", role = Role.USER)
public void 사용자_상태승인인예약정보_수정_실패() throws Exception {
public void 사용자_상태승인인예약정보_수정_실패() {
Reserve failedReserve = reserve.withReserveStatusId(ReserveStatus.APPROVE.getKey());
Reserve saved = reserveRepository.insert(failedReserve).block();
assertNotNull(saved);
@@ -463,7 +458,7 @@ public class ReserveApiControllerTest {
}
@Test
public void 관리자_예약_성공() throws Exception {
public void 관리자_예약_성공() {
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));
BDDMockito.when(reserveItemServiceClient.updateInventory(ArgumentMatchers.anyLong(), ArgumentMatchers.anyInt()))
@@ -495,7 +490,7 @@ public class ReserveApiControllerTest {
}
@Test
public void 예약신청_valid_실패() throws Exception {
public void 예약신청_valid_실패() {
ReserveItem validReserveItem = ReserveItem.builder()
.reserveItemId(1L)
.reserveItemName("test")
@@ -532,7 +527,7 @@ public class ReserveApiControllerTest {
}
@Test
public void 물품재고조회_성공() throws Exception {
public void 물품재고조회_성공() {
BDDMockito.when(reserveItemServiceClient.findById(ArgumentMatchers.anyLong()))
.thenReturn(Mono.just(ReserveItemResponseDto.builder().reserveItem(reserveItem).build()));