/*
* Copyright (C) 2013-2017 NTT DATA Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package org.terasoluna.tourreservation.domain.service.reserve;
import java.util.List;
import javax.inject.Inject;
import lombok.extern.slf4j.Slf4j;
import org.dozer.Mapper;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.terasoluna.gfw.common.date.jodatime.JodaTimeDateFactory;
import org.terasoluna.gfw.common.exception.BusinessException;
import org.terasoluna.gfw.common.message.ResultMessages;
import org.terasoluna.tourreservation.domain.common.constants.MessageId;
import org.terasoluna.tourreservation.domain.model.Reserve;
import org.terasoluna.tourreservation.domain.model.TourInfo;
import org.terasoluna.tourreservation.domain.repository.reserve.ReserveRepository;
import org.terasoluna.tourreservation.domain.service.tourinfo.PriceCalculateOutput;
import org.terasoluna.tourreservation.domain.service.tourinfo.PriceCalculateSharedService;
import org.terasoluna.tourreservation.domain.service.tourinfo.TourInfoSharedService;
@Slf4j
@Transactional
@Service
public class ReserveServiceImpl implements ReserveService {
@Inject
ReserveRepository reserveRepository;
@Inject
AuthorizedReserveSharedService authorizedReserveSharedService;
@Inject
TourInfoSharedService tourInfoSharedService;
@Inject
PriceCalculateSharedService priceCalculateService;
@Inject
JodaTimeDateFactory dateFactory;
@Inject
Mapper beanMapper;
@Override
public Reserve findOneWithTourInfo(String reserveNo) {
Reserve reserve = authorizedReserveSharedService.findOne(reserveNo);
if (reserve != null) {
TourInfo tourInfo = tourInfoSharedService
.findOneWithDetails(reserve.getTourInfo().getTourCode());
reserve.setTourInfo(tourInfo);
}
return reserve;
}
@Override
public List<Reserve> findAllWithTourInfoByCustomer(String customerCode) {
List<Reserve> reserves = reserveRepository
.findAllWithTourInfoByCustomer(customerCode);
return reserves;
}
@Override
public ReserveTourOutput reserve(ReserveTourInput input) throws BusinessException {
TourInfo tourInfo = tourInfoSharedService
.findOneWithDetailsForUpdate(input.getTourCode());
DateTime today = dateFactory.newDateTime().withTime(0, 0, 0, 0);
// * check date
// error if today is after payment limit
if (tourInfoSharedService.isOverPaymentLimit(tourInfo)) {
ResultMessages message = ResultMessages.error().add(
MessageId.E_TR_0004);
throw new BusinessException(message);
}
// * check vacancy
int reserveMember = input.getAdultCount() + input.getChildCount();
int aveRecMax = tourInfo.getAvaRecMax();
// retrieve the number of current reservations
Long sumCount = reserveRepository
.countReservedPersonSumByTourInfo(tourInfo.getTourCode());
if (sumCount == null) {
sumCount = 0L;
}
// calculate vacancy
long vacantCount = aveRecMax - sumCount;
log.debug("vacantCount({}), reserveMember({})", vacantCount,
reserveMember);
// error if reserved number is larger than available vacancy
if (vacantCount < reserveMember) {
ResultMessages message = ResultMessages.error().add(
MessageId.E_TR_0005);
throw new BusinessException(message);
}
// * reserve
PriceCalculateOutput priceCalculateOutput = priceCalculateService
.calculatePrice(tourInfo.getBasePrice(), input.getAdultCount(),
input.getChildCount());
Reserve reserve = beanMapper.map(input, Reserve.class);
reserve.setTourInfo(tourInfo);
reserve.setSumPrice(priceCalculateOutput.getSumPrice());
reserve.setReservedDay(today.toDate());
reserve.setTransfer(Reserve.NOT_TRANSFERED);
reserveRepository.insert(reserve);
log.debug("reserved {}", reserve);
// * create output
ReserveTourOutput tourReserveOutput = new ReserveTourOutput();
tourReserveOutput.setPriceCalculateOutput(priceCalculateOutput);
tourReserveOutput.setReserve(reserve);
tourReserveOutput.setTourInfo(tourInfo);
tourReserveOutput.setPaymentTimeLimit(tourInfo.getPaymentLimit()
.toDate());
tourReserveOutput.setCustomer(input.getCustomer());
return tourReserveOutput;
}
@Override
public void cancel(String reserveNo) throws BusinessException {
Reserve reserve = findOneWithTourInfo(reserveNo);
String transfer = reserve.getTransfer();
if (Reserve.TRANSFERED.equals(transfer)) {
ResultMessages message = ResultMessages.error().add(
MessageId.E_TR_0001);
throw new BusinessException(message);
}
TourInfo info = tourInfoSharedService.findOneWithDetails(reserve
.getTourInfo().getTourCode());
// compare system date and payment limit.
// if the payment limit has been exceeded,
// navigate to business error screen
if (tourInfoSharedService.isOverPaymentLimit(info)) {
ResultMessages message = ResultMessages.error().add(
MessageId.E_TR_0002);
throw new BusinessException(message);
}
// cancel the reservation
// reserve = reserveRepository.findForUpdate(reserveNo); TODO
reserve = reserveRepository.findOneForUpdate(reserveNo);
if (reserve != null) {
reserveRepository.delete(reserveNo);
} else {
ResultMessages message = ResultMessages.error().add(
MessageId.E_TR_0003);
throw new BusinessException(message);
}
log.debug("canceled reserveNo={}", reserveNo);
}
@Override
public ReservationUpdateOutput update(ReservationUpdateInput input) throws BusinessException {
Reserve reserve = findOneWithTourInfo(input.getReserveNo());
beanMapper.map(input, reserve, "reserve_map_nonnull");
TourInfo info = reserve.getTourInfo();
PriceCalculateOutput price = priceCalculateService.calculatePrice(info
.getBasePrice(), input.getAdultCount(), input.getChildCount());
reserve.setSumPrice(price.getSumPrice());
reserveRepository.update(reserve);
ReservationUpdateOutput output = new ReservationUpdateOutput();
output.setReserve(reserve);
output.setPriceCalculateOutput(price);
output.setPaymentTimeLimit(info.getPaymentLimit().toDate());
return output;
}
}