This commit is contained in:
jooho
2021-10-26 09:37:45 +09:00
parent bb73c32473
commit fd50dd78a0
41 changed files with 520 additions and 583 deletions

View File

@@ -14,6 +14,7 @@ import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemRes
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemSaveRequestDto;
import org.egovframe.cloud.reserveitemservice.api.reserveItem.dto.ReserveItemUpdateRequestDto;
import org.egovframe.cloud.reserveitemservice.service.reserveItem.ReserveItemService;
import org.springframework.core.env.Environment;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
@@ -55,6 +56,21 @@ public class ReserveItemApiController {
private final ReserveItemService reserveItemService;
private final Environment env;
/**
* 서비스 상태 확인
*
* @return
*/
@GetMapping("/actuator/health-info")
public String status() {
return String.format("GET Reserve Item Service on" +
"\n local.server.port :" + env.getProperty("local.server.port")
+ "\n egov.message :" + env.getProperty("egov.message")
);
}
/**
* 목록 조회
*
@@ -148,7 +164,7 @@ public class ReserveItemApiController {
@GetMapping("/api/v1/reserve-items/relations/{reserveItemId}")
@ResponseStatus(HttpStatus.OK)
public Mono<ReserveItemRelationResponseDto> findByIdWithRelations(@PathVariable Long reserveItemId) {
return reserveItemService.findByIdWithRelations(reserveItemId).log();
return reserveItemService.findByIdWithRelations(reserveItemId);
}
/**

View File

@@ -45,49 +45,18 @@ public class ReserveItemListResponseDto {
private Boolean isPossible; //예약 가능 여부
@Builder
public ReserveItemListResponseDto(ReserveItem reserveItem) {
this.reserveItemId = reserveItem.getReserveItemId();
this.reserveItemName = reserveItem.getReserveItemName();
this.locationId = reserveItem.getLocationId();
this.locationName = reserveItem.getLocation().getLocationName();
this.categoryId = reserveItem.getCategoryId();
this.categoryName = reserveItem.getCategoryName();
this.totalQty = reserveItem.getTotalQty();
this.inventoryQty = reserveItem.getInventoryQty();
this.isUse = reserveItem.getIsUse();
this.createDate = reserveItem.getCreateDate();
this.isPossible = isReservationPossible(reserveItem);
}
/**
* 예약 가능 여부 체크
*
* @param reserveItem
* @return
*/
private boolean isReservationPossible(ReserveItem reserveItem) {
LocalDateTime now = LocalDateTime.now();
if (!reserveItem.getIsUse()) {
return false;
}
if (reserveItem.getInventoryQty() <= 0) {
return false;
}
if (reserveItem.getIsPeriod()) {
if (reserveItem.getRequestStartDate().isBefore(now) && reserveItem.getRequestEndDate().isAfter(now)) {
return true;
}else {
return false;
}
} else {
if (reserveItem.getOperationStartDate().isBefore(now) && reserveItem.getOperationEndDate().isAfter(now)) {
return true;
}else {
return false;
}
}
public ReserveItemListResponseDto(ReserveItem entity) {
this.reserveItemId = entity.getReserveItemId();
this.reserveItemName = entity.getReserveItemName();
this.locationId = entity.getLocationId();
this.locationName = entity.getLocation().getLocationName();
this.categoryId = entity.getCategoryId();
this.categoryName = entity.getCategoryName();
this.totalQty = entity.getTotalQty();
this.inventoryQty = entity.getInventoryQty();
this.isUse = entity.getIsUse();
this.createDate = entity.getCreateDate();
this.isPossible = entity.isReservationPossible();
}
}

View File

@@ -36,38 +36,7 @@ public class ReserveItemMainResponseDto {
this.endDate = entity.getRequestEndDate();
}
}
this.isPossible = isReservationPossible(entity);
}
/**
* 예약 가능 여부 체크
*
* @param entity
* @return
*/
private boolean isReservationPossible(ReserveItem entity) {
LocalDateTime now = LocalDateTime.now();
if (!entity.getIsUse()) {
return false;
}
if (entity.getInventoryQty() <= 0) {
return false;
}
if (entity.getIsPeriod()) {
if (entity.getRequestStartDate().isBefore(now) && entity.getRequestEndDate().isAfter(now)) {
return true;
}else {
return false;
}
} else {
if (entity.getOperationStartDate().isBefore(now) && entity.getOperationEndDate().isAfter(now)) {
return true;
}else {
return false;
}
}
this.isPossible = entity.isReservationPossible();
}
}

View File

@@ -66,6 +66,7 @@ public class ReserveItemRelationResponseDto {
private String managerDept; //담당자 소속
private String managerName; //담당자 이름
private String managerContact; //담당자 연락처
private Boolean isPossible; //예약 가능 여부
@Builder
public ReserveItemRelationResponseDto(ReserveItem entity) {
@@ -103,8 +104,9 @@ public class ReserveItemRelationResponseDto {
this.managerDept = entity.getManagerDept();
this.managerName = entity.getManagerName();
this.managerContact = entity.getManagerContact();
this.isPossible = entity.isReservationPossible();
}
}

View File

@@ -332,10 +332,46 @@ public class ReserveItem extends BaseEntity {
return this;
}
/**
* 생성일 세팅
*
* @param createDate
* @return
*/
public ReserveItem setCreateDate(LocalDateTime createDate) {
this.createDate = createDate;
return this;
}
/**
* 예약 가능 여부 체크
*
* @return
*/
public Boolean isReservationPossible() {
if (!this.getIsUse()) {
return false;
}
if (this.getInventoryQty() <= 0) {
return false;
}
LocalDateTime now = LocalDateTime.now();
if (this.getReserveMethodId().equals("internet") && this.getReserveMeansId().equals("realtime")) {
if (this.getRequestStartDate().isBefore(now) && this.getRequestEndDate().isAfter(now)) {
return true;
}else {
return false;
}
} else {
if (this.getOperationStartDate().isBefore(now) && this.getOperationEndDate().isAfter(now)) {
return true;
}else {
return false;
}
}
}
}

View File

@@ -33,9 +33,6 @@ public interface ReserveItemRepositoryCustom {
Flux<ReserveItem> search(ReserveItemRequestDto requestDto, Pageable pageable);
Mono<Long> searchCount(ReserveItemRequestDto requestDto, Pageable pageable);
Flux<ReserveItem> searchForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable);
Mono<Long> searchCountForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable);
Mono<ReserveItem> findWithRelation(Long reserveItemId);
Flux<ReserveItem> findLatestByCategory(Integer count, String categoryId);

View File

@@ -77,42 +77,6 @@ public class ReserveItemRepositoryImpl implements ReserveItemRepositoryCustom{
.count();
}
@Override
public Flux<ReserveItem> searchForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable) {
Criteria where = Criteria.from(whereQuery(requestDto));
if (!"all".equals(categoryId)) {
where = where.and(where("category_id").is(categoryId));
}
Query query = Query.query(where("use_at").isTrue().and(where))
.sort(Sort.by(Sort.Direction.DESC, "create_date"))
.with(pageable);
return entityTemplate.select(ReserveItem.class)
.matching(query)
.all()
.flatMap(this::loadRelations)
.switchIfEmpty(Flux.empty());
}
@Override
public Mono<Long> searchCountForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable) {
Criteria where = Criteria.from(whereQuery(requestDto));
if (!"all".equals(categoryId)) {
where = where.and(where("category_id").is(categoryId));
}
Query query = Query.query(where("use_at").isTrue().and(where))
.sort(Sort.by(Sort.Direction.DESC, "create_date"))
.with(pageable);
return entityTemplate.select(ReserveItem.class)
.matching(query)
.count();
}
/**
* relation 걸린 table 정보도 같이 조회
* 공통코드, 지역
@@ -258,11 +222,11 @@ public class ReserveItemRepositoryImpl implements ReserveItemRepositoryCustom{
}
}
if (requestDto.getLocationId() != null) {
if (requestDto.getLocationId() != null && !"null".equals(requestDto.getLocationId()) && !"undefined".equals(requestDto.getLocationId())) {
whereCriteria.add(where("location_id").in(requestDto.getLocationId()));
}
if (requestDto.getCategoryId() != null ) {
if (requestDto.getCategoryId() != null && !"null".equals(requestDto.getCategoryId()) && !"undefined".equals(requestDto.getCategoryId())) {
whereCriteria.add(where("category_id").in(requestDto.getCategoryId()));
}
@@ -271,6 +235,7 @@ public class ReserveItemRepositoryImpl implements ReserveItemRepositoryCustom{
whereCriteria.add(where("use_at").isTrue());
whereCriteria.add(where("reserve_method_id").is("internet"));
}
System.out.println(whereCriteria.toString());
return whereCriteria;
}

View File

@@ -165,7 +165,7 @@ public class LocationService extends ReactiveAbstractService {
.switchIfEmpty(monoResponseStatusEntityNotFoundException(locationId))
.flatMap(locationRepository::delete)
.onErrorResume(DataIntegrityViolationException.class,
throwable -> Mono.error(new BusinessMessageException("참조하는 데이터가 있어 삭제할 수 없습니다.")));
throwable -> Mono.error(new BusinessMessageException(getMessage("err.db.constraint.delete"))));
}
/**

View File

@@ -1,5 +1,6 @@
package org.egovframe.cloud.reserveitemservice.service.reserveItem;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.Collections;
@@ -79,7 +80,7 @@ public class ReserveItemService extends ReactiveAbstractService {
* @return
*/
private Mono<ReserveItemListResponseDto> convertReserveItemListResponseDto(ReserveItem reserveItem) {
return Mono.just(ReserveItemListResponseDto.builder().reserveItem(reserveItem).build());
return Mono.just(ReserveItemListResponseDto.builder().entity(reserveItem).build());
}
/**
@@ -108,10 +109,13 @@ public class ReserveItemService extends ReactiveAbstractService {
*/
@Transactional(readOnly = true)
public Mono<Page<ReserveItemListResponseDto>> searchForUser(String categoryId, ReserveItemRequestDto requestDto, Pageable pageable) {
return reserveItemRepository.searchForUser(categoryId, requestDto, pageable)
if (!"all".equals(categoryId)) {
requestDto.setCategoryId(categoryId);
}
return reserveItemRepository.search(requestDto, pageable)
.flatMap(this::convertReserveItemListResponseDto)
.collectList()
.zipWith(reserveItemRepository.searchCountForUser(categoryId, requestDto, pageable))
.zipWith(reserveItemRepository.searchCount(requestDto, pageable))
.flatMap(tuple -> Mono.just(new PageImpl<>(tuple.getT1(), pageable, tuple.getT2())));
}
@@ -200,22 +204,26 @@ public class ReserveItemService extends ReactiveAbstractService {
.switchIfEmpty(monoResponseStatusEntityNotFoundException(reserveItemId))
.flatMap(reserveItem -> {
if (!Category.EDUCATION.isEquals(reserveItem.getCategoryId())) {
return Mono.error(new BusinessMessageException("저장할 수 없습니다."));
//해당 예약은 수정할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_not_update")));
}
LocalDateTime now = LocalDateTime.now();
if (!(now.isAfter(reserveItem.getRequestStartDate()) && now.isBefore(reserveItem.getRequestEndDate()))) {
return Mono.error(new BusinessMessageException("예약 가능 일자가 아닙니다."));
//해당 날짜에는 예약할 수 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_date")));
}
int qty = reserveItem.getInventoryQty() - reserveQty;
if (qty < 0) {
return Mono.error(new BusinessMessageException("재고가 없습니다."));
//해당 날짜에 예약할 수 있는 재고수량이 없습니다.
return Mono.error(new BusinessMessageException(getMessage("valid.reserve_count")));
}
return Mono.just(reserveItem.updateInventoryQty(qty));
})
.flatMap(reserveItemRepository::save)
.delayElement(Duration.ofSeconds(5))
.publishOn(Schedulers.boundedElastic())
.doOnNext(reserveItem -> {
log.info("reserve item inventory updated success");

View File

@@ -2,9 +2,12 @@ package org.egovframe.cloud.reserveitemservice.validator;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.egovframe.cloud.common.util.MessageUtil;
import org.egovframe.cloud.reserveitemservice.validator.annotation.ReserveItemSaveValid;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.reflect.Field;
@@ -30,6 +33,11 @@ import java.time.LocalDateTime;
@Slf4j
public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItemSaveValid, Object> {
@Resource(
name = "messageUtil"
)
protected MessageUtil messageUtil;
private String message;
@Override
@@ -54,7 +62,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
LocalDateTime operationEndDate = (LocalDateTime) getFieldValue(value, "operationEndDate");
if (operationStartDate.isAfter(operationEndDate)) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("시작일 종료일 보다 니다.")
//시작일, 종료일, {0}이 {1}보다 늦습니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("valid.to_be_slow.format", new Object[]{messageUtil.getMessage("common.start_date"), messageUtil.getMessage("common.end_date")}))
.addPropertyNode("operationStartDate")
.addConstraintViolation();
fieldValid = false;
@@ -66,7 +75,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
// 예약 구분 필수
if (isNull(value, "reserveMeansId")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 예약 구분은 필수입니다.")
//인터넷 예약 구분은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.reserve_means")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("reserveMeansId")
.addConstraintViolation();
fieldValid = false;
@@ -77,24 +87,28 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
// 예약 신청 기간 필수
if (isNull(value, "requestStartDate")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 예약 신청 시작 기간은 필수입니다.")
.addPropertyNode("requestStartDate")
.addConstraintViolation();
// 예약 신청 시작일 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.request")+" "+messageUtil.getMessage("common.start_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("requestStartDate")
.addConstraintViolation();
fieldValid = false;
} else if (isNull(value, "requestEndDate")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 예약 신청 종료 기간은 필수입니다.")
.addPropertyNode("requestEndDate")
.addConstraintViolation();
// 예약 신청 종료일 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.request")+" "+messageUtil.getMessage("common.end_datetime") + messageUtil.getMessage("valid.required"))
.addPropertyNode("requestEndDate")
.addConstraintViolation();
fieldValid = false;
}else {
LocalDateTime requestStartDate = (LocalDateTime) getFieldValue(value, "requestStartDate");
LocalDateTime requestEndDate = (LocalDateTime) getFieldValue(value, "requestEndDate");
if (requestStartDate.isAfter(requestEndDate)) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("시작일 종료일 보다 니다.")
.addPropertyNode("requestStartDate")
.addConstraintViolation();
//시작일, 종료일, {0}이 {1}보다 늦습니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("valid.to_be_slow.format", new Object[]{messageUtil.getMessage("common.start_date"), messageUtil.getMessage("common.end_date")}))
.addPropertyNode("requestStartDate")
.addConstraintViolation();
fieldValid = false;
}
}
@@ -102,7 +116,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//기간 지정 필수
if (isNull(value, "isPeriod")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("인터넷 예약인 경우 기간 지정 여부는 필수입니다.")
//기간 지정 가능 여부 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.period_possible")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("requestEndDate")
.addConstraintViolation();
fieldValid = false;
@@ -111,7 +126,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
// 기간 지정 가능인 경우 최대 얘약일 수 필수
if (isPeriod && isNull(value, "periodMaxCount")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("기간 지정이 가능인 경우 최대 예약 일수는 필수입니다.")
//최대 예약 가능 일수 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.max_period_days")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("periodMaxCount")
.addConstraintViolation();
fieldValid = false;
@@ -121,7 +137,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//예약 구분이 외부 링크인 경우 외부 링크 url 필수
if (isNull(value, "externalUrl")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("예약 구분이 외부링크인 경우 외부링크 url 값은 필수입니다.")
//외부링크 URL 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.external_url")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("externalUrl")
.addConstraintViolation();
fieldValid = false;
@@ -132,7 +149,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//예약 방법인 '전화'인 경우 contact 필수
if (isNull(value, "contact")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("전화예약인 경우 문의처는 필수입니다.")
//문의처 값은 필수입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.contact")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("contact")
.addConstraintViolation();
fieldValid = false;
@@ -141,7 +159,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
//예약 방법인 '방문'인 경우 주소 필수
if (isNull(value, "address")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("방문예약인 경우 주소는 필수입니다.")
//주소 값은 필수 입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("common.address")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("address")
.addConstraintViolation();
fieldValid = false;
@@ -152,7 +171,8 @@ public class ReserveItemSaveValidator implements ConstraintValidator<ReserveItem
Boolean isPaid = Boolean.valueOf(String.valueOf(getFieldValue(value, "isPaid")));
if (isPaid && isNull(value, "usageCost")) {
context.disableDefaultConstraintViolation();
context.buildConstraintViolationWithTemplate("유료인 경우 이용 요금은 필수입니다.")
//이용요금은 필수입니다.
context.buildConstraintViolationWithTemplate(messageUtil.getMessage("reserve_item.usage_fee")+ messageUtil.getMessage("valid.required"))
.addPropertyNode("usageCost")
.addConstraintViolation();
fieldValid = false;