From 031b7ec322b734717011bf03e6fec2c25d6acf10 Mon Sep 17 00:00:00 2001 From: Celestino Bellone <3385346+cbellone@users.noreply.github.com> Date: Wed, 8 Jan 2020 17:27:36 +0100 Subject: [PATCH] Offline external payment (#854) * initial implementation of DeferredBankTransferManager * update public frontend and admin * update italian translation --- gradle.properties | 2 +- .../alfio/controller/IndexController.java | 9 +- .../manager/TicketReservationManager.java | 5 +- .../manager/payment/BankTransferManager.java | 24 +++- .../payment/DeferredBankTransferManager.java | 80 +++++++++++++ .../payment/RevolutBankTransferManager.java | 2 + src/main/java/alfio/model/OrderSummary.java | 3 +- .../java/alfio/model/TicketReservation.java | 16 ++- .../alfio/model/system/ConfigurationKeys.java | 1 + .../TicketReservationRepository.java | 8 +- .../repository/TicketSearchRepository.java | 2 +- .../java/alfio/util/TemplateResource.java | 2 +- .../resources/alfio/i18n/public.properties | 3 + .../resources/alfio/i18n/public_it.properties | 5 +- .../admin/partials/configuration/event.html | 27 +++-- .../partials/configuration/organization.html | 22 ++-- .../admin/partials/configuration/system.html | 26 ++-- .../feature/configuration/configuration.js | 42 ++++++- .../manager/TicketReservationManagerTest.java | 2 +- .../DeferredBankTransferManagerTest.java | 111 ++++++++++++++++++ 20 files changed, 333 insertions(+), 59 deletions(-) create mode 100644 src/main/java/alfio/manager/payment/DeferredBankTransferManager.java create mode 100644 src/test/java/alfio/manager/payment/DeferredBankTransferManagerTest.java diff --git a/gradle.properties b/gradle.properties index 0139a2809a..faaae4ac9d 100644 --- a/gradle.properties +++ b/gradle.properties @@ -14,4 +14,4 @@ junitVersion=5.1.0 systemProp.jdk.tls.client.protocols="TLSv1,TLSv1.1,TLSv1.2" # https://jitpack.io/#alfio-event/alf.io-public-frontend -> go to commit tab, set the version -alfioPublicFrontendVersion=78a49b22b3 \ No newline at end of file +alfioPublicFrontendVersion=9cfee80051 \ No newline at end of file diff --git a/src/main/java/alfio/controller/IndexController.java b/src/main/java/alfio/controller/IndexController.java index 4d90e3556d..5d1783345a 100644 --- a/src/main/java/alfio/controller/IndexController.java +++ b/src/main/java/alfio/controller/IndexController.java @@ -137,6 +137,7 @@ public ResponseEntity replyToK8s() { "/event/{eventShortName}/reservation/{reservationId}/overview", "/event/{eventShortName}/reservation/{reservationId}/waitingPayment", "/event/{eventShortName}/reservation/{reservationId}/waiting-payment", + "/event/{eventShortName}/reservation/{reservationId}/deferred-payment", "/event/{eventShortName}/reservation/{reservationId}/processing-payment", "/event/{eventShortName}/reservation/{reservationId}/success", "/event/{eventShortName}/reservation/{reservationId}/not-found", @@ -171,24 +172,22 @@ public void replyToIndex(@PathVariable(value = "eventShortName", required = fals public String redirectToReservation(@PathVariable(value = "eventShortName") String eventShortName, @PathVariable(value = "reservationId") String reservationId) { if (eventRepository.existsByShortName(eventShortName)) { var reservationStatusUrlSegment = ticketReservationRepository.findOptionalStatusAndValidationById(reservationId) - .map(status -> reservationStatusToUrlMapping(status)).orElse("not-found"); + .map(IndexController::reservationStatusToUrlMapping).orElse("not-found"); - var redirectUrl = "redirect:" + UriComponentsBuilder.fromPath("/event/{eventShortName}/reservation/{reservationId}/{status}") + return "redirect:" + UriComponentsBuilder.fromPath("/event/{eventShortName}/reservation/{reservationId}/{status}") .buildAndExpand(Map.of("eventShortName", eventShortName, "reservationId", reservationId, "status",reservationStatusUrlSegment)) .toUriString(); - - return redirectUrl; } else { return "redirect:/"; } } private static String reservationStatusToUrlMapping(TicketReservationStatusAndValidation status) { - // PENDING, IN_PAYMENT, EXTERNAL_PROCESSING_PAYMENT, WAITING_EXTERNAL_CONFIRMATION, OFFLINE_PAYMENT, COMPLETE, STUCK, CANCELLED, CREDIT_NOTE_ISSUED switch (status.getStatus()) { case PENDING: return Boolean.TRUE.equals(status.getValidated()) ? "overview" : "book"; case COMPLETE: return "success"; case OFFLINE_PAYMENT: return "waiting-payment"; + case DEFERRED_OFFLINE_PAYMENT: return "deferred-payment"; case EXTERNAL_PROCESSING_PAYMENT: case WAITING_EXTERNAL_CONFIRMATION: return "processing-payment"; case IN_PAYMENT: diff --git a/src/main/java/alfio/manager/TicketReservationManager.java b/src/main/java/alfio/manager/TicketReservationManager.java index 4bf80f368a..86f0393415 100644 --- a/src/main/java/alfio/manager/TicketReservationManager.java +++ b/src/main/java/alfio/manager/TicketReservationManager.java @@ -649,7 +649,7 @@ public void confirmOfflinePayment(Event event, String reservationId, String user TicketReservation ticketReservation = findById(reservationId).orElseThrow(IllegalArgumentException::new); ticketReservationRepository.lockReservationForUpdate(reservationId); Validate.isTrue(ticketReservation.getPaymentMethod() == PaymentProxy.OFFLINE, "invalid payment method"); - Validate.isTrue(ticketReservation.getStatus() == TicketReservationStatus.OFFLINE_PAYMENT, "invalid status"); + Validate.isTrue(ticketReservation.isPendingOfflinePayment(), "invalid status"); ticketReservationRepository.confirmOfflinePayment(reservationId, TicketReservationStatus.COMPLETE.name(), ZonedDateTime.now(event.getZoneId())); @@ -675,7 +675,7 @@ public void confirmOfflinePayment(Event event, String reservationId, String user void registerAlfioTransaction(Event event, String reservationId, PaymentProxy paymentProxy) { var totalPrice = totalReservationCostWithVAT(reservationId); int priceWithVAT = totalPrice.getPriceWithVAT(); - Long platformFee = FeeCalculator.getCalculator(event, configurationManager, Objects.requireNonNullElse(totalPrice.getCurrencyCode(), event.getCurrency())) + long platformFee = FeeCalculator.getCalculator(event, configurationManager, Objects.requireNonNullElse(totalPrice.getCurrencyCode(), event.getCurrency())) .apply(ticketRepository.countTicketsInReservation(reservationId), (long) priceWithVAT) .orElse(0L); @@ -1231,6 +1231,7 @@ public OrderSummary orderSummaryForReservation(TicketReservation reservation, Ev formatCents(reservationCost.getPriceWithVAT(), currencyCode), formatCents(reservationCost.getVAT(), currencyCode), reservation.getStatus() == TicketReservationStatus.OFFLINE_PAYMENT, + reservation.getStatus() == DEFERRED_OFFLINE_PAYMENT, reservation.getPaymentMethod() == PaymentProxy.ON_SITE, Optional.ofNullable(event.getVat()).map(p -> MonetaryUtil.formatCents(MonetaryUtil.unitToCents(p, currencyCode), currencyCode)).orElse(null), reservation.getVatStatus(), diff --git a/src/main/java/alfio/manager/payment/BankTransferManager.java b/src/main/java/alfio/manager/payment/BankTransferManager.java index 82780a3dce..d4986c9c97 100644 --- a/src/main/java/alfio/manager/payment/BankTransferManager.java +++ b/src/main/java/alfio/manager/payment/BankTransferManager.java @@ -20,6 +20,7 @@ import alfio.manager.system.ConfigurationLevel; import alfio.manager.system.ConfigurationManager; import alfio.model.Event; +import alfio.model.TicketReservation; import alfio.model.system.ConfigurationKeys; import alfio.model.transaction.*; import alfio.repository.TicketReservationRepository; @@ -35,7 +36,9 @@ import java.util.*; import static alfio.manager.TicketReservationManager.NOT_YET_PAID_TRANSACTION_ID; +import static alfio.model.TicketReservation.TicketReservationStatus.OFFLINE_PAYMENT; import static alfio.model.system.ConfigurationKeys.*; +import static alfio.model.system.ConfigurationKeys.BANK_TRANSFER_ENABLED; import static java.time.ZoneOffset.UTC; @Component @@ -43,6 +46,9 @@ @AllArgsConstructor public class BankTransferManager implements PaymentProvider { + private static final EnumSet OPTIONS_TO_LOAD = EnumSet.of(BANK_TRANSFER_ENABLED, + DEFERRED_BANK_TRANSFER_ENABLED, OFFLINE_PAYMENT_DAYS, REVOLUT_ENABLED, REVOLUT_API_KEY, + REVOLUT_LIVE_MODE, REVOLUT_MANUAL_REVIEW); private final ConfigurationManager configurationManager; private final TicketReservationRepository ticketReservationRepository; private final TransactionRepository transactionRepository; @@ -63,17 +69,25 @@ boolean bankTransferEnabled(PaymentMethod paymentMethod, PaymentContext paymentC } Map options(PaymentContext paymentContext) { - return configurationManager.getFor(EnumSet.of(BANK_TRANSFER_ENABLED, OFFLINE_PAYMENT_DAYS, REVOLUT_ENABLED, REVOLUT_API_KEY, REVOLUT_LIVE_MODE, REVOLUT_MANUAL_REVIEW), paymentContext.getConfigurationLevel()); + return configurationManager.getFor(OPTIONS_TO_LOAD, paymentContext.getConfigurationLevel()); + } + + boolean isPaymentDeferredEnabled(Map options) { + return options.get(DEFERRED_BANK_TRANSFER_ENABLED).getValueAsBooleanOrDefault(false); } @Override public PaymentResult doPayment(PaymentSpecification spec) { transitionToOfflinePayment(spec); + overrideExistingTransactions(spec); + return PaymentResult.successful(NOT_YET_PAID_TRANSACTION_ID); + } + + void overrideExistingTransactions(PaymentSpecification spec) { PaymentManagerUtils.invalidateExistingTransactions(spec.getReservationId(), transactionRepository); transactionRepository.insert(UUID.randomUUID().toString(), null, spec.getReservationId(), ZonedDateTime.now(UTC), spec.getPriceWithVAT(), spec.getCurrencyCode(), "", PaymentProxy.OFFLINE.name(), 0L, 0L, Transaction.Status.PENDING, Map.of()); - return PaymentResult.successful(NOT_YET_PAID_TRANSACTION_ID); } @Override @@ -95,7 +109,11 @@ public PaymentResult doPayment(PaymentSpecification spec) { private void transitionToOfflinePayment(PaymentSpecification spec) { ZonedDateTime deadline = getOfflinePaymentDeadline(spec.getPaymentContext(), configurationManager); - int updatedReservation = ticketReservationRepository.postponePayment(spec.getReservationId(), Date.from(deadline.toInstant()), spec.getEmail(), + postponePayment(spec, OFFLINE_PAYMENT, deadline); + } + + void postponePayment(PaymentSpecification spec, TicketReservation.TicketReservationStatus status, ZonedDateTime deadline) { + int updatedReservation = ticketReservationRepository.postponePayment(spec.getReservationId(), status, Date.from(deadline.toInstant()), spec.getEmail(), spec.getCustomerName().getFullName(), spec.getCustomerName().getFirstName(), spec.getCustomerName().getLastName(), spec.getBillingAddress(), spec.getCustomerReference()); Validate.isTrue(updatedReservation == 1, "expected exactly one updated reservation, got " + updatedReservation); } diff --git a/src/main/java/alfio/manager/payment/DeferredBankTransferManager.java b/src/main/java/alfio/manager/payment/DeferredBankTransferManager.java new file mode 100644 index 0000000000..b83ea618ee --- /dev/null +++ b/src/main/java/alfio/manager/payment/DeferredBankTransferManager.java @@ -0,0 +1,80 @@ +/** + * This file is part of alf.io. + * + * alf.io is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * alf.io is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with alf.io. If not, see . + */ +package alfio.manager.payment; + +import alfio.manager.support.PaymentResult; +import alfio.manager.system.ConfigurationManager; +import alfio.model.TicketReservation; +import alfio.model.transaction.*; +import alfio.repository.TicketReservationRepository; +import alfio.repository.TransactionRepository; +import lombok.extern.log4j.Log4j2; +import org.springframework.core.annotation.Order; +import org.springframework.stereotype.Component; + +import java.time.ZonedDateTime; +import java.util.*; + +import static alfio.manager.TicketReservationManager.NOT_YET_PAID_TRANSACTION_ID; +import static alfio.model.TicketReservation.TicketReservationStatus.DEFERRED_OFFLINE_PAYMENT; +import static java.time.ZoneOffset.UTC; + +@Component +@Order(0) +@Log4j2 +public class DeferredBankTransferManager implements PaymentProvider { + + private final TicketReservationRepository ticketReservationRepository; + private final BankTransferManager bankTransferManager; + + public DeferredBankTransferManager(TicketReservationRepository ticketReservationRepository, + BankTransferManager bankTransferManager) { + this.ticketReservationRepository = ticketReservationRepository; + this.bankTransferManager = bankTransferManager; + } + + @Override + public boolean accept(PaymentMethod paymentMethod, PaymentContext paymentContext) { + var options = bankTransferManager.options(paymentContext); + return paymentContext.getEvent() != null + && bankTransferManager.bankTransferEnabled(paymentMethod, paymentContext, options) + && bankTransferManager.isPaymentDeferredEnabled(options); + } + + @Override + public PaymentResult doPayment(PaymentSpecification spec) { + bankTransferManager.postponePayment(spec, DEFERRED_OFFLINE_PAYMENT, Objects.requireNonNull(spec.getEvent()).getBegin()); + bankTransferManager.overrideExistingTransactions(spec); + return PaymentResult.successful(NOT_YET_PAID_TRANSACTION_ID); + } + + @Override + public Map getModelOptions(PaymentContext context) { + return Map.of("deferred", true); + } + + @Override + public boolean accept(Transaction transaction) { + return PaymentProxy.OFFLINE == transaction.getPaymentProxy() && isReservationStatusCompatible(transaction); + } + + private Boolean isReservationStatusCompatible(Transaction transaction) { + return ticketReservationRepository.findOptionalStatusAndValidationById(transaction.getReservationId()) + .map(sv -> sv.getStatus() == DEFERRED_OFFLINE_PAYMENT) + .orElse(false); + } +} diff --git a/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java b/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java index 213d231251..8b41c13b0d 100644 --- a/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java +++ b/src/main/java/alfio/manager/payment/RevolutBankTransferManager.java @@ -39,6 +39,7 @@ import lombok.AllArgsConstructor; import lombok.extern.log4j.Log4j2; import org.apache.commons.lang3.tuple.Pair; +import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; @@ -59,6 +60,7 @@ import static alfio.util.EventUtil.JSON_DATETIME_FORMATTER; @Component +@Order(1) @Transactional @Log4j2 @AllArgsConstructor diff --git a/src/main/java/alfio/model/OrderSummary.java b/src/main/java/alfio/model/OrderSummary.java index b5a39aa0cc..04ea677379 100644 --- a/src/main/java/alfio/model/OrderSummary.java +++ b/src/main/java/alfio/model/OrderSummary.java @@ -30,6 +30,7 @@ public class OrderSummary { private final String totalPrice; private final String totalVAT; private final boolean waitingForPayment; + private final boolean deferredPayment; private final boolean cashPayment; private final String vatPercentage; private final PriceContainer.VatStatus vatStatus; @@ -49,7 +50,7 @@ public boolean getCashPayment() { } public boolean getNotYetPaid() { - return waitingForPayment || cashPayment; + return waitingForPayment || cashPayment || deferredPayment; } public int getTicketAmount() { diff --git a/src/main/java/alfio/model/TicketReservation.java b/src/main/java/alfio/model/TicketReservation.java index ddf3f450a6..eca49d3868 100644 --- a/src/main/java/alfio/model/TicketReservation.java +++ b/src/main/java/alfio/model/TicketReservation.java @@ -33,7 +33,16 @@ public class TicketReservation implements PriceContainer { public enum TicketReservationStatus { - PENDING, IN_PAYMENT, EXTERNAL_PROCESSING_PAYMENT, WAITING_EXTERNAL_CONFIRMATION, OFFLINE_PAYMENT, COMPLETE, STUCK, CANCELLED, CREDIT_NOTE_ISSUED + PENDING, + IN_PAYMENT, + EXTERNAL_PROCESSING_PAYMENT, + WAITING_EXTERNAL_CONFIRMATION, + OFFLINE_PAYMENT, + DEFERRED_OFFLINE_PAYMENT, + COMPLETE, + STUCK, + CANCELLED, + CREDIT_NOTE_ISSUED } private final String id; @@ -207,4 +216,9 @@ public String getPaidAmount() { public Optional getOptionalVatPercentage() { return Optional.ofNullable(usedVatPercent); } + + public boolean isPendingOfflinePayment() { + return status == TicketReservationStatus.OFFLINE_PAYMENT + || status == TicketReservationStatus.DEFERRED_OFFLINE_PAYMENT; + } } diff --git a/src/main/java/alfio/model/system/ConfigurationKeys.java b/src/main/java/alfio/model/system/ConfigurationKeys.java index 1566578b07..121dd7e31b 100644 --- a/src/main/java/alfio/model/system/ConfigurationKeys.java +++ b/src/main/java/alfio/model/system/ConfigurationKeys.java @@ -111,6 +111,7 @@ public enum ConfigurationKeys { SMTP_PROPERTIES("SMTP Properties", false, SettingCategory.MAIL, ComponentType.TEXTAREA, false, EnumSet.of(SYSTEM)), BANK_TRANSFER_ENABLED("Bank transfer enabled", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION)), + DEFERRED_BANK_TRANSFER_ENABLED("Handle Bank Transfer payment externally (default false)", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.BOOLEAN, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), OFFLINE_PAYMENT_DAYS("Maximum number of days allowed to pay an offline ticket", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.TEXT, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), OFFLINE_REMINDER_HOURS("How many hours before expiration should be sent a reminder e-mail for offline payments?", false, SettingCategory.PAYMENT_OFFLINE, ComponentType.TEXT, false, EnumSet.of(SYSTEM, ORGANIZATION, EVENT)), diff --git a/src/main/java/alfio/repository/TicketReservationRepository.java b/src/main/java/alfio/repository/TicketReservationRepository.java index 1a98ba2948..2f91507069 100644 --- a/src/main/java/alfio/repository/TicketReservationRepository.java +++ b/src/main/java/alfio/repository/TicketReservationRepository.java @@ -56,9 +56,9 @@ int updateTicketReservation(@Bind("reservationId") String reservationId, @Bind("paymentMethod") String paymentMethod, @Bind("customerReference") String customerReference); - @Query("update tickets_reservation set validity = :validity, status = 'OFFLINE_PAYMENT', payment_method = 'OFFLINE', full_name = :fullName, first_name = :firstName," + + @Query("update tickets_reservation set validity = :validity, status = :status, payment_method = 'OFFLINE', full_name = :fullName, first_name = :firstName," + " last_name = :lastName, email_address = :email, billing_address = :billingAddress, customer_reference = :customerReference where id = :reservationId") - int postponePayment(@Bind("reservationId") String reservationId, @Bind("validity") Date validity, @Bind("email") String email, + int postponePayment(@Bind("reservationId") String reservationId, @Bind("status") TicketReservation.TicketReservationStatus status, @Bind("validity") Date validity, @Bind("email") String email, @Bind("fullName") String fullName, @Bind("firstName") String firstName, @Bind("lastName") String lastName, @Bind("billingAddress") String billingAddress, @Bind("customerReference") String customerReference); @@ -69,7 +69,7 @@ int postponePayment(@Bind("reservationId") String reservationId, @Bind("validity @Query("update tickets_reservation set full_name = :fullName where id = :reservationId") int updateAssignee(@Bind("reservationId") String reservationId, @Bind("fullName") String fullName); - @Query("select count(id) from tickets_reservation where status = 'OFFLINE_PAYMENT' and event_id_fk = :eventId") + @Query("select count(id) from tickets_reservation where status in('OFFLINE_PAYMENT', 'DEFERRED_OFFLINE_PAYMENT') and event_id_fk = :eventId") Integer findAllReservationsWaitingForPaymentCountInEventId(@Bind("eventId") int eventId); @Query("select * from tickets_reservation where status = 'OFFLINE_PAYMENT' and date_trunc('day', validity) <= :expiration and offline_payment_reminder_sent = false for update skip locked") @@ -159,7 +159,7 @@ int updateBillingData(@Bind("vatStatus") PriceContainer.VatStatus vatStatus, @Query("select count(ticket.id) ticket_count, to_char(date_trunc('day', tickets_reservation.creation_ts), 'YYYY-MM-DD') as day from ticket " + "inner join tickets_reservation on tickets_reservation_id = tickets_reservation.id where " + "ticket.event_id = :eventId and " + - "tickets_reservation.status in ('IN_PAYMENT', 'EXTERNAL_PROCESSING_PAYMENT', 'OFFLINE_PAYMENT', 'COMPLETE', 'STUCK') and " + + "tickets_reservation.status in ('IN_PAYMENT', 'EXTERNAL_PROCESSING_PAYMENT', 'OFFLINE_PAYMENT', 'DEFERRED_OFFLINE_PAYMENT', 'COMPLETE', 'STUCK') and " + "tickets_reservation.creation_ts >= :from and " + "tickets_reservation.creation_ts <= :to " + "group by day order by day asc") diff --git a/src/main/java/alfio/repository/TicketSearchRepository.java b/src/main/java/alfio/repository/TicketSearchRepository.java index e31ed28e2f..fada1e7acb 100644 --- a/src/main/java/alfio/repository/TicketSearchRepository.java +++ b/src/main/java/alfio/repository/TicketSearchRepository.java @@ -78,7 +78,7 @@ List findReservationsForEvent(@Bind("eventId") int eventId, @Query("select distinct on(tr_id) "+RESERVATION_SEARCH_FIELD+", "+TRANSACTION_FIELDS+"," +PROMO_CODE_FIELDS+" from reservation_and_ticket_and_tx where tr_id in (:reservationIds) and tr_status = 'OFFLINE_PAYMENT' and bt_reservation_id is not null") List findOfflineReservationsWithTransaction(@Bind("reservationIds") List reservationIds); - @Query("select distinct on(tr_id) "+RESERVATION_SEARCH_FIELD+", "+TRANSACTION_FIELDS+"," +PROMO_CODE_FIELDS+" from reservation_and_ticket_and_tx where tr_event_id = :eventId and tr_id is not null and tr_status = 'OFFLINE_PAYMENT'") + @Query("select distinct on(tr_id) "+RESERVATION_SEARCH_FIELD+", "+TRANSACTION_FIELDS+"," +PROMO_CODE_FIELDS+" from reservation_and_ticket_and_tx where tr_event_id = :eventId and tr_id is not null and tr_status in('OFFLINE_PAYMENT', 'DEFERRED_OFFLINE_PAYMENT')") List findOfflineReservationsWithOptionalTransaction(@Bind("eventId") int eventId); @Query("select count(distinct tr_id) from (" + FIND_ALL_TICKETS_INCLUDING_NEW +" ) as d_tbl") diff --git a/src/main/java/alfio/util/TemplateResource.java b/src/main/java/alfio/util/TemplateResource.java index ff8f2b5c3c..3eded5aefa 100644 --- a/src/main/java/alfio/util/TemplateResource.java +++ b/src/main/java/alfio/util/TemplateResource.java @@ -271,7 +271,7 @@ private static Map prepareSampleDataForConfirmationEmail(Organiz Optional vat = Optional.of("VAT-NR"); List tickets = Collections.singletonList(new TicketWithCategory(sampleTicket(), sampleCategory())); OrderSummary orderSummary = new OrderSummary(new TotalPrice(1000, 80, 0, 0, "CHF"), - Collections.singletonList(new SummaryRow("Ticket", "10.00", "9.20", 1, "9.20", "9.20", 1000, SummaryRow.SummaryType.TICKET)), false, "10.00", "0.80", false, false, "8", PriceContainer.VatStatus.INCLUDED, "1.00"); + Collections.singletonList(new SummaryRow("Ticket", "10.00", "9.20", 1, "9.20", "9.20", 1000, SummaryRow.SummaryType.TICKET)), false, "10.00", "0.80", false, false, false, "8", PriceContainer.VatStatus.INCLUDED, "1.00"); String reservationUrl = "http://your-domain.tld/reservation-url/"; String reservationShortId = "597e7e7b"; return prepareModelForConfirmationEmail(organization, event, reservation, vat, tickets, orderSummary, reservationUrl, reservationShortId, Optional.of("My Invoice\nAddress"), Optional.empty(), Optional.empty(), Map.of()); diff --git a/src/main/resources/alfio/i18n/public.properties b/src/main/resources/alfio/i18n/public.properties index 7e652cd515..eabf146edd 100644 --- a/src/main/resources/alfio/i18n/public.properties +++ b/src/main/resources/alfio/i18n/public.properties @@ -87,6 +87,9 @@ reservation-page.on-site=On-site cash payment reservation-page.on-site.description=You''ll receive a ticket but in order to access the event you will have to pay at the entrance desk. reservation-page.offline=Bank Transfer reservation-page.offline.description=You''ll have {0} days in order to complete the payment (payment instruction will follow on the next steps). As soon as we''ve received and verified the payment, you''ll receive your ticket. +reservation-page.offline.deferred.description=After confirming the reservation, you will receive detailed instructions on how to complete the payment. Once the payment is complete, you will receive your ticket(s). +reservation-page.offline.deferred.success.title=Thank you for confirming your Reservation! +reservation-page.offline.deferred.success.message=We''ll get back to you soon with the instructions on how to complete the payment. reservation-page.cardholder.name=Cardholder''s name reservation-page.card.details=Card Details reservation-page.card-number=Card Number diff --git a/src/main/resources/alfio/i18n/public_it.properties b/src/main/resources/alfio/i18n/public_it.properties index 1e405c11c5..7d15d808dc 100644 --- a/src/main/resources/alfio/i18n/public_it.properties +++ b/src/main/resources/alfio/i18n/public_it.properties @@ -353,4 +353,7 @@ event-days.from=Da event-days.to=a event-list.no-events=Non ci sono eventi pubblici reservation-page.cancel-reservation.confirmation.text=Confermi di voler annullare questa prenotazione? -error.STEP_1_CATEGORIES_NOT_COMPATIBLE=Le categorie selezionate non possono essere combinate \ No newline at end of file +error.STEP_1_CATEGORIES_NOT_COMPATIBLE=Le categorie selezionate non possono essere combinate +reservation-page.offline.deferred.description=Una volta confermata la prenotazione, riceverai le istruzioni su come completare il pagamento. Una volta che il pagamento sarĂ  stato effettuato, riceverai i tuoi biglietti. +reservation-page.offline.deferred.success.title=Grazie di aver confermato la tua Prenotazione! +reservation-page.offline.deferred.success.message=Riceverai a breve le istruzioni su come effettuare il pagamento. \ No newline at end of file diff --git a/src/main/webapp/resources/angular-templates/admin/partials/configuration/event.html b/src/main/webapp/resources/angular-templates/admin/partials/configuration/event.html index cf01b82aab..017c38694a 100644 --- a/src/main/webapp/resources/angular-templates/admin/partials/configuration/event.html +++ b/src/main/webapp/resources/angular-templates/admin/partials/configuration/event.html @@ -188,21 +188,25 @@

Payment

-
Offline payment configuration
+
Bank Transfer payment configuration
-

In order to be able to accept offline payments, you must fill your Bank Account data.

+

More info and documentation available on the help page.

-
+ + +
- -

If the IBAN above is actually a Revolut Bank Account, you can enable the integration in order to check incoming payments automatically and flag the reservations as complete once the due amount has been received.

-
- +
+ +

If the IBAN above is actually a Revolut Bank Account, you can enable the integration in order to check incoming payments automatically and flag the reservations as complete once the due amount has been received.

+
+ +
@@ -218,10 +222,7 @@

Check-in settings

See Alf.io-PI repository for more information.

-
- -
-