From 88f009bcf8c5a22dbabb214a6324b5e292050acf Mon Sep 17 00:00:00 2001 From: srosse <stephane.rosse@frentix.com> Date: Fri, 13 Nov 2020 12:06:30 +0100 Subject: [PATCH] OO-5059: special message if the transaction is pending after payment --- .../ui/RepositoryEntryRuntimeController.java | 4 +- .../resource/accesscontrol/ACService.java | 2 + .../manager/ACFrontendManager.java | 6 ++ .../accesscontrol/manager/ACOrderDAO.java | 25 +++++++ .../ui/AccessRefusedController.java | 22 ++++-- .../ui/_content/access_pending.html | 4 ++ .../ui/_content/access_refused.html | 14 +--- .../ui/_i18n/LocalStrings_de.properties | 1 + .../ui/_i18n/LocalStrings_en.properties | 1 + .../accesscontrol/ACFrontendManagerTest.java | 1 + .../accesscontrol/ACOrderManagerTest.java | 67 +++++++++++++++++++ 11 files changed, 127 insertions(+), 20 deletions(-) create mode 100644 src/main/java/org/olat/resource/accesscontrol/ui/_content/access_pending.html diff --git a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java index 8489cd9e867..eba6ef1491a 100644 --- a/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java +++ b/src/main/java/org/olat/repository/ui/RepositoryEntryRuntimeController.java @@ -1032,7 +1032,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController } private void accessRefused(UserRequest ureq) { - Controller ctrl = new AccessRefusedController(ureq, getWindowControl()); + Controller ctrl = new AccessRefusedController(ureq, getWindowControl(), re); listenTo(ctrl); toolbarPanel.rootController(re.getDisplayname(), ctrl); } @@ -1157,7 +1157,7 @@ public class RepositoryEntryRuntimeController extends MainLayoutBasicController userCourseInfoMgr.updateUserCourseInformations(re.getOlatResource(), getIdentity()); } } else { - runtimeController = new AccessRefusedController(ureq, getWindowControl()); + runtimeController = new AccessRefusedController(ureq, getWindowControl(), re); listenTo(runtimeController); toolbarPanel.rootController(re.getDisplayname(), runtimeController); } diff --git a/src/main/java/org/olat/resource/accesscontrol/ACService.java b/src/main/java/org/olat/resource/accesscontrol/ACService.java index c5aecfe9968..17852eb2266 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ACService.java +++ b/src/main/java/org/olat/resource/accesscontrol/ACService.java @@ -74,6 +74,8 @@ public interface ACService { * @return */ public AccessResult isAccessible(RepositoryEntry entry, Identity forId, Boolean knowMember, boolean allowNonInteractiveAccess); + + public boolean isAccessToResourcePending(OLATResource resource, IdentityRef identity); public Offer createOffer(OLATResource resource, String resourceName); 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 265bc0ae40d..27a06e9a3a0 100644 --- a/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java +++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACFrontendManager.java @@ -481,6 +481,12 @@ public class ACFrontendManager implements ACService, UserDataExportable { } } + @Override + public boolean isAccessToResourcePending(OLATResource resource, IdentityRef identity) { + List<Order> orders = orderManager.findPendingOrders(resource, identity); + return !orders.isEmpty(); + } + @Override public boolean allowAccesToResource(final Identity identity, final Offer offer) { //check if offer is ok: key is stupid but further check as date, validity... diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java index 22c170c338f..2e150a94d6b 100644 --- a/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java +++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACOrderDAO.java @@ -34,6 +34,7 @@ import org.olat.basesecurity.IdentityRef; import org.olat.core.commons.persistence.DB; import org.olat.core.commons.persistence.NativeQueryBuilder; import org.olat.core.commons.persistence.PersistenceHelper; +import org.olat.core.commons.persistence.QueryBuilder; import org.olat.core.commons.persistence.SortKey; import org.olat.core.id.Identity; import org.olat.resource.OLATResource; @@ -44,6 +45,7 @@ import org.olat.resource.accesscontrol.OrderLine; import org.olat.resource.accesscontrol.OrderPart; import org.olat.resource.accesscontrol.OrderStatus; import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.model.AccessTransactionStatus; import org.olat.resource.accesscontrol.model.OrderImpl; import org.olat.resource.accesscontrol.model.OrderLineImpl; import org.olat.resource.accesscontrol.model.OrderPartImpl; @@ -253,6 +255,29 @@ public class ACOrderDAO { Object rawOrders = query.getSingleResult(); return rawOrders instanceof Number ? ((Number)rawOrders).intValue() : 0; } + + public List<Order> findPendingOrders(OLATResource resource, IdentityRef delivery) { + QueryBuilder sb = new QueryBuilder(); + sb.append("select distinct o from ").append(OrderImpl.class.getName()).append(" o") + .append(" inner join o.parts orderPart") + .append(" inner join orderPart.lines orderLine") + .append(" inner join orderLine.offer offer") + .append(" where o.delivery.key=:deliveryKey and offer.resource.key=:resourceKey") + .append(" and o.orderStatus=:status") + .append(" and exists (select trx.key from actransaction as trx") + .append(" where trx.order.key=o.key and trx.statusStr ").in(AccessTransactionStatus.PENDING) + .append(" ) and not exists (select successTrx.key from actransaction as successTrx") + .append(" where successTrx.order.key=o.key and successTrx.statusStr ") + .in(AccessTransactionStatus.SUCCESS, AccessTransactionStatus.ERROR, AccessTransactionStatus.CANCELED) + .append(" )"); + + return dbInstance.getCurrentEntityManager() + .createQuery(sb.toString(), Order.class) + .setParameter("resourceKey", resource.getKey()) + .setParameter("deliveryKey", delivery.getKey()) + .setParameter("status", OrderStatus.PREPAYMENT.name()) + .getResultList(); + } /** * The method is optimized for our settings: 1 order -> 1 order part -> 1 order line diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/AccessRefusedController.java b/src/main/java/org/olat/resource/accesscontrol/ui/AccessRefusedController.java index d1ff4fb5baf..e683057df6d 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/AccessRefusedController.java +++ b/src/main/java/org/olat/resource/accesscontrol/ui/AccessRefusedController.java @@ -21,12 +21,13 @@ package org.olat.resource.accesscontrol.ui; import org.olat.core.gui.UserRequest; import org.olat.core.gui.components.Component; -import org.olat.core.gui.components.panel.SimpleStackedPanel; -import org.olat.core.gui.components.panel.StackedPanel; import org.olat.core.gui.components.velocity.VelocityContainer; import org.olat.core.gui.control.Event; import org.olat.core.gui.control.WindowControl; import org.olat.core.gui.control.controller.BasicController; +import org.olat.repository.RepositoryEntry; +import org.olat.resource.accesscontrol.ACService; +import org.springframework.beans.factory.annotation.Autowired; /** * @@ -35,14 +36,23 @@ import org.olat.core.gui.control.controller.BasicController; * */ public class AccessRefusedController extends BasicController { + + @Autowired + private ACService acService; public AccessRefusedController(UserRequest ureq, WindowControl wControl) { + this(ureq, wControl, null); + } + + public AccessRefusedController(UserRequest ureq, WindowControl wControl, RepositoryEntry entry) { super(ureq, wControl); - VelocityContainer mainVC = createVelocityContainer("access_refused"); - StackedPanel contentP = new SimpleStackedPanel(""); - contentP.setContent(mainVC); - putInitialPanel(contentP); + boolean pending = entry != null && acService + .isAccessToResourcePending(entry.getOlatResource(), getIdentity()); + + String template = pending ? "access_pending" : "access_refused"; + VelocityContainer mainVC = createVelocityContainer(template); + putInitialPanel(mainVC); } @Override diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_pending.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_pending.html new file mode 100644 index 00000000000..a0e29b49dfa --- /dev/null +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_pending.html @@ -0,0 +1,4 @@ +<div class="o_access_method_list" role="alert"> + <h3><i class="o_icon o_icon-fw o_ac_order_status_pending_icon"> </i> $r.translate("access.title")</h3> + <p class="o_warning clearfix">$r.translate("access.pending.desc")</p> +</div> diff --git a/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_refused.html b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_refused.html index a237f835cb6..12e2ef1ab43 100644 --- a/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_refused.html +++ b/src/main/java/org/olat/resource/accesscontrol/ui/_content/access_refused.html @@ -1,14 +1,4 @@ -<div class="o_access_method_list"> - <h3><i class="o_icon o_icon-fw o_icon_booking"> </i> $r.translate("access.title")</h3> +<div class="o_access_method_list" role="alert"> + <h3><i class="o_icon o_icon-fw o_icon_warning"> </i> $r.translate("access.title")</h3> <p class="o_warning clearfix">$r.translate("access.refused.desc")</p> </div> - - - - - - - - - - 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 fc7a16214a3..ddc95bb5ab1 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 @@ -15,6 +15,7 @@ access.free.desc=Diese Ressource ist f\u00FCr Sie frei verf\u00FCgbar. W\u00E4hl access.free.title=Freie Ressource access.info.price.noVat={0} access.info.price.vat={0} (inkl. {1}% MwSt) +access.pending.desc=Ihre Buchung dieser Ressource ist zur Zeit schwebend. Bitte kontaktieren Sie den Besitzer dieser Ressource wenn es zu lange dauert. access.refused.desc=Diese Ressource kann zur Zeit nicht gebucht werden. Bitte kontaktieren Sie den Besitzer dieser Ressource. access.title=Ressource buchen access.token.desc=Diese Ressource ist mit einem Zugangscode gesch\u00FCtzt. Geben Sie einen Zugangscode ein und w\u00E4hlen Sie die Schaltfl\u00E4che "$\:access.button" um sich f\u00FCr den Zugang zu registrieren. Den Zugangscode erhalten Sie von dem Betreiber dieser Ressource. 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 3d63ea907d7..dc555c457f4 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 @@ -15,6 +15,7 @@ access.free.desc=This resource is freely available for you. Press the button "$\ access.free.title=Free resource access.info.price.noVat={0} access.info.price.vat={0} (incl. {1}% VAT) +access.pending.desc=The booking of this resource is currently pending. If the situation doesn't evolve, please contact the owner of this resource. access.refused.desc=This resource is currently not available for booking. Please contact the owner of this resource. access.title=Book resource access.token.desc=This resource is protected with an access code. Enter the access code and press the button "$\:access.button" to register for access. The access code can be obtained from the operator of this resource. diff --git a/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java b/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java index ce082acd0c7..f9ca761e1ad 100644 --- a/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/ACFrontendManagerTest.java @@ -398,6 +398,7 @@ public class ACFrontendManagerTest extends OlatTestCase { CodeHelper.printMilliSecondTime(start, "One click"); } + @Test public void testStandardMethods() { Identity ident = JunitTestHelper.createAndPersistIdentityAsRndUser("ac-method-mgr"); diff --git a/src/test/java/org/olat/resource/accesscontrol/ACOrderManagerTest.java b/src/test/java/org/olat/resource/accesscontrol/ACOrderManagerTest.java index fdafd681897..ccb7afe4e86 100644 --- a/src/test/java/org/olat/resource/accesscontrol/ACOrderManagerTest.java +++ b/src/test/java/org/olat/resource/accesscontrol/ACOrderManagerTest.java @@ -45,8 +45,10 @@ import org.olat.resource.accesscontrol.manager.ACOfferDAO; import org.olat.resource.accesscontrol.manager.ACOrderDAO; import org.olat.resource.accesscontrol.manager.ACTransactionDAO; import org.olat.resource.accesscontrol.model.AccessMethod; +import org.olat.resource.accesscontrol.model.AccessTransactionImpl; import org.olat.resource.accesscontrol.model.AccessTransactionStatus; import org.olat.resource.accesscontrol.model.FreeAccessMethod; +import org.olat.resource.accesscontrol.model.OrderImpl; import org.olat.resource.accesscontrol.model.PriceImpl; import org.olat.resource.accesscontrol.model.RawOrderItem; import org.olat.resource.accesscontrol.model.TokenAccessMethod; @@ -511,6 +513,71 @@ public class ACOrderManagerTest extends OlatTestCase { assertNotNull(retrievedOrder1); } + @Test + public void findPendingOrders() { + //create some offers to buy + Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("pending-"); + OLATResource randomOres = createResource(); + Offer offer = acService.createOffer(randomOres, "Test pending resource 1"); + offer = acService.save(offer); + dbInstance.commitAndCloseSession(); + + //create a link offer to method + List<AccessMethod> methods = acMethodManager.getAvailableMethodsByType(TokenAccessMethod.class); + assertNotNull(methods); + assertEquals(1, methods.size()); + AccessMethod method = methods.get(0); + OfferAccess access = acMethodManager.createOfferAccess(offer, method); + acMethodManager.save(access); + dbInstance.commitAndCloseSession(); + + //save an order + Order order = acOrderManager.saveOneClick(id, access); + ((OrderImpl)order).setOrderStatus(OrderStatus.NEW); + order = acOrderManager.save(order); + dbInstance.commitAndCloseSession(); + + List<Order> newOrders = acOrderManager.findPendingOrders(randomOres, id); + Assert.assertTrue(newOrders.isEmpty()); + + // add a transaction in new status + OrderPart part = order.getParts().get(0); + AccessTransaction accessTransaction = acTransactionManager.createTransaction(order, part, method); + ((AccessTransactionImpl)accessTransaction).setStatus(AccessTransactionStatus.NEW); + acTransactionManager.save(accessTransaction); + dbInstance.commitAndCloseSession(); + + List<Order> reallyNewOrders = acOrderManager.findPendingOrders(randomOres, id); + Assert.assertTrue(reallyNewOrders.isEmpty()); + + // add a transaction pending + order = acOrderManager.loadOrderByKey(order.getKey()); + ((OrderImpl)order).setOrderStatus(OrderStatus.PREPAYMENT); + order = acOrderManager.save(order); + part = order.getParts().get(0); + AccessTransaction pendingAccessTransaction = acTransactionManager.createTransaction(order, part, method); + ((AccessTransactionImpl)pendingAccessTransaction).setStatus(AccessTransactionStatus.PENDING); + acTransactionManager.save(pendingAccessTransaction); + dbInstance.commitAndCloseSession(); + + List<Order> pendingOrders = acOrderManager.findPendingOrders(randomOres, id); + Assert.assertFalse(pendingOrders.isEmpty()); + Assert.assertEquals(order, pendingOrders.get(0)); + + // add a transaction success + order = acOrderManager.loadOrderByKey(order.getKey()); + ((OrderImpl)order).setOrderStatus(OrderStatus.PREPAYMENT); + order = acOrderManager.save(order); + part = order.getParts().get(0); + AccessTransaction successAccessTransaction = acTransactionManager.createTransaction(order, part, method); + ((AccessTransactionImpl)successAccessTransaction).setStatus(AccessTransactionStatus.SUCCESS); + acTransactionManager.save(successAccessTransaction); + dbInstance.commitAndCloseSession(); + + List<Order> successOrders = acOrderManager.findPendingOrders(randomOres, id); + Assert.assertTrue(successOrders.isEmpty()); + } + private OLATResource createResource() { //create a repository entry OLATResourceable resourceable = new TypedResourceable(UUID.randomUUID().toString().replace("-", "")); -- GitLab