use of alfio.model.Audit.EntityType.RESERVATION in project alf.io by alfio-event.
the class AdminReservationManager method confirmReservation.
// the following methods have an explicit transaction handling, therefore the @Transactional annotation is not helpful here
Result<Triple<TicketReservation, List<Ticket>, PurchaseContext>> confirmReservation(PurchaseContextType purchaseContextType, String eventName, String reservationId, String username, Notification notification, UUID subscriptionId) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionTemplate template = new TransactionTemplate(transactionManager, definition);
return template.execute(status -> {
try {
Result<Triple<TicketReservation, List<Ticket>, PurchaseContext>> result = purchaseContextManager.findBy(purchaseContextType, eventName).map(purchaseContext -> ticketReservationRepository.findOptionalReservationById(reservationId).filter(r -> r.getStatus() == TicketReservationStatus.PENDING || r.getStatus() == TicketReservationStatus.STUCK).map(r -> performConfirmation(reservationId, purchaseContext, r, notification, username, subscriptionId)).orElseGet(() -> Result.error(ErrorCode.ReservationError.UPDATE_FAILED))).orElseGet(() -> Result.error(ErrorCode.ReservationError.NOT_FOUND));
if (!result.isSuccess()) {
log.debug("Reservation confirmation failed for eventName: {} reservationId: {}, username: {}", eventName, reservationId, username);
status.setRollbackOnly();
}
return result;
} catch (Exception e) {
log.error("Error during confirmation of reservation eventName: {} reservationId: {}, username: {}", eventName, reservationId, username);
status.setRollbackOnly();
return Result.error(singletonList(ErrorCode.custom("", e.getMessage())));
}
});
}
use of alfio.model.Audit.EntityType.RESERVATION in project alf.io by alfio-event.
the class AdminReservationManager method updateReservation.
public Result<Boolean> updateReservation(PurchaseContextType purchaseContextType, String publicIdentifier, String reservationId, AdminReservationModification adminReservationModification, String username) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
TransactionTemplate template = new TransactionTemplate(transactionManager, definition);
return template.execute(status -> {
try {
Result<Boolean> result = purchaseContextManager.findBy(purchaseContextType, publicIdentifier).map(event -> ticketReservationRepository.findOptionalReservationById(reservationId).map(r -> performUpdate(reservationId, event, r, adminReservationModification, username)).orElseGet(() -> Result.error(ErrorCode.ReservationError.UPDATE_FAILED))).orElseGet(() -> Result.error(ErrorCode.ReservationError.NOT_FOUND));
if (!result.isSuccess()) {
log.debug("Application error detected eventName: {} reservationId: {}, username: {}, reservation: {}", publicIdentifier, reservationId, username, AdminReservationModification.summary(adminReservationModification));
status.setRollbackOnly();
}
return result;
} catch (Exception e) {
log.error("Error during update of reservation eventName: {} reservationId: {}, username: {}, reservation: {}", publicIdentifier, reservationId, username, AdminReservationModification.summary(adminReservationModification));
status.setRollbackOnly();
return Result.error(singletonList(ErrorCode.custom("", e.getMessage())));
}
});
}
use of alfio.model.Audit.EntityType.RESERVATION in project alf.io by alfio-event.
the class AdminReservationManager method createReservation.
public Result<Pair<TicketReservation, List<Ticket>>> createReservation(AdminReservationModification input, String eventName, String username) {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition(TransactionDefinition.PROPAGATION_NESTED);
TransactionTemplate template = new TransactionTemplate(transactionManager, definition);
return template.execute(status -> {
var savepoint = status.createSavepoint();
try {
Result<Pair<TicketReservation, List<Ticket>>> result = eventRepository.findOptionalByShortNameForUpdate(eventName).map(e -> validateTickets(input, e)).map(r -> r.flatMap(p -> transactionalCreateReservation(p.getRight(), p.getLeft(), username))).orElse(Result.error(ErrorCode.EventError.NOT_FOUND));
if (!result.isSuccess()) {
log.debug("Error during update of reservation eventName: {}, username: {}, reservation: {}", eventName, username, AdminReservationModification.summary(input));
status.rollbackToSavepoint(savepoint);
}
return result;
} catch (Exception e) {
log.error("Error during update of reservation eventName: {}, username: {}, reservation: {}", eventName, username, AdminReservationModification.summary(input));
status.rollbackToSavepoint(savepoint);
return Result.error(singletonList(ErrorCode.custom(e instanceof DuplicateReferenceException ? "duplicate-reference" : "", e.getMessage())));
}
});
}
use of alfio.model.Audit.EntityType.RESERVATION 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.Audit.EntityType.RESERVATION in project alf.io by alfio-event.
the class TicketReservationManager method sendAssignmentReminder.
private void sendAssignmentReminder(Pair<Event, Set<String>> p) {
try {
nestedTransactionTemplate.execute(ts -> {
Event event = p.getLeft();
var messageSource = messageSourceManager.getMessageSourceFor(event);
ZoneId eventZoneId = event.getZoneId();
int quietPeriod = configurationManager.getFor(ASSIGNMENT_REMINDER_INTERVAL, ConfigurationLevel.event(event)).getValueAsIntOrDefault(3);
p.getRight().stream().map(id -> findByIdForNotification(id, clockProvider.withZone(eventZoneId), quietPeriod)).filter(Optional::isPresent).map(Optional::get).forEach(reservation -> {
Map<String, Object> model = prepareModelForReservationEmail(event, reservation);
ticketReservationRepository.updateLatestReminderTimestamp(reservation.getId(), ZonedDateTime.now(clockProvider.withZone(eventZoneId)));
Locale locale = findReservationLanguage(reservation.getId());
notificationManager.sendSimpleEmail(event, reservation.getId(), reservation.getEmail(), messageSource.getMessage("reminder.ticket-not-assigned.subject", new Object[] { event.getDisplayName() }, locale), () -> templateManager.renderTemplate(event, TemplateResource.REMINDER_TICKETS_ASSIGNMENT_EMAIL, model, locale));
});
return null;
});
} catch (Exception ex) {
log.warn("cannot send reminder message", ex);
}
}
Aggregations