diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 5472f459ea..83a72f13fc 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -379,28 +379,13 @@ public PaymentResult confirm(String gatewayToken, String payerId, Event event, S try { PaymentResult paymentResult; ticketReservationRepository.lockReservationForUpdate(reservationId); + //save billing data in case we have to go back to PENDING + ticketReservationRepository.updateBillingData(vatStatus, vatNr, vatCountryCode, invoiceRequested, reservationId); if(isDiscountCodeUsageExceeded(reservationId)) { return PaymentResult.unsuccessful(ErrorsCode.STEP_2_DISCOUNT_CODE_USAGE_EXCEEDED); } - if(reservationCost.getPriceWithVAT() > 0) { - if(invoiceRequested && configurationManager.hasAllConfigurationsForInvoice(event)) { - int invoiceSequence = invoiceSequencesRepository.lockReservationForUpdate(event.getOrganizationId()); - invoiceSequencesRepository.incrementSequenceFor(event.getOrganizationId()); - String pattern = configurationManager.getStringConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ConfigurationKeys.INVOICE_NUMBER_PATTERN), "%d"); - ticketReservationRepository.setInvoiceNumber(reservationId, String.format(pattern, invoiceSequence)); - } - ticketReservationRepository.updateBillingData(vatStatus, vatNr, vatCountryCode, invoiceRequested, reservationId); - - // - extensionManager.handleInvoiceGeneration(event, reservationId, - email, customerName, userLanguage, billingAddress, customerReference, - reservationCost, invoiceRequested, vatCountryCode, vatNr, vatStatus).ifPresent(invoiceGeneration -> { - if (invoiceGeneration.getInvoiceNumber() != null) { - ticketReservationRepository.setInvoiceNumber(reservationId, invoiceGeneration.getInvoiceNumber()); - } - }); - - // + boolean toBePaid = reservationCost.getPriceWithVAT() > 0; + if(toBePaid) { switch(paymentProxy) { case STRIPE: paymentResult = paymentManager.processStripePayment(reservationId, gatewayToken, reservationCost.getPriceWithVAT(), event, email, customerName, billingAddress); @@ -429,6 +414,12 @@ public PaymentResult confirm(String gatewayToken, String payerId, Event event, S } else { paymentResult = PaymentResult.successful(NOT_YET_PAID_TRANSACTION_ID); } + if(!paymentResult.isSuccessful()) { + return paymentResult; + } + if(toBePaid) { + generateInvoiceNumber(event, reservationId, email, customerName, userLanguage, billingAddress, customerReference, reservationCost, invoiceRequested, vatCountryCode, vatNr, vatStatus); + } completeReservation(event, reservationId, email, customerName, userLanguage, billingAddress, specialPriceSessionId, paymentProxy, customerReference, tcAccepted, privacyPolicyAccepted); return paymentResult; } catch(Exception ex) { @@ -440,6 +431,24 @@ public PaymentResult confirm(String gatewayToken, String payerId, Event event, S } + private void generateInvoiceNumber(Event event, String reservationId, String email, CustomerName customerName, Locale userLanguage, String billingAddress, String customerReference, TotalPrice reservationCost, boolean invoiceRequested, String vatCountryCode, String vatNr, PriceContainer.VatStatus vatStatus) { + + if(!invoiceRequested || !configurationManager.hasAllConfigurationsForInvoice(event)) { + return; + } + + String invoiceNumber = extensionManager.handleInvoiceGeneration(event, reservationId, email, customerName, userLanguage, billingAddress, customerReference, reservationCost, true, vatCountryCode, vatNr, vatStatus) + .flatMap(invoiceGeneration -> Optional.ofNullable(StringUtils.trimToNull(invoiceGeneration.getInvoiceNumber()))) + .orElseGet(() -> { + int invoiceSequence = invoiceSequencesRepository.lockReservationForUpdate(event.getOrganizationId()); + invoiceSequencesRepository.incrementSequenceFor(event.getOrganizationId()); + String pattern = configurationManager.getStringConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ConfigurationKeys.INVOICE_NUMBER_PATTERN), "%d"); + return String.format(pattern, invoiceSequence); + }); + + ticketReservationRepository.setInvoiceNumber(reservationId, invoiceNumber); + } + private boolean isDiscountCodeUsageExceeded(String reservationId) { TicketReservation reservation = ticketReservationRepository.findReservationById(reservationId); if(reservation.getPromoCodeDiscountId() != null) { @@ -872,9 +881,9 @@ private static TotalPrice totalReservationCostWithVAT(PromoCodeDiscount promoCod Stream>> additionalServiceItems) { List ticketPrices = tickets.stream().map(t -> TicketPriceContainer.from(t, reservationVatStatus, event, promoCodeDiscount)).collect(toList()); - BigDecimal totalVAT = ticketPrices.stream().map(TicketPriceContainer::getVAT).reduce(BigDecimal.ZERO, BigDecimal::add); - BigDecimal totalDiscount = ticketPrices.stream().map(TicketPriceContainer::getAppliedDiscount).reduce(BigDecimal.ZERO, BigDecimal::add); - BigDecimal totalNET = ticketPrices.stream().map(TicketPriceContainer::getFinalPrice).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal totalVAT = calcTotal(ticketPrices, PriceContainer::getRawVAT); + BigDecimal totalDiscount = calcTotal(ticketPrices, PriceContainer::getAppliedDiscount); + BigDecimal totalNET = calcTotal(ticketPrices, PriceContainer::getFinalPrice); int discountedTickets = (int) ticketPrices.stream().filter(t -> t.getAppliedDiscount().compareTo(BigDecimal.ZERO) > 0).count(); int discountAppliedCount = discountedTickets <= 1 || promoCodeDiscount.getDiscountType() == DiscountType.FIXED_AMOUNT ? discountedTickets : 1; @@ -882,12 +891,16 @@ private static TotalPrice totalReservationCostWithVAT(PromoCodeDiscount promoCod .flatMap(generateASIPriceContainers(event, null)) .collect(toList()); - BigDecimal asTotalVAT = asPrices.stream().map(AdditionalServiceItemPriceContainer::getVAT).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal asTotalVAT = calcTotal(asPrices, PriceContainer::getRawVAT); //FIXME discount is not applied to donations, as it wouldn't make sense. Must be implemented for #111 - BigDecimal asTotalNET = asPrices.stream().map(AdditionalServiceItemPriceContainer::getFinalPrice).reduce(BigDecimal.ZERO, BigDecimal::add); + BigDecimal asTotalNET = calcTotal(asPrices, PriceContainer::getFinalPrice); return new TotalPrice(unitToCents(totalNET.add(asTotalNET)), unitToCents(totalVAT.add(asTotalVAT)), -(MonetaryUtil.unitToCents(totalDiscount)), discountAppliedCount); } + private static BigDecimal calcTotal(List elements, Function operator) { + return elements.stream().map(operator).reduce(BigDecimal.ZERO, BigDecimal::add); + } + private static Function>, Stream> generateASIPriceContainers(Event event, PromoCodeDiscount discount) { return p -> p.getValue().stream().map(asi -> AdditionalServiceItemPriceContainer.from(asi, p.getKey(), event, discount)); } @@ -959,10 +972,10 @@ List extractSummary(String reservationId, PriceContainer.VatStatus r .collect(Collectors.groupingBy(TicketPriceContainer::getCategoryId)) .forEach((categoryId, ticketsByCategory) -> { final int subTotal = ticketsByCategory.stream().mapToInt(TicketPriceContainer::getSummarySrcPriceCts).sum(); - final int subTotalBeforeVat = ticketsByCategory.stream().mapToInt(TicketPriceContainer::getSummaryPriceBeforeVatCts).sum(); + final int subTotalBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(ticketsByCategory); TicketPriceContainer firstTicket = ticketsByCategory.get(0); final int ticketPriceCts = firstTicket.getSummarySrcPriceCts(); - final int priceBeforeVat = firstTicket.getSummaryPriceBeforeVatCts(); + final int priceBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(firstTicket)); String categoryName = ticketCategoryRepository.getByIdAndActive(categoryId, event.getId()).getName(); summary.add(new SummaryRow(categoryName, formatCents(ticketPriceCts), formatCents(priceBeforeVat), ticketsByCategory.size(), formatCents(subTotal), formatCents(subTotalBeforeVat), subTotal, SummaryRow.SummaryType.TICKET)); }); @@ -977,8 +990,8 @@ List extractSummary(String reservationId, PriceContainer.VatStatus r List prices = generateASIPriceContainers(event, null).apply(entry).collect(toList()); AdditionalServiceItemPriceContainer first = prices.get(0); final int subtotal = prices.stream().mapToInt(AdditionalServiceItemPriceContainer::getSrcPriceCts).sum(); - final int subtotalBeforeVat = prices.stream().mapToInt(AdditionalServiceItemPriceContainer::getSummaryPriceBeforeVatCts).sum(); - return new SummaryRow(title.getValue(), formatCents(first.getSrcPriceCts()), formatCents(first.getSummaryPriceBeforeVatCts()), prices.size(), formatCents(subtotal), formatCents(subtotalBeforeVat), subtotal, SummaryRow.SummaryType.ADDITIONAL_SERVICE); + final int subtotalBeforeVat = SummaryPriceContainer.getSummaryPriceBeforeVatCts(prices); + return new SummaryRow(title.getValue(), formatCents(first.getSrcPriceCts()), formatCents(SummaryPriceContainer.getSummaryPriceBeforeVatCts(singletonList(first))), prices.size(), formatCents(subtotal), formatCents(subtotalBeforeVat), subtotal, SummaryRow.SummaryType.ADDITIONAL_SERVICE); }).collect(Collectors.toList())); Optional.ofNullable(promoCodeDiscount).ifPresent(promo -> { @@ -1053,7 +1066,9 @@ private void cancelReservation(String reservationId, boolean expired) { ticketFieldRepository.deleteAllValuesForReservations(reservationIdsToRemove); Event event = eventRepository.findByReservationId(reservationId); int updatedAS = additionalServiceItemRepository.updateItemsStatusWithReservationUUID(reservationId, expired ? AdditionalServiceItemStatus.EXPIRED : AdditionalServiceItemStatus.CANCELLED); - int updatedTickets = ticketRepository.findTicketsInReservation(reservationId).stream().mapToInt(t -> ticketRepository.releaseExpiredTicket(reservationId, event.getId(), t.getId())).sum(); + int updatedTickets = ticketRepository.findTicketIdsInReservation(reservationId).stream().mapToInt( + tickedId -> ticketRepository.releaseExpiredTicket(reservationId, event.getId(), tickedId, UUID.randomUUID().toString()) + ).sum(); Validate.isTrue(updatedTickets + updatedAS > 0, "no items have been updated"); waitingQueueManager.fireReservationExpired(reservationId); groupManager.deleteWhitelistedTicketsForReservation(reservationId); diff --git a/src/main/java/alfio/manager/WaitingQueueManager.java b/src/main/java/alfio/manager/WaitingQueueManager.java index be9475f91f..076411653c 100644 --- a/src/main/java/alfio/manager/WaitingQueueManager.java +++ b/src/main/java/alfio/manager/WaitingQueueManager.java @@ -112,10 +112,10 @@ private void notifySubscription(Event event, CustomerName name, String email, Lo private WaitingQueueSubscription.Type getSubscriptionType(Event event) { ZonedDateTime now = ZonedDateTime.now(event.getZoneId()); return ticketCategoryRepository.findByEventId(event.getId()).stream() + .filter(tc -> now.isAfter(tc.getInception(event.getZoneId()))) .findFirst() - .filter(tc -> now.isBefore(tc.getInception(event.getZoneId()))) - .map(tc -> WaitingQueueSubscription.Type.PRE_SALES) - .orElse(WaitingQueueSubscription.Type.SOLD_OUT); + .map(tc -> WaitingQueueSubscription.Type.SOLD_OUT) + .orElse(WaitingQueueSubscription.Type.PRE_SALES); } private void validateSubscriptionType(Event event, WaitingQueueSubscription.Type type) { diff --git a/src/main/java/alfio/model/PriceContainer.java b/src/main/java/alfio/model/PriceContainer.java index 0b4e71a6b6..73bfe1f1e6 100644 --- a/src/main/java/alfio/model/PriceContainer.java +++ b/src/main/java/alfio/model/PriceContainer.java @@ -31,8 +31,8 @@ public interface PriceContainer { - BiFunction includedVatExtractor = (price, vatPercentage) -> MonetaryUtil.extractVAT(price, vatPercentage).setScale(2, RoundingMode.HALF_UP); - BiFunction notIncludedVatCalculator = (price, vatPercentage) -> MonetaryUtil.calcVat(price, vatPercentage).setScale(2, RoundingMode.HALF_UP); + BiFunction includedVatExtractor = MonetaryUtil::extractVAT; + BiFunction notIncludedVatCalculator = MonetaryUtil::calcVat; enum VatStatus { NONE((price, vatPercentage) -> BigDecimal.ZERO, UnaryOperator.identity()), @@ -51,6 +51,10 @@ enum VatStatus { } public BigDecimal extractVat(BigDecimal price, BigDecimal vatPercentage) { + return this.extractRawVAT(price, vatPercentage).setScale(2, RoundingMode.HALF_UP); + } + + public BigDecimal extractRawVAT(BigDecimal price, BigDecimal vatPercentage) { return this.extractor.andThen(transformer).apply(price, vatPercentage); } @@ -123,6 +127,18 @@ default BigDecimal getVAT() { return getVAT(price.subtract(getAppliedDiscount()), getVatStatus(), getVatPercentageOrZero()); } + + /** + * Returns the VAT, with a reasonable, less error-prone, rounding + * @return vat + * @see MonetaryUtil#ROUNDING_SCALE + */ + default BigDecimal getRawVAT() { + final BigDecimal price = MonetaryUtil.centsToUnit(getSrcPriceCts()); + return getVatStatus().extractRawVAT(price.subtract(getAppliedDiscount()), getVatPercentageOrZero()); + } + + /** * @return the discount applied, if any */ diff --git a/src/main/java/alfio/model/SummaryPriceContainer.java b/src/main/java/alfio/model/SummaryPriceContainer.java index cce546a9b3..9113501d42 100644 --- a/src/main/java/alfio/model/SummaryPriceContainer.java +++ b/src/main/java/alfio/model/SummaryPriceContainer.java @@ -16,20 +16,26 @@ */ package alfio.model; +import alfio.util.MonetaryUtil; + +import java.math.BigDecimal; +import java.util.List; + import static alfio.util.MonetaryUtil.centsToUnit; -import static alfio.util.MonetaryUtil.unitToCents; public interface SummaryPriceContainer extends PriceContainer { - Integer getVatCts(); + Integer getFinalPriceCts(); - default int getSummaryPriceBeforeVatCts() { - PriceContainer.VatStatus vatStatus = getVatStatus(); - if(vatStatus == PriceContainer.VatStatus.NOT_INCLUDED_EXEMPT) { - return getSrcPriceCts(); - } else if(vatStatus == PriceContainer.VatStatus.INCLUDED_EXEMPT) { - return getSrcPriceCts() + unitToCents(vatStatus.extractVat(centsToUnit(getSrcPriceCts()), getVatPercentageOrZero())); - } - return getFinalPriceCts() - getVatCts(); + static int getSummaryPriceBeforeVatCts(List elements) { + return elements.stream().map(item -> { + PriceContainer.VatStatus vatStatus = item.getVatStatus(); + if(vatStatus == PriceContainer.VatStatus.NOT_INCLUDED_EXEMPT) { + return MonetaryUtil.centsToUnit(item.getSrcPriceCts()); + } else if(vatStatus == PriceContainer.VatStatus.INCLUDED_EXEMPT) { + return MonetaryUtil.centsToUnit(item.getSrcPriceCts()).add(vatStatus.extractRawVAT(centsToUnit(item.getSrcPriceCts()), item.getVatPercentageOrZero())); + } + return MonetaryUtil.centsToUnit(item.getFinalPriceCts()).subtract(item.getRawVAT()); + }).reduce(BigDecimal::add).map(MonetaryUtil::unitToCents).orElse(0); } } diff --git a/src/main/java/alfio/model/decorator/TicketPriceContainer.java b/src/main/java/alfio/model/decorator/TicketPriceContainer.java index a7187b7071..a213551903 100644 --- a/src/main/java/alfio/model/decorator/TicketPriceContainer.java +++ b/src/main/java/alfio/model/decorator/TicketPriceContainer.java @@ -72,11 +72,6 @@ public static TicketPriceContainer from(Ticket t, VatStatus reservationVatStatus return new TicketPriceContainer(t, discount, e.getCurrency(), e.getVat(), vatStatus); } - @Override - public Integer getVatCts() { - return ticket.getVatCts(); - } - @Override public Integer getFinalPriceCts() { return ticket.getFinalPriceCts(); diff --git a/src/main/java/alfio/repository/TicketRepository.java b/src/main/java/alfio/repository/TicketRepository.java index 6a6cdfcd67..37948605e4 100644 --- a/src/main/java/alfio/repository/TicketRepository.java +++ b/src/main/java/alfio/repository/TicketRepository.java @@ -21,12 +21,11 @@ import alfio.model.TicketInfo; import alfio.model.TicketWithReservationAndTransaction; import ch.digitalfondue.npjt.*; +import org.springframework.jdbc.core.namedparam.MapSqlParameterSource; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; import java.time.ZonedDateTime; -import java.util.Date; -import java.util.List; -import java.util.Optional; -import java.util.Set; +import java.util.*; @QueryRepository public interface TicketRepository { @@ -124,6 +123,9 @@ public interface TicketRepository { @Query("select * from ticket where tickets_reservation_id = :reservationId order by category_id asc, uuid asc") List findTicketsInReservation(@Bind("reservationId") String reservationId); + @Query("select id from ticket where tickets_reservation_id = :reservationId order by category_id asc, uuid asc") + List findTicketIdsInReservation(@Bind("reservationId") String reservationId); + @Query("select * from ticket where tickets_reservation_id = :reservationId order by category_id asc, uuid asc LIMIT 1 OFFSET 0") Optional findFirstTicketInReservation(@Bind("reservationId") String reservationId); @@ -238,11 +240,15 @@ public interface TicketRepository { @Query(value = RELEASE_TICKET_QUERY, type = QueryType.TEMPLATE) String batchReleaseTickets(); - @Query("update ticket set status = 'RELEASED', " + RESET_TICKET + " where id = :ticketId and status = 'PENDING' and tickets_reservation_id = :reservationId and event_id = :eventId") - int releaseExpiredTicket(@Bind("reservationId") String reservationId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId); + @Query("update ticket set status = 'RELEASED', uuid = :newUuid, " + RESET_TICKET + " where id = :ticketId and status = 'PENDING' and tickets_reservation_id = :reservationId and event_id = :eventId") + int releaseExpiredTicket(@Bind("reservationId") String reservationId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId, @Bind("newUuid") String newUuid); + + NamedParameterJdbcTemplate getNamedParameterJdbcTemplate(); - @Query("update ticket set status = 'RELEASED', " + RESET_TICKET + " where id in (:ticketIds)") - int resetTickets(@Bind("ticketIds") List ticketIds); + default void resetTickets(List ticketIds) { + MapSqlParameterSource[] params = ticketIds.stream().map(ticketId -> new MapSqlParameterSource("ticketId", ticketId).addValue("newUuid", UUID.randomUUID().toString())).toArray(MapSqlParameterSource[]::new); + getNamedParameterJdbcTemplate().batchUpdate("update ticket set status = 'RELEASED', uuid = :newUuid, " + RESET_TICKET + " where id = :ticketId", params); + } @Query("select count(*) from ticket where status = 'RELEASED' and event_id = :eventId") Integer countWaiting(@Bind("eventId") int eventId); diff --git a/src/main/java/alfio/util/MonetaryUtil.java b/src/main/java/alfio/util/MonetaryUtil.java index 34ddd2c42a..c4f792dd14 100644 --- a/src/main/java/alfio/util/MonetaryUtil.java +++ b/src/main/java/alfio/util/MonetaryUtil.java @@ -24,6 +24,7 @@ public final class MonetaryUtil { public static final BigDecimal HUNDRED = new BigDecimal("100.00"); + public static final int ROUNDING_SCALE = 10; private MonetaryUtil() { } @@ -33,11 +34,11 @@ public static int addVAT(int priceInCents, BigDecimal vat) { } public static BigDecimal addVAT(BigDecimal price, BigDecimal vat) { - return price.add(price.multiply(vat.divide(HUNDRED, 5, UP))).setScale(0, HALF_UP); + return price.add(price.multiply(vat.divide(HUNDRED, ROUNDING_SCALE, UP))).setScale(0, HALF_UP); } public static BigDecimal extractVAT(BigDecimal price, BigDecimal vat) { - return price.subtract(price.divide(BigDecimal.ONE.add(vat.divide(HUNDRED, 5, UP)), 5, HALF_DOWN)); + return price.subtract(price.divide(BigDecimal.ONE.add(vat.divide(HUNDRED, ROUNDING_SCALE, UP)), ROUNDING_SCALE, HALF_DOWN)); } public static int calcPercentage(int priceInCents, BigDecimal vat) { @@ -45,13 +46,13 @@ public static int calcPercentage(int priceInCents, BigDecimal vat) { } public static T calcPercentage(long priceInCents, BigDecimal vat, Function converter) { - BigDecimal result = new BigDecimal(priceInCents).multiply(vat.divide(HUNDRED, 5, UP)) + BigDecimal result = new BigDecimal(priceInCents).multiply(vat.divide(HUNDRED, ROUNDING_SCALE, UP)) .setScale(0, HALF_UP); return converter.apply(result); } public static BigDecimal calcVat(BigDecimal price, BigDecimal percentage) { - return price.multiply(percentage.divide(HUNDRED, 5, HALF_UP)); + return price.multiply(percentage.divide(HUNDRED, ROUNDING_SCALE, HALF_UP)); } public static BigDecimal centsToUnit(int cents) { diff --git a/src/main/webapp/resources/css/admin.css b/src/main/webapp/resources/css/admin.css index 4e48daec01..025327e623 100644 --- a/src/main/webapp/resources/css/admin.css +++ b/src/main/webapp/resources/css/admin.css @@ -225,11 +225,7 @@ td.cell-wrap { @media screen and (min-width: 991px) { .setting input[type="text"], .setting input:not([type]), .setting textarea, .setting select { - padding-left: 85px; - } - - .setting select { /* Enable Padding on Select on OSX */ - -webkit-appearance: none; + text-indent:85px; } .settings-label { diff --git a/src/test/java/alfio/manager/TicketReservationManagerTest.java b/src/test/java/alfio/manager/TicketReservationManagerTest.java index a5c30e91a8..4c9cafda5e 100644 --- a/src/test/java/alfio/manager/TicketReservationManagerTest.java +++ b/src/test/java/alfio/manager/TicketReservationManagerTest.java @@ -494,9 +494,10 @@ public void renewSpecialPrice() { @Test public void cancelPendingReservationAndRenewCode() { String RESERVATION_ID = "rid"; - when(ticketRepository.releaseExpiredTicket(eq(RESERVATION_ID), anyInt(), anyInt())).thenReturn(1); + when(ticketRepository.releaseExpiredTicket(eq(RESERVATION_ID), anyInt(), anyInt(), anyString())).thenReturn(1); when(eventRepository.findByReservationId(eq(RESERVATION_ID))).thenReturn(event); when(ticketRepository.findTicketsInReservation(eq(RESERVATION_ID))).thenReturn(Collections.singletonList(ticket)); + when(ticketRepository.findTicketIdsInReservation(eq(RESERVATION_ID))).thenReturn(Collections.singletonList(TICKET_ID)); when(ticket.getTicketsReservationId()).thenReturn(RESERVATION_ID); when(ticketRepository.findBySpecialPriceId(eq(SPECIAL_PRICE_ID))).thenReturn(Optional.of(ticket)); TicketReservation reservation = mock(TicketReservation.class); @@ -511,7 +512,7 @@ public void cancelPendingReservationAndRenewCode() { Optional renewed = trm.renewSpecialPrice(Optional.of(specialPrice), Optional.of(SPECIAL_PRICE_SESSION_ID)); verify(specialPriceRepository).resetToFreeAndCleanupForReservation(eq(singletonList(RESERVATION_ID))); verify(ticketRepository).resetCategoryIdForUnboundedCategories(eq(singletonList(RESERVATION_ID))); - verify(ticketRepository).releaseExpiredTicket(RESERVATION_ID, EVENT_ID, TICKET_ID); + verify(ticketRepository).releaseExpiredTicket(eq(RESERVATION_ID), eq(EVENT_ID), eq(TICKET_ID), anyString()); verify(ticketReservationRepository).remove(eq(singletonList(RESERVATION_ID))); verify(waitingQueueManager).fireReservationExpired(eq(RESERVATION_ID)); assertTrue(renewed.isPresent()); @@ -717,7 +718,7 @@ public void confirmPaidReservation() { } @Test - public void returnFailureCodeIfPaymentNotSuccesful() { + public void returnFailureCodeIfPaymentNotSuccessful() { initConfirmReservation(); when(ticketReservationRepository.updateTicketReservation(eq(RESERVATION_ID), eq(IN_PAYMENT.toString()), anyString(), anyString(), anyString(), anyString(), anyString(), anyString(), isNull(ZonedDateTime.class), eq(PaymentProxy.STRIPE.toString()), anyString())).thenReturn(1); when(ticketReservationRepository.updateReservationStatus(eq(RESERVATION_ID), eq(TicketReservationStatus.PENDING.toString()))).thenReturn(1); @@ -731,7 +732,7 @@ public void returnFailureCodeIfPaymentNotSuccesful() { verify(ticketReservationRepository).lockReservationForUpdate(eq(RESERVATION_ID)); verify(paymentManager).processStripePayment(eq(RESERVATION_ID), eq(GATEWAY_TOKEN), anyInt(), eq(event), anyString(), any(CustomerName.class), anyString()); verify(ticketReservationRepository).updateReservationStatus(eq(RESERVATION_ID), eq(TicketReservationStatus.PENDING.toString())); - verify(configurationManager).hasAllConfigurationsForInvoice(eq(event)); + verify(configurationManager, never()).hasAllConfigurationsForInvoice(eq(event)); verify(ticketReservationRepository).updateBillingData(any(), anyString(), anyString(), anyBoolean(), anyString()); }