use of alfio.model.modification.AdditionalServiceReservationModification in project alf.io by alfio-event.
the class TicketReservationManager method createTicketReservation.
/**
* Create a ticket reservation. It will create a reservation _only_ if it can find enough tickets. Note that it will not do date/validity validation. This must be ensured by the
* caller.
*
* @param event
* @param list
* @param reservationExpiration
* @param forWaitingQueue
* @return
*/
public String createTicketReservation(Event event, List<TicketReservationWithOptionalCodeModification> list, List<ASReservationWithOptionalCodeModification> additionalServices, Date reservationExpiration, Optional<String> promotionCodeDiscount, Locale locale, boolean forWaitingQueue, Principal principal) throws NotEnoughTicketsException, MissingSpecialPriceTokenException, InvalidSpecialPriceTokenException {
String reservationId = UUID.randomUUID().toString();
Optional<PromoCodeDiscount> discount = promotionCodeDiscount.flatMap(promoCodeDiscount -> promoCodeDiscountRepository.findPromoCodeInEventOrOrganization(event.getId(), promoCodeDiscount));
Optional<PromoCodeDiscount> dynamicDiscount = createDynamicPromoCode(discount, event, list, reservationId);
ticketReservationRepository.createNewReservation(reservationId, event.now(clockProvider), reservationExpiration, dynamicDiscount.or(() -> discount).map(PromoCodeDiscount::getId).orElse(null), locale.getLanguage(), event.getId(), event.getVat(), event.isVatIncluded(), event.getCurrency(), event.getOrganizationId(), retrievePublicUserId(principal));
list.forEach(t -> reserveTicketsForCategory(event, reservationId, t, locale, forWaitingQueue, discount.orElse(null), dynamicDiscount.orElse(null)));
int ticketCount = list.stream().map(TicketReservationWithOptionalCodeModification::getQuantity).mapToInt(Integer::intValue).sum();
// apply valid additional service with supplement policy mandatory one for ticket
additionalServiceRepository.findAllInEventWithPolicy(event.getId(), AdditionalService.SupplementPolicy.MANDATORY_ONE_FOR_TICKET).stream().filter(AdditionalService::getSaleable).forEach(as -> {
AdditionalServiceReservationModification asrm = new AdditionalServiceReservationModification();
asrm.setAdditionalServiceId(as.getId());
asrm.setQuantity(ticketCount);
reserveAdditionalServicesForReservation(event.getId(), reservationId, new ASReservationWithOptionalCodeModification(asrm, Optional.empty()), discount.orElse(null));
});
additionalServices.forEach(as -> reserveAdditionalServicesForReservation(event.getId(), reservationId, as, discount.orElse(null)));
var totalPrice = totalReservationCostWithVAT(reservationId).getLeft();
var vatStatus = event.getVatStatus();
ticketReservationRepository.updateBillingData(event.getVatStatus(), calculateSrcPrice(vatStatus, totalPrice), totalPrice.getPriceWithVAT(), totalPrice.getVAT(), Math.abs(totalPrice.getDiscount()), event.getCurrency(), null, null, false, reservationId);
auditingRepository.insert(reservationId, null, event.getId(), Audit.EventType.RESERVATION_CREATE, new Date(), Audit.EntityType.RESERVATION, reservationId);
if (isDiscountCodeUsageExceeded(reservationId)) {
throw new TooManyTicketsForDiscountCodeException();
}
if (!canProceedWithPayment(event, totalPrice, reservationId)) {
throw new CannotProceedWithPayment("No payment method applicable for categories " + list.stream().map(t -> String.valueOf(t.getTicketCategoryId())).collect(Collectors.joining(", ")));
}
return reservationId;
}
use of alfio.model.modification.AdditionalServiceReservationModification in project alf.io by alfio-event.
the class ReservationForm method validate.
public Optional<Pair<List<TicketReservationWithOptionalCodeModification>, List<ASReservationWithOptionalCodeModification>>> validate(Errors bindingResult, TicketReservationManager tickReservationManager, AdditionalServiceRepository additionalServiceRepository, EventManager eventManager, Event event) {
int selectionCount = ticketSelectionCount();
if (selectionCount <= 0) {
bindingResult.reject(ErrorsCode.STEP_1_SELECT_AT_LEAST_ONE);
return Optional.empty();
}
List<Pair<TicketReservationModification, Integer>> maxTicketsByTicketReservation = selected().stream().map(r -> Pair.of(r, tickReservationManager.maxAmountOfTicketsForCategory(event.getOrganizationId(), event.getId(), r.getTicketCategoryId()))).collect(toList());
Optional<Pair<TicketReservationModification, Integer>> error = maxTicketsByTicketReservation.stream().filter(p -> p.getKey().getAmount() > p.getValue()).findAny();
if (error.isPresent()) {
bindingResult.reject(ErrorsCode.STEP_1_OVER_MAXIMUM, new Object[] { error.get().getValue() }, null);
return Optional.empty();
}
final List<TicketReservationModification> categories = selected();
final List<AdditionalServiceReservationModification> additionalServices = selectedAdditionalServices();
final boolean validCategorySelection = categories.stream().allMatch(c -> {
TicketCategory tc = eventManager.getTicketCategoryById(c.getTicketCategoryId(), event.getId());
return OptionalWrapper.optionally(() -> eventManager.findEventByTicketCategory(tc)).isPresent();
});
final boolean validAdditionalServiceSelected = additionalServices.stream().allMatch(asm -> {
AdditionalService as = eventManager.getAdditionalServiceById(asm.getAdditionalServiceId(), event.getId());
ZonedDateTime now = ZonedDateTime.now(event.getZoneId());
return as.getInception(event.getZoneId()).isBefore(now) && as.getExpiration(event.getZoneId()).isAfter(now) && asm.getQuantity() >= 0 && ((as.isFixPrice() && asm.isQuantityValid(as, selectionCount)) || (!as.isFixPrice() && asm.getAmount() != null && asm.getAmount().compareTo(BigDecimal.ZERO) >= 0)) && OptionalWrapper.optionally(() -> eventManager.findEventByAdditionalService(as)).isPresent();
});
if (!validCategorySelection || !validAdditionalServiceSelected) {
bindingResult.reject(ErrorsCode.STEP_1_TICKET_CATEGORY_MUST_BE_SALEABLE);
return Optional.empty();
}
List<TicketReservationWithOptionalCodeModification> res = new ArrayList<>();
//
Optional<SpecialPrice> specialCode = Optional.ofNullable(StringUtils.trimToNull(promoCode)).flatMap((trimmedCode) -> tickReservationManager.getSpecialPriceByCode(trimmedCode));
//
final ZonedDateTime now = ZonedDateTime.now(event.getZoneId());
maxTicketsByTicketReservation.forEach((pair) -> validateCategory(bindingResult, tickReservationManager, eventManager, event, pair.getRight(), res, specialCode, now, pair.getLeft()));
return bindingResult.hasErrors() ? Optional.empty() : Optional.of(Pair.of(res, additionalServices.stream().map(as -> new ASReservationWithOptionalCodeModification(as, specialCode)).collect(Collectors.toList())));
}
use of alfio.model.modification.AdditionalServiceReservationModification in project alf.io by alfio-event.
the class TicketReservationManager method createTicketReservation.
/**
* Create a ticket reservation. It will create a reservation _only_ if it can find enough tickets. Note that it will not do date/validity validation. This must be ensured by the
* caller.
*
* @param event
* @param list
* @param reservationExpiration
* @param forWaitingQueue
* @return
*/
public String createTicketReservation(Event event, List<TicketReservationWithOptionalCodeModification> list, List<ASReservationWithOptionalCodeModification> additionalServices, Date reservationExpiration, Optional<String> specialPriceSessionId, Optional<String> promotionCodeDiscount, Locale locale, boolean forWaitingQueue) throws NotEnoughTicketsException, MissingSpecialPriceTokenException, InvalidSpecialPriceTokenException {
String reservationId = UUID.randomUUID().toString();
Optional<PromoCodeDiscount> discount = promotionCodeDiscount.flatMap((promoCodeDiscount) -> promoCodeDiscountRepository.findPromoCodeInEventOrOrganization(event.getId(), promoCodeDiscount));
ticketReservationRepository.createNewReservation(reservationId, reservationExpiration, discount.map(PromoCodeDiscount::getId).orElse(null), locale.getLanguage(), event.getId(), event.getVat(), event.isVatIncluded());
list.forEach(t -> reserveTicketsForCategory(event, specialPriceSessionId, reservationId, t, locale, forWaitingQueue, discount.orElse(null)));
int ticketCount = list.stream().map(TicketReservationWithOptionalCodeModification::getAmount).mapToInt(Integer::intValue).sum();
// apply valid additional service with supplement policy mandatory one for ticket
additionalServiceRepository.findAllInEventWithPolicy(event.getId(), AdditionalService.SupplementPolicy.MANDATORY_ONE_FOR_TICKET).stream().filter(AdditionalService::getSaleable).forEach(as -> {
AdditionalServiceReservationModification asrm = new AdditionalServiceReservationModification();
asrm.setAdditionalServiceId(as.getId());
asrm.setQuantity(ticketCount);
reserveAdditionalServicesForReservation(event.getId(), reservationId, new ASReservationWithOptionalCodeModification(asrm, Optional.empty()), discount.orElse(null));
});
additionalServices.forEach(as -> reserveAdditionalServicesForReservation(event.getId(), reservationId, as, discount.orElse(null)));
TicketReservation reservation = ticketReservationRepository.findReservationById(reservationId);
OrderSummary orderSummary = orderSummaryForReservationId(reservation.getId(), event, Locale.forLanguageTag(reservation.getUserLanguage()));
ticketReservationRepository.addReservationInvoiceOrReceiptModel(reservationId, Json.toJson(orderSummary));
auditingRepository.insert(reservationId, null, event.getId(), Audit.EventType.RESERVATION_CREATE, new Date(), Audit.EntityType.RESERVATION, reservationId);
return reservationId;
}
use of alfio.model.modification.AdditionalServiceReservationModification in project alf.io by alfio-event.
the class ReservationUtil method validateCreateRequest.
public static Optional<Pair<List<TicketReservationWithOptionalCodeModification>, List<ASReservationWithOptionalCodeModification>>> validateCreateRequest(ReservationCreate request, Errors bindingResult, TicketReservationManager tickReservationManager, EventManager eventManager, String validatedPromoCodeDiscount, Event event) {
int selectionCount = ticketSelectionCount(request.getTickets());
if (selectionCount <= 0) {
bindingResult.reject(ErrorsCode.STEP_1_SELECT_AT_LEAST_ONE);
return Optional.empty();
}
List<Pair<TicketReservationModification, Integer>> maxTicketsByTicketReservation = selected(request.getTickets()).stream().map(r -> Pair.of(r, tickReservationManager.maxAmountOfTicketsForCategory(event, r.getTicketCategoryId(), validatedPromoCodeDiscount))).collect(toList());
Optional<Pair<TicketReservationModification, Integer>> error = maxTicketsByTicketReservation.stream().filter(p -> p.getKey().getQuantity() > p.getValue()).findAny();
if (error.isPresent()) {
bindingResult.reject(ErrorsCode.STEP_1_OVER_MAXIMUM, new Object[] { error.get().getValue() }, null);
return Optional.empty();
}
final List<TicketReservationModification> categories = selected(request.getTickets());
final List<AdditionalServiceReservationModification> additionalServices = selectedAdditionalServices(request.getAdditionalServices());
final boolean validCategorySelection = categories.stream().allMatch(c -> {
TicketCategory tc = eventManager.getTicketCategoryById(c.getTicketCategoryId(), event.getId());
return eventManager.eventExistsById(tc.getEventId());
});
final boolean validAdditionalServiceSelected = additionalServices.stream().allMatch(asm -> {
AdditionalService as = eventManager.getAdditionalServiceById(asm.getAdditionalServiceId(), event.getId());
ZonedDateTime now = event.now(ClockProvider.clock());
return as.getInception(event.getZoneId()).isBefore(now) && as.getExpiration(event.getZoneId()).isAfter(now) && asm.getQuantity() >= 0 && ((as.isFixPrice() && asm.isQuantityValid(as, selectionCount)) || (!as.isFixPrice() && asm.getAmount() != null && asm.getAmount().compareTo(BigDecimal.ZERO) >= 0)) && eventManager.eventExistsById(as.getEventId());
});
if (!validCategorySelection || !validAdditionalServiceSelected) {
bindingResult.reject(ErrorsCode.STEP_1_TICKET_CATEGORY_MUST_BE_SALEABLE);
return Optional.empty();
}
List<TicketReservationWithOptionalCodeModification> res = new ArrayList<>();
//
Optional<SpecialPrice> specialCode = Optional.ofNullable(StringUtils.trimToNull(request.getPromoCode())).flatMap(tickReservationManager::getSpecialPriceByCode);
//
final ZonedDateTime now = event.now(ClockProvider.clock());
maxTicketsByTicketReservation.forEach(pair -> validateCategory(bindingResult, tickReservationManager, eventManager, event, pair.getRight(), res, specialCode, now, pair.getLeft()));
return bindingResult.hasErrors() ? Optional.empty() : Optional.of(Pair.of(res, additionalServices.stream().map(as -> new ASReservationWithOptionalCodeModification(as, specialCode)).collect(Collectors.toList())));
}
Aggregations