TimeBookApp.java
package sk.iway.iwcm.components.reservation;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ModelAttribute;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Getter;
import lombok.Setter;
import sk.iway.iwcm.Identity;
import sk.iway.iwcm.Logger;
import sk.iway.iwcm.Tools;
import sk.iway.iwcm.components.WebjetComponentAbstract;
import sk.iway.iwcm.components.reservation.jpa.ReservationEditorFields;
import sk.iway.iwcm.components.reservation.jpa.ReservationEntity;
import sk.iway.iwcm.components.reservation.jpa.ReservationObjectEntity;
import sk.iway.iwcm.components.reservation.jpa.ReservationObjectPriceRepository;
import sk.iway.iwcm.components.reservation.jpa.ReservationObjectRepository;
import sk.iway.iwcm.components.reservation.jpa.ReservationRepository;
import sk.iway.iwcm.components.reservation.rest.ReservationService;
import sk.iway.iwcm.i18n.Prop;
import sk.iway.iwcm.system.annotations.DefaultHandler;
import sk.iway.iwcm.system.annotations.WebjetAppStore;
import sk.iway.iwcm.system.annotations.WebjetComponent;
import sk.iway.iwcm.system.datatable.DataTableColumnType;
import sk.iway.iwcm.system.datatable.ProcessItemAction;
import sk.iway.iwcm.system.datatable.annotations.DataTableColumn;
import sk.iway.iwcm.system.datatable.annotations.DataTableColumnEditor;
import sk.iway.iwcm.system.datatable.annotations.DataTableColumnEditorAttr;
import sk.iway.iwcm.system.jpa.DefaultTimeValueConverter;
import sk.iway.iwcm.users.UsersDB;
@WebjetComponent("sk.iway.iwcm.components.reservation.TimeBookApp")
@WebjetAppStore(nameKey = "components.reservation.time_book.title", descKey="components.reservation.time_book.desc", imagePath = "ti ti-calendar-check text-success bg-light", galleryImages = "/apps/reservation/mvc/app-page.png", commonSettings = true)
@Getter
@Setter
public class TimeBookApp extends WebjetComponentAbstract {
@JsonIgnore
private ReservationObjectRepository ror;
@JsonIgnore
private ReservationRepository rr;
@JsonIgnore
private ReservationObjectPriceRepository ropr;
private static final String VIEW_PATH = "/apps/reservation/mvc/time-book"; //NOSONAR
private static final String ERROR_MSG = "components.reservation.reservation_app.save_error";
@Autowired
public TimeBookApp(ReservationObjectRepository ror, ReservationRepository rr, ReservationObjectPriceRepository ropr) {
this.ror = ror;
this.rr = rr;
this.ropr = ropr;
}
//Choose reservation object
@DataTableColumn(inputType = DataTableColumnType.MULTISELECT, title = "components.reservation.time_book.reservation_object_ids", tab = "basic", editor = {
@DataTableColumnEditor(
options = {
@DataTableColumnEditorAttr(key = "method:sk.iway.iwcm.components.reservation.rest.ReservationService.getReservationObjectHoursSelectList", value = "label:value")
}
)
})
private String reservationObjectIds;
@Override
public void init(HttpServletRequest request, HttpServletResponse response) {
Logger.debug(TimeBookApp.class, "Init of TimeBookApp app");
}
@DefaultHandler
public String view(Model model, HttpServletRequest request)
{
prepareTimeBookApp(model, request, null);
return VIEW_PATH;
}
public String saveForm(@Valid @ModelAttribute("entity") ReservationEntity entity, BindingResult result, Model model, HttpServletRequest request) {
//Remove errors about timeFrom-timeTo this fields are sent in separe param
List<ObjectError> realErrors = new ArrayList<>();
for(ObjectError err : result.getAllErrors()) {
FieldError ferr = (FieldError) err;
if(ferr.getField().equals("dateFrom") || ferr.getField().equals("dateTo")) {
continue;
}
realErrors.add(err);
}
if(Tools.isEmail(entity.getEmail()) == false) {
realErrors.add(new FieldError("entity", "email", Prop.getInstance(request).getText("javax.validation.constraints.Email.message")));
}
if(Tools.isEmpty(realErrors)) {
Prop prop = Prop.getInstance(request);
Long reservationObjectId = Tools.getLongValue(request.getParameter("reservationObjectId"), -1);
if(reservationObjectId == -1) {
return returnError(prop.getText(ERROR_MSG), model, request);
}
String reservationDateString = request.getParameter("reservationDateHidden");
Date reservationDate;
if(reservationDateString.matches(ReservationService.REGEX_YYYY_MM_DD)) {
reservationDate = Tools.getDateFromString(reservationDateString, ReservationService.FE_DATEPICKER_FORMAT);
} else {
return returnError(prop.getText(ERROR_MSG), model, request);
}
String[] timeRange = Tools.getTokens(request.getParameter("timeRange"), "-");
if(timeRange.length != 2) {
return returnError(prop.getText(ERROR_MSG), model, request);
}
//Remove ":00" postfix
timeRange[0] = timeRange[0].substring(0, timeRange[0].length()-3);
timeRange[1] = timeRange[1].substring(0, timeRange[1].length()-3);
Date timeFrom = DefaultTimeValueConverter.getValidTimeValue(Integer.valueOf(timeRange[0]), 0, 1);
Date timeTo = DefaultTimeValueConverter.getValidTimeValue(Integer.valueOf(timeRange[1]), 0);
entity.setReservationObjectId(reservationObjectId);
entity.setDateFrom( DefaultTimeValueConverter.combineDateWithTime(reservationDate, timeFrom) );
entity.setDateTo( DefaultTimeValueConverter.combineDateWithTime(reservationDate, timeTo) );
try {
ReservationObjectEntity roe = ror.findById(entity.getReservationObjectId()).orElse(null);
if(roe == null) {
return returnError(prop.getText(ERROR_MSG), model, request);
}
entity.setReservationObjectForReservation(roe);
ReservationEditorFields ref = new ReservationEditorFields();
ref.toReservationEntity(entity, rr, request, true, false, ProcessItemAction.CREATE);
} catch (Exception e) {
return returnError( e.getLocalizedMessage(), model, request);
}
//Its CREATE, reservationId is by default -1
int userId = ReservationService.getUserToPay(entity.getEmail(), Long.valueOf(-1), rr, request);
entity.setUserId(userId);
entity.setPrice( ReservationService.calculateReservationPrice(reservationDate, reservationDate, timeFrom, timeTo, reservationObjectId, userId, ror, ropr) );
boolean isAccepted = ReservationService.acceptation(entity, request);
rr.save(entity);
//After save send mail
ReservationService reservationService = new ReservationService(prop);
reservationService.sendCreatedReservationEmail(entity, request);
//Add suitable message
if(isAccepted) {
model.addAttribute("saveMsg", prop.getText("components.reservation.reservation_app.save_msg"));
} else {
model.addAttribute("saveMsg", prop.getText("components.reservation.reservation_app.save_msg_acceptation"));
}
prepareTimeBookApp(model, request, entity.getDateFrom());
return VIEW_PATH;
}
prepareTimeBookApp(model, request, entity.getDateFrom());
model.addAttribute("errors", realErrors);
model.addAttribute("reservationEntity", entity);
return VIEW_PATH;
}
private void prepareTimeBookApp(Model model, HttpServletRequest request, Date setReservationDate) {
if(Tools.isEmpty(reservationObjectIds)) return;
Integer[] ids = Arrays.stream( Tools.getTokensInt(reservationObjectIds, "+") ).boxed().toArray( Integer[]::new );
List<ReservationObjectEntity> reservationObjectList = ror.findAllByIdIn(ids);
Date reservationDate;
if(setReservationDate != null) {
reservationDate = setReservationDate;
} else {
reservationDate = ReservationService.getReservationDate(request.getParameter("reservation-date"), ReservationService.FE_DATEPICKER_FORMAT);
}
//datepicker require yyyy-MM-dd string as value
SimpleDateFormat format = new SimpleDateFormat(ReservationService.FE_DATEPICKER_FORMAT);
model.addAttribute("reservationDate", format.format(reservationDate));
/* Prepare list with hour that represent reservation range (joined by all reservation objects range) */
Long minTimeStart = Long.MAX_VALUE;
Long maxTimeEnd = Long.MIN_VALUE;
Map<Long, Long[]> timeRanges = new HashMap<>();
for(ReservationObjectEntity roe : reservationObjectList) {
Long[] timeRange = ReservationService.getReservationTimeRange(reservationDate, roe);
timeRanges.put(roe.getId(), timeRange);
if(timeRange[0] < minTimeStart) minTimeStart = timeRange[0];
if(timeRange[1] > maxTimeEnd) maxTimeEnd = timeRange[1];
}
List<String> hours = ReservationService.getHoursForTable(minTimeStart, maxTimeEnd);
model.addAttribute("hours", hours);
/* Figure out, how many reservations for current hour and reservation object are already used */
Map<String, List<ReservationService.ReservationTableCell>> tableLines = new HashMap<>();
for(ReservationObjectEntity roe : reservationObjectList) {
tableLines.put(roe.getName(), ReservationService.computeReservationUsageByHours(roe, rr, minTimeStart, maxTimeEnd, timeRanges.get(roe.getId())));
}
model.addAttribute("tableLines", tableLines);
ReservationEntity reservation = new ReservationEntity();
Identity user = UsersDB.getCurrentUser(request);
if(user != null) {
reservation.setName(user.getFirstName());
reservation.setSurname(user.getLastName());
reservation.setEmail(user.getEmail());
}
model.addAttribute("reservationEntity", reservation);
}
public String returnError(String errorMsg, Date reservationDate, Model model, HttpServletRequest request) {
request.setAttribute("reservationDate", reservationDate);
return returnError(errorMsg, model, request);
}
public String returnError(String errorMsg, Model model, HttpServletRequest request) {
model.addAttribute("customError", errorMsg);
prepareTimeBookApp(model, request, null);
return VIEW_PATH;
}
}