From 049eee43e14c20c80f860b908aa6ddc6e99f33e7 Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Mon, 11 Jan 2021 16:11:48 +0100 Subject: [PATCH] OO-5200: optimise selection of buyer's country --- .../paypalcheckout/PaypalCheckoutManager.java | 4 + .../paypalcheckout/PaypalCheckoutModule.java | 26 +++++ .../manager/PaypalCheckoutManagerImpl.java | 49 ++++++++++ ...heckoutAccountConfigurationController.java | 49 ++++++++++ .../ui/PaypalSmartButtonAccessController.java | 6 ++ .../ui/_content/paypal_smart_buttons.html | 2 +- .../ui/_i18n/LocalStrings_de.properties | 2 + .../ui/_i18n/LocalStrings_en.properties | 2 + .../manager/PaypalCheckoutManagerTest.java | 97 +++++++++++++++++++ .../java/org/olat/test/AllTestsJunit4.java | 1 + 10 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerTest.java diff --git a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutManager.java b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutManager.java index 1f30465bb0b..c706ce81f55 100644 --- a/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutManager.java +++ b/src/main/java/org/olat/resource/accesscontrol/provider/paypalcheckout/PaypalCheckoutManager.java @@ -20,6 +20,7 @@ package org.olat.resource.accesscontrol.provider.paypalcheckout; import java.util.List; +import java.util.Locale; import org.olat.core.id.Identity; import org.olat.resource.accesscontrol.OfferAccess; @@ -91,4 +92,7 @@ public interface PaypalCheckoutManager { public List<PaypalCheckoutTransaction> searchTransactions(String id); + + public String getPreferredLocale(Locale locale); + } 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 2a3dbb85271..5017ed8d8bc 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 @@ -51,6 +51,7 @@ public class PaypalCheckoutModule extends AbstractSpringModule { 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 PAYPAL_PREFERRED_COUNTRIES = "paypal.preferRed.countries"; private static final String[] currencies = new String[] { "AUD", @@ -93,6 +94,8 @@ public class PaypalCheckoutModule extends AbstractSpringModule { private boolean acceptPendingReview; @Value("${paypal.webhhok.id:#{null}}") private String webhookId; + @Value("${paypal.preferred.countries:CH}") + private String preferredCountries; @Autowired private PaypalRESTWebhookProvider webhookProvider; @@ -193,6 +196,29 @@ public class PaypalCheckoutModule extends AbstractSpringModule { setStringProperty(PAYPAL_ACCEPT_PENDING_REVIEW, Boolean.toString(accept), true); } + /** + * @return An immutable list of countries to prefer + */ + public List<String> getPreferredCountriesList() { + List<String> countries; + if(StringHelper.containsNonWhitespace(preferredCountries)) { + String[] countriesArr = preferredCountries.split("[,]"); + countries = List.of(countriesArr); + } else { + countries = List.of(); + } + return countries; + } + + public String getPreferredCountries() { + return preferredCountries; + } + + public void setPreferredCountries(String preferredCountries) { + this.preferredCountries = preferredCountries; + setStringProperty(PAYPAL_PREFERRED_COUNTRIES, preferredCountries, true); + } + public String getExcludeFundings() { return excludeFundings; } 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 973bbf27d3e..0ea954fabe0 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 @@ -22,12 +22,15 @@ package org.olat.resource.accesscontrol.provider.paypalcheckout.manager; import java.io.IOException; import java.util.Date; import java.util.List; +import java.util.Locale; import org.apache.logging.log4j.Logger; import org.olat.core.commons.persistence.DB; import org.olat.core.helpers.Settings; import org.olat.core.id.Identity; import org.olat.core.logging.Tracing; +import org.olat.core.util.StringHelper; +import org.olat.core.util.i18n.I18nManager; import org.olat.resource.OLATResource; import org.olat.resource.accesscontrol.ACService; import org.olat.resource.accesscontrol.AccessTransaction; @@ -74,6 +77,8 @@ public class PaypalCheckoutManagerImpl implements PaypalCheckoutManager { @Autowired private ACOrderDAO orderManager; @Autowired + private I18nManager i18nManager; + @Autowired private ACReservationDAO reservationDao; @Autowired private CheckoutV2Provider checkoutProvider; @@ -84,6 +89,50 @@ public class PaypalCheckoutManagerImpl implements PaypalCheckoutManager { @Autowired private PaypalCheckoutTransactionDAO transactionDao; + + @Override + public String getPreferredLocale(Locale locale) { + String val; + List<String> preferredCountries = checkoutModule.getPreferredCountriesList(); + if(preferredCountries.isEmpty()) { + Locale regionalizedLocale = i18nManager.getRegionalizedLocale(locale); + val = regionalizedLocale.toString(); + } else { + String language = locale.getLanguage(); + String country = locale.getCountry(); + if(!StringHelper.containsNonWhitespace(country)) { + Locale[] allLocales = Locale.getAvailableLocales(); + for(String preferredCountry:preferredCountries) { + if(exists(language, preferredCountry, allLocales)) { + country = preferredCountry; + break; + } + } + } + + if(StringHelper.containsNonWhitespace(country)) { + val = language + "_" + country.toUpperCase(); + } else { + Locale regionalizedLocale = i18nManager.getRegionalizedLocale(locale); + val = regionalizedLocale.toString(); + } + } + + if(!StringHelper.containsNonWhitespace(val)) { + val = "de_CH"; + } + return val; + } + + private boolean exists(String language, String country, Locale[] allLocales) { + for(Locale locale:allLocales) { + if(locale.getCountry().equals(country) && locale.getLanguage().equals(language)) { + return true; + } + } + return false; + } + @Override public CheckoutRequest request(Identity delivery, OfferAccess offerAccess, String mapperUri, String sessionId) { StringBuilder url = new StringBuilder(); 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 b419a76f3c1..d9643007ab8 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 @@ -19,7 +19,10 @@ */ package org.olat.resource.accesscontrol.provider.paypalcheckout.ui; +import java.text.Collator; +import java.util.Collection; import java.util.List; +import java.util.Locale; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.form.flexible.FormItem; @@ -34,6 +37,7 @@ import org.olat.core.gui.components.util.KeyValues; import org.olat.core.gui.control.Controller; import org.olat.core.gui.control.WindowControl; import org.olat.core.util.StringHelper; +import org.olat.core.util.i18n.I18nModule; import org.olat.resource.accesscontrol.AccessControlModule; import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutModule; import org.springframework.beans.factory.annotation.Autowired; @@ -56,9 +60,12 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr private SingleSelection smartButtonsEl; private MultipleSelectionElement enableEl; private MultipleSelectionElement pendingReviewEl; + private MultipleSelectionElement preferredCountriesEl; private final List<String> paypalCurrencies; + @Autowired + private I18nModule i18nModule; @Autowired private AccessControlModule acModule; @Autowired @@ -111,6 +118,17 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr currencyEl.select("CHF", true); } + KeyValues countries = getCountries(); + preferredCountriesEl = uifactory.addCheckboxesDropdown("countries", "paypal.preferred.countries", formLayout, + countries.keys(), countries.values()); + preferredCountriesEl.setHelpTextKey("paypal.preferred.countries.hint", null); + List<String> preferredCountries = paypalModule.getPreferredCountriesList(); + for(String country:preferredCountries) { + if(countries.containsKey(country)) { + preferredCountriesEl.select(country, true); + } + } + String clientId = paypalModule.getClientId(); clientIdEl = uifactory.addTextElement("checkout.client.id", 128, clientId, formLayout); String clientSecret = paypalModule.getClientSecret(); @@ -121,6 +139,27 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr uifactory.addFormSubmitButton("save", buttonGroupLayout); } + private KeyValues getCountries() { + KeyValues keyValues = new KeyValues(); + Collection<Locale> languages = i18nModule.getAllLocales().values(); + Locale[] locales = Locale.getAvailableLocales(); + for(Locale language:languages) { + for(Locale locale:locales) { + if(language.getLanguage().equals(locale.getLanguage())) { + String country = locale.getCountry(); + String displayCountry = locale.getDisplayCountry(getLocale()); + if(!keyValues.containsKey(country) && StringHelper.containsNonWhitespace(displayCountry)) { + keyValues.add(KeyValues.entry(country, displayCountry)); + } + } + } + } + + final Collator collator = Collator.getInstance(getLocale()); + keyValues.sort((k1, k2) -> collator.compare(k1.getValue(), k2.getValue())); + return keyValues; + } + private void updateUI() { boolean enabled = enableEl.isAtLeastSelected(1); currencyEl.setVisible(enabled); @@ -164,6 +203,15 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr } super.formInnerEvent(ureq, source, event); } + + private String getPreferredCountries() { + StringBuilder sb = new StringBuilder(); + for(String country:preferredCountriesEl.getSelectedKeys()) { + if(sb.length() > 0) sb.append(","); + sb.append(country); + } + return sb.toString(); + } @Override protected void formOK(UserRequest ureq) { @@ -177,6 +225,7 @@ public class PaypalCheckoutAccountConfigurationController extends FormBasicContr } paypalModule.setSmartButtons(smartButtonsEl.isOneSelected() && smartButtonsEl.isSelected(0)); paypalModule.setAcceptPendingReview(pendingReviewEl.isAtLeastSelected(1)); + paypalModule.setPreferredCountries(getPreferredCountries()); 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 948ff7524da..e25ecf467e1 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 @@ -31,6 +31,7 @@ import org.olat.core.util.Formatter; import org.olat.core.util.StringHelper; import org.olat.resource.accesscontrol.OfferAccess; import org.olat.resource.accesscontrol.Price; +import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutManager; import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutModule; import org.olat.resource.accesscontrol.ui.FormController; import org.olat.resource.accesscontrol.ui.PriceFormat; @@ -48,6 +49,8 @@ public class PaypalSmartButtonAccessController extends FormBasicController imple @Autowired private PaypalCheckoutModule paypalModule; + @Autowired + private PaypalCheckoutManager paypalCheckoutManager; public PaypalSmartButtonAccessController(UserRequest ureq, WindowControl wControl, OfferAccess link) { super(ureq, wControl, "paypal_smart_buttons"); @@ -73,6 +76,9 @@ public class PaypalSmartButtonAccessController extends FormBasicController imple layoutCont.contextPut("excludeFundings", excludeFundings == null ? "" : excludeFundings); layoutCont.contextPut("csrfToken", ureq.getUserSession().getCsrfToken()); + String preferedLocale = paypalCheckoutManager.getPreferredLocale(getLocale()); + layoutCont.contextPut("plocale", preferedLocale); + String description = link.getOffer().getDescription(); if(StringHelper.containsNonWhitespace(description)) { if(!StringHelper.isHtml(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 8fa7d7f612e..ce157276be4 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 data-csp-nonce="${csrfToken}"> jQuery(function() { jQuery.ajax({ - url: 'https://www.paypal.com/sdk/js?client-id=$clientId¤cy=${currency}&intent=authorize&commit=true&disable-funding=${excludeFundings}', + url: 'https://www.paypal.com/sdk/js?client-id=$clientId&locale=$plocale¤cy=${currency}&intent=authorize&commit=true&disable-funding=${excludeFundings}', cache: true,//paypal don't like the anti-cache parameter 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 ee61ca10472..9b91cab3fbb 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 @@ -40,6 +40,8 @@ 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.preferred.countries=Vorselektierte L\u00E4nder +paypal.preferred.countries.hint=Probiert abhängig von der Benutzer Sprache den Land vorzuseleketieren 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 7e23e44f325..c29b407af2d 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 @@ -40,6 +40,8 @@ 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.preferred.countries=Preselected countries +paypal.preferred.countries.hint=Try to pre-select the countries defined here depending of the language of the user. 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/test/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerTest.java b/src/test/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerTest.java new file mode 100644 index 00000000000..584d0cafb58 --- /dev/null +++ b/src/test/java/org/olat/resource/accesscontrol/provider/paypalcheckout/manager/PaypalCheckoutManagerTest.java @@ -0,0 +1,97 @@ +/** + * <a href="http://www.openolat.org"> + * OpenOLAT - Online Learning and Training</a><br> + * <p> + * Licensed under the Apache License, Version 2.0 (the "License"); <br> + * you may not use this file except in compliance with the License.<br> + * You may obtain a copy of the License at the + * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> + * <p> + * Unless required by applicable law or agreed to in writing,<br> + * software distributed under the License is distributed on an "AS IS" BASIS, <br> + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> + * See the License for the specific language governing permissions and <br> + * limitations under the License. + * <p> + * Initial code contributed and copyrighted by<br> + * frentix GmbH, http://www.frentix.com + * <p> + */ +package org.olat.resource.accesscontrol.provider.paypalcheckout.manager; + +import java.util.Locale; + +import org.junit.Assert; +import org.junit.Test; +import org.olat.core.util.i18n.I18nManager; +import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutManager; +import org.olat.resource.accesscontrol.provider.paypalcheckout.PaypalCheckoutModule; +import org.olat.test.OlatTestCase; +import org.springframework.beans.factory.annotation.Autowired; + + +/** + * + * Initial date: 11 janv. 2021<br> + * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com + * + */ +public class PaypalCheckoutManagerTest extends OlatTestCase { + + @Autowired + private I18nManager i18nManager; + @Autowired + private PaypalCheckoutModule paypalCheckoutModule; + @Autowired + private PaypalCheckoutManager paypalCheckoutManager; + + @Test + public void preferredLocale() { + paypalCheckoutModule.setPreferredCountries(""); + + Locale deLocale = i18nManager.getLocaleOrDefault("de"); + String preferredDeLocale = paypalCheckoutManager.getPreferredLocale(deLocale); + Assert.assertEquals("de_DE", preferredDeLocale); + + Locale frLocale = i18nManager.getLocaleOrDefault("fr"); + String preferredFrLocale = paypalCheckoutManager.getPreferredLocale(frLocale); + Assert.assertEquals("fr_FR", preferredFrLocale); + + Locale jpLocale = i18nManager.getLocaleOrDefault("jp"); + String preferredJpLocale = paypalCheckoutManager.getPreferredLocale(jpLocale); + Assert.assertEquals("ja_JP", preferredJpLocale); + + Locale ptBrLocale = i18nManager.getLocaleOrDefault("pt_BR"); + String preferredPtBrLocale = paypalCheckoutManager.getPreferredLocale(ptBrLocale); + Assert.assertEquals("pt_BR", preferredPtBrLocale); + + Locale enLocale = i18nManager.getLocaleOrDefault("en"); + String preferredEnLocale = paypalCheckoutManager.getPreferredLocale(enLocale); + Assert.assertTrue(preferredEnLocale.startsWith("en")); + } + + @Test + public void preferredLocaleInSwitzerland() { + paypalCheckoutModule.setPreferredCountries("CH"); + + Locale deLocale = i18nManager.getLocaleOrDefault("de"); + String preferredDeLocale = paypalCheckoutManager.getPreferredLocale(deLocale); + Assert.assertEquals("de_CH", preferredDeLocale); + + Locale frLocale = i18nManager.getLocaleOrDefault("fr"); + String preferredFrLocale = paypalCheckoutManager.getPreferredLocale(frLocale); + Assert.assertEquals("fr_CH", preferredFrLocale); + + Locale jpLocale = i18nManager.getLocaleOrDefault("jp"); + String preferredJpLocale = paypalCheckoutManager.getPreferredLocale(jpLocale); + Assert.assertEquals("ja_JP", preferredJpLocale); + + Locale ptBrLocale = i18nManager.getLocaleOrDefault("pt_BR"); + String preferredPtBrLocale = paypalCheckoutManager.getPreferredLocale(ptBrLocale); + Assert.assertEquals("pt_BR", preferredPtBrLocale); + + Locale enLocale = i18nManager.getLocaleOrDefault("en"); + String preferredEnLocale = paypalCheckoutManager.getPreferredLocale(enLocale); + Assert.assertEquals("en_CH", preferredEnLocale); + } +} diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java index 7d9c4e9c363..aa0681fa0b6 100644 --- a/src/test/java/org/olat/test/AllTestsJunit4.java +++ b/src/test/java/org/olat/test/AllTestsJunit4.java @@ -486,6 +486,7 @@ import org.junit.runners.Suite; org.olat.resource.accesscontrol.ACReservationDAOTest.class, org.olat.resource.accesscontrol.provider.auto.AutoAccessManagerTest.class, org.olat.resource.accesscontrol.provider.auto.manager.AdvanceOrderDAOTest.class, + org.olat.resource.accesscontrol.provider.paypalcheckout.manager.PaypalCheckoutManagerTest.class, org.olat.resource.accesscontrol.provider.paypalcheckout.manager.PaypalCheckoutTransactionDAOTest.class, /** * Pure JUnit test without need of framework -- GitLab