diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java index 27a06e9a3a083cacfb13e94b593f404f20e81fc8..f8068e465711872c36eb77d9f812f8810ea8912b 100644 --- a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java +++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java @@ -740,6 +740,7 @@ public class ACFrontendManager implements ACService, UserDataExportable { boolean error = false; boolean canceled = false; boolean pending = false; + boolean okPending = false; if(OrderStatus.CANCELED.name().equals(orderStatus)) { canceled = true; @@ -749,6 +750,9 @@ public class ACFrontendManager implements ACService, UserDataExportable { if((trxStatus != null && trxStatus.contains(PaypalCheckoutStatus.PENDING.name())) || (pspTrxStatus != null && pspTrxStatus.contains(PaypalCheckoutStatus.PENDING.name()))) { pending = true; + } else if((trxStatus != null && trxStatus.contains("SUCCESS")) + && (pspTrxStatus != null && pspTrxStatus.contains("INPROCESS"))) { + okPending = true; } else { warning = true; } @@ -772,13 +776,19 @@ public class ACFrontendManager implements ACService, UserDataExportable { } } + if(okPending) { + return Status.OK_PENDING; + } if(pending) { return Status.PENDING; - } else if(error) { + } + if(error) { return Status.ERROR; - } else if (warning) { + } + if (warning) { return Status.WARNING; - } else if(canceled) { + } + if(canceled) { return Status.CANCELED; } return Status.OK; diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutModule.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutModule.java index d35653741e3f85ccf7dae46e62ec826b6e4d93cf..2a3dbb8527119a72cd841881aa400157917093d9 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutModule.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutModule.java @@ -50,6 +50,7 @@ public class PaypalCheckoutModule extends AbstractSpringModule { private static final String PAYPAL_CURRENCY = "paypal.checkout.v2.currency"; private static final String PAYPAL_SMART_BUTTONS = "paypal.checkout.v2.smart.buttons"; private static final String PAYPAL_WEBHOOK_ID = "paypal.webhhok.id"; + private static final String PAYPAL_ACCEPT_PENDING_REVIEW = "paypal.checkout.v2.accept.pending.review"; private static final String[] currencies = new String[] { "AUD", @@ -86,6 +87,10 @@ public class PaypalCheckoutModule extends AbstractSpringModule { private String paypalCurrency; @Value("${paypal.checkout.v2.smart.buttons:true}") private boolean smartButtons; + @Value("${paypal.checkout.v2.exclude.funding:credit,sepa}") + private String excludeFundings; + @Value("${paypal.checkout.v2.accept.pending.review:false}") + private boolean acceptPendingReview; @Value("${paypal.webhhok.id:#{null}}") private String webhookId; @@ -109,7 +114,8 @@ public class PaypalCheckoutModule extends AbstractSpringModule { paypalCurrency = getStringPropertyValue(PAYPAL_CURRENCY, paypalCurrency); webhookId = getStringPropertyValue(PAYPAL_WEBHOOK_ID, webhookId); smartButtons = "true".equals(getStringPropertyValue(PAYPAL_SMART_BUTTONS, Boolean.toString(smartButtons))); - + acceptPendingReview = "true".equals(getStringPropertyValue(PAYPAL_ACCEPT_PENDING_REVIEW, Boolean.toString(acceptPendingReview))); + if(!StringHelper.containsNonWhitespace(webhookId) && StringHelper.containsNonWhitespace(clientId) && StringHelper.containsNonWhitespace(clientSecret)) { updateWebhook(clientId, clientSecret); } @@ -178,6 +184,23 @@ public class PaypalCheckoutModule extends AbstractSpringModule { setStringProperty(PAYPAL_SMART_BUTTONS, Boolean.toString(smartButtons), true); } + public boolean isAcceptPendingReview() { + return acceptPendingReview; + } + + public void setAcceptPendingReview(boolean accept) { + this.acceptPendingReview = accept; + setStringProperty(PAYPAL_ACCEPT_PENDING_REVIEW, Boolean.toString(accept), true); + } + + public String getExcludeFundings() { + return excludeFundings; + } + + public void setExcludeFundings(String excludeFundings) { + this.excludeFundings = excludeFundings; + } + public boolean isSandbox() { return sandbox; } diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerImpl.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerImpl.java index 19349efad8f2a0ccdb6e4c29a0713958f6081204..2dda66c1e3295b178a8218557bea91549755455f 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerImpl.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerImpl.java @@ -45,6 +45,7 @@ import org.olat.resource.accesscontrol.manager.ACTransactionDAO; import org.olat.resource.accesscontrol.model.AccessTransactionStatus; import org.olat.resource.accesscontrol.model.PSPTransaction; import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutManager; +import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutModule; import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutStatus; import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutTransaction; import org.olat.resource.accesscontrol.provider.paypalcheckout.model.CheckoutRequest; @@ -77,6 +78,8 @@ public class PaypalCheckoutManagerImpl implements PaypalCheckoutManager { @Autowired private CheckoutV2Provider checkoutProvider; @Autowired + private PaypalCheckoutModule checkoutModule; + @Autowired private ACTransactionDAO transactionManager; @Autowired private PaypalCheckoutTransactionDAO transactionDao; @@ -248,10 +251,14 @@ public class PaypalCheckoutManagerImpl implements PaypalCheckoutManager { PaypalCheckoutAccessMethod method = getMethodSecure(trx.getMethodId()); if(order.getKey().equals(trx.getOrderId())) { + Identity identity = order.getDelivery(); for(OrderPart part:order.getParts()) { if(part.getKey().equals(trx.getOrderPartId())) { AccessTransaction transaction = transactionManager.createTransaction(order, part, method); - transactionManager.update(transaction, AccessTransactionStatus.PENDING); + transaction = transactionManager.update(transaction, AccessTransactionStatus.PENDING); + if(checkoutModule.isAcceptPendingReview()) { + allowAccessToResource(identity, part, transaction, method); + } } } } else { @@ -301,16 +308,8 @@ public class PaypalCheckoutManagerImpl implements PaypalCheckoutManager { for(OrderPart part:order.getParts()) { if(part.getKey().equals(trx.getOrderPartId())) { AccessTransaction transaction = transactionManager.createTransaction(order, part, method); - transactionManager.save(transaction); - for(OrderLine line:part.getOrderLines()) { - if(acService.allowAccesToResource(identity, line.getOffer())) { - log.info(Tracing.M_AUDIT, "Paypal Checkout payed access granted for: {} to {}", buildLogMessage(line, method), identity); - transaction = transactionManager.update(transaction, AccessTransactionStatus.SUCCESS); - } else { - log.error("Paypal Checkout payed access refused for: {} to {}", buildLogMessage(line, method), identity); - transaction = transactionManager.update(transaction, AccessTransactionStatus.ERROR); - } - } + transaction = transactionManager.save(transaction); + allowAccessToResource(identity, part, transaction, method); } } } else { @@ -319,6 +318,18 @@ public class PaypalCheckoutManagerImpl implements PaypalCheckoutManager { dbInstance.commit(); } + private void allowAccessToResource(Identity identity, OrderPart part, AccessTransaction transaction, PaypalCheckoutAccessMethod method) { + for(OrderLine line:part.getOrderLines()) { + if(acService.allowAccesToResource(identity, line.getOffer())) { + log.info(Tracing.M_AUDIT, "Paypal Checkout payed access granted for: {} to {}", buildLogMessage(line, method), identity); + transaction = transactionManager.update(transaction, AccessTransactionStatus.SUCCESS); + } else { + log.error("Paypal Checkout payed access refused for: {} to {}", buildLogMessage(line, method), identity); + transaction = transactionManager.update(transaction, AccessTransactionStatus.ERROR); + } + } + } + private PaypalCheckoutAccessMethod getMethodSecure(Long key) { PaypalCheckoutAccessMethod smethod = null; List<PaypalCheckoutAccessMethod> methods = getPaypalCheckoutMethods(); diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalCheckoutAccountConfigurationController.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalCheckoutAccountConfigurationController.java index d4b5a9795981ae3f50ee2db09adbd49356fd93bc..b419a76f3c1a6032e94b1caa208c03d370b44ae0 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalCheckoutAccountConfigurationController.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalCheckoutAccountConfigurationController.java @@ -55,6 +55,7 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr private SingleSelection currencyEl; private SingleSelection smartButtonsEl; private MultipleSelectionElement enableEl; + private MultipleSelectionElement pendingReviewEl; private final List<String> paypalCurrencies; @@ -94,6 +95,12 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr } else { smartButtonsEl.select(smartButtonsKeys[1], true); } + + String[] onPendingValues = new String[] { translate("paypal.pending.review.accept") }; + pendingReviewEl = uifactory.addCheckboxesHorizontal("pending.review", "paypal.pending.review", formLayout, onKeys, onPendingValues); + pendingReviewEl.setExampleKey("paypal.pending.review.accept.explain", null); + pendingReviewEl.select(onKeys[0], paypalModule.isAcceptPendingReview()); + pendingReviewEl.addActionListener(FormEvent.ONCHANGE); KeyValues currencies = new KeyValues(); paypalCurrencies.forEach(currency -> currencies.add(KeyValues.entry(currency, currency))); @@ -169,6 +176,7 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr paypalModule.setPaypalCurrency(currencyEl.getSelectedKey()); } paypalModule.setSmartButtons(smartButtonsEl.isOneSelected() && smartButtonsEl.isSelected(0)); + paypalModule.setAcceptPendingReview(pendingReviewEl.isAtLeastSelected(1)); doUpdateWebhook(); } else { paypalModule.setClientId(null); diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalSmartButtonAccessController.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalSmartButtonAccessController.java index ad58d806403fc36cef6e90376b9fb84c58ecef3f..de1b6f1c4701072959409e921f79f374537184b8 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalSmartButtonAccessController.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/PaypalSmartButtonAccessController.java @@ -69,6 +69,8 @@ public class PaypalSmartButtonAccessController extends FormBasicController imple layoutCont.contextPut("clientId", appId); String currency = link.getOffer().getPrice().getCurrencyCode(); layoutCont.contextPut("currency", currency); + String excludeFundings = paypalModule.getExcludeFundings(); + layoutCont.contextPut("excludeFundings", excludeFundings == null ? "" : excludeFundings); String description = link.getOffer().getDescription(); if(StringHelper.containsNonWhitespace(description)) { diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_content/paypal_smart_buttons.html b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_content/paypal_smart_buttons.html index d8f11eb877fd12c5b40ab619ee9a186534a47034..2209d67478a49fcf13cd5e40791211c79b7de8ef 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_content/paypal_smart_buttons.html +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_content/paypal_smart_buttons.html @@ -21,7 +21,7 @@ <script defer> jQuery(function() { jQuery.ajax({ - url: 'https://www.paypal.com/sdk/js?client-id=$clientId¤cy=$currency&intent=authorize', + url: 'https://www.paypal.com/sdk/js?client-id=$clientId¤cy=${currency}&intent=authorize&commit=true&disable-funding=${excludeFundings}', cache: true, dataType: "script", success: loadButtons, diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_de.properties index a43eb885706fccfa8c8a2feb1e380c8132782014..97ee2a73278fb3f0d3ae2d6e612e4b0722628c1e 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_de.properties @@ -37,6 +37,9 @@ paypal.menu.title.alt=PayPal Checkout konfigurieren paypal.order.id=Bestellung ID (in PayPal) paypal.order.status=Status paypal.order.status.reason=Status Erkl\u00E4rung +paypal.pending.review=Ausstehende Transaktionen +paypal.pending.review.accept=Defaultmessig akkzeptieren (Buchung zum Kurs wird durchgef\u00FChrt) +paypal.pending.review.accept.explain=Stornieren von Transaktionen in PayPal werden nicht automatisch Mitgliedschaft im Kurs k\u00FCndigen. paypal.process.transaction=Transaktion ist erfolgreich und wird verarbeitet. paypal.reservation.failed=Es gibt momentan keinen freien Platz. paypal.segment.account=Konto diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_en.properties index 0e72f1ec192b54812cdded5672fca63efff7a2fd..cb9663b94ef0c1afd262f36cc7c1b06cc315f954 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/ui/_i18n/LocalStrings_en.properties @@ -37,6 +37,9 @@ paypal.menu.title.alt=Configure PayPal Checkout paypal.order.id=Order ID (in PayPal) paypal.order.status=Status paypal.order.status.reason=Status reason +paypal.pending.review=Pending transactions +paypal.pending.review.accept=Accept per default (booking to course will be completed) +paypal.pending.review.accept.explain=Canceling transactions in PayPal will not automatically cancel the membership to the course. paypal.process.transaction=Your transaction is approved and is currently processed. paypal.reservation.failed=There isn't currently an available place. paypal.segment.account=Account diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusRenderer.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusRenderer.java index c7bcd9a166a13ee3b07525bd8a7a5cc193912a05..3ad53281494dba6879aa6d08f92bb153a32fc51b 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusRenderer.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrderStatusRenderer.java @@ -68,6 +68,10 @@ public class OrderStatusRenderer implements FlexiCellRenderer { String canceledTitle = translator.translate("order.status.canceled"); sb.append("<span title=\"").append(canceledTitle).append("\"><i class='o_icon o_icon-fw o_ac_order_status_canceled_icon'> </i></span>"); break; + case OK_PENDING: + String acceptedButPending = translator.translate("order.status.ok.pending"); + sb.append("<span title=\"").append(acceptedButPending).append("\"><i class='o_icon o_icon-fw o_ac_order_status_payed_icon'> </i> <small><i class='o_icon o_ac_order_status_pending_icon'> </i></small></span>"); + break; default: String payedTitle = translator.translate("order.status.payed"); sb.append("<span title=\"").append(payedTitle).append("\"><i class='o_icon o_icon-fw o_ac_order_status_payed_icon'> </i></span>"); diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/OrderTableItem.java b/src/main/java/org/olat/resource/accesscontrol/ui/OrderTableItem.java index 751ea8a575f2739494c272171152dab4edd27d6a..ce0b2e2de35ae7d99d26a4129727f2003bbd6660 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/OrderTableItem.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/OrderTableItem.java @@ -121,11 +121,11 @@ public class OrderTableItem { return methods; } - public Collection<AccessTransaction> getTransactions2() { + public Collection<AccessTransaction> getTransactions() { return transactions; } - public Collection<PSPTransaction> getPSPTransactions2() { + public Collection<PSPTransaction> getPSPTransactions() { return pspTransactions; } @@ -141,6 +141,7 @@ public class OrderTableItem { ERROR, WARNING, OK, + OK_PENDING, PENDING, CANCELED, } diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties index ddc95bb5ab160793e56657eda9a1b7fe894517e9..eb5c7120f3eac4228f92c1dc140c950bf0397d98 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_de.properties @@ -87,6 +87,7 @@ order.status=Status order.status.canceled=Abgebrochen order.status.error=Fehler order.status.new=Neu +order.status.ok.pending=Akkzeptiert aber ausstehend order.status.payed=Bezahlt order.status.prepayment=In Zahlungsprozess order.summary=Inhalt diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties index dc555c457f4f847f24901e7df31dfa8704dda4f8..7f3fe23681d5cb074b1c446fbeaa1bf6d340e8b1 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_i18n/LocalStrings_en.properties @@ -105,6 +105,7 @@ order.item.name=Resource name order.menu.title=Bookings order.menu.title.alt=Bookings order.nr=Booking number +order.status.ok.pending=Accepted but pending order.part.payment=Booking method order.status=Status order.status.canceled=Aborted