killbill-memoizeit

Details

diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
index 89473ac..956cb7b 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/JaxrsResource.java
@@ -256,6 +256,8 @@ public interface JaxrsResource {
     public static final String FORM = "form";
     public static final String NOTIFICATION = "notification";
 
+    public static final String CANCEL_SCHEDULED_PAYMENT_TRANSACTION = "cancelScheduledPaymentTransaction";
+
 
     public static final String INVOICE_TEMPLATE = "template";
     public static final String INVOICE_MP_TEMPLATE = "manualPayTemplate";
diff --git a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
index 6b47e30..e0e13b8 100644
--- a/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
+++ b/jaxrs/src/main/java/org/killbill/billing/jaxrs/resources/PaymentResource.java
@@ -784,6 +784,45 @@ public class PaymentResource extends ComboPaymentResource {
         return createPaymentResponse(uriInfo, result, transactionType, paymentTransactionJson.getTransactionExternalKey());
     }
 
+    @TimedResource(name = "cancelScheduledPaymentTransaction")
+    @DELETE
+    @Path("/{paymentTransactionId:" + UUID_PATTERN + "}/" + CANCEL_SCHEDULED_PAYMENT_TRANSACTION)
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    @ApiOperation(value = "Cancels a scheduled payment attempt retry")
+    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionId supplied")})
+    public Response cancelScheduledPaymentTransactionById(@PathParam("paymentTransactionId") final String paymentTransactionId,
+                                                          @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                                          @HeaderParam(HDR_REASON) final String reason,
+                                                          @HeaderParam(HDR_COMMENT) final String comment,
+                                                          @javax.ws.rs.core.Context final UriInfo uriInfo,
+                                                          @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+        paymentApi.cancelScheduledPaymentTransaction(UUID.fromString(paymentTransactionId), callContext);
+        return Response.status(Status.OK).build();
+    }
+
+    @TimedResource(name = "cancelScheduledPaymentTransaction")
+    @DELETE
+    @Path("/" + CANCEL_SCHEDULED_PAYMENT_TRANSACTION)
+    @Consumes(APPLICATION_JSON)
+    @Produces(APPLICATION_JSON)
+    @ApiOperation(value = "Cancels a scheduled payment attempt retry")
+    @ApiResponses(value = {@ApiResponse(code = 400, message = "Invalid paymentTransactionExternalKey supplied")})
+    public Response cancelScheduledPaymentTransactionByExternalKey(@QueryParam(QUERY_TRANSACTION_EXTERNAL_KEY) final String paymentTransactionExternalKey,
+                                                                   @HeaderParam(HDR_CREATED_BY) final String createdBy,
+                                                                   @HeaderParam(HDR_REASON) final String reason,
+                                                                   @HeaderParam(HDR_COMMENT) final String comment,
+                                                                   @javax.ws.rs.core.Context final UriInfo uriInfo,
+                                                                   @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, AccountApiException {
+        final CallContext callContext = context.createContext(createdBy, reason, comment, request);
+        paymentApi.cancelScheduledPaymentTransaction(paymentTransactionExternalKey, callContext);
+        return Response.status(Status.OK).build();
+    }
+
+
+
+
     @TimedResource
     @GET
     @Path("/{paymentId:" + UUID_PATTERN + "}/" + CUSTOM_FIELDS)
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
index 394320d..d73faad 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentApi.java
@@ -582,6 +582,18 @@ public class DefaultPaymentApi extends DefaultApiBase implements PaymentApi {
     }
 
     @Override
+    public void cancelScheduledPaymentTransaction(final String paymentTransactionExternalKey, final CallContext callContext) throws PaymentApiException {
+        checkNotNullParameter(paymentTransactionExternalKey, "paymentTransactionExternalKey");
+        paymentProcessor.cancelScheduledPaymentTransaction(null, paymentTransactionExternalKey, callContext);
+    }
+
+    @Override
+    public void cancelScheduledPaymentTransaction(final UUID paymentTransactionId, final CallContext callContext) throws PaymentApiException {
+        checkNotNullParameter(paymentTransactionId, "paymentTransactionId");
+        paymentProcessor.cancelScheduledPaymentTransaction(paymentTransactionId, null, callContext);
+    }
+
+    @Override
     public Payment notifyPendingTransactionOfStateChanged(final Account account, final UUID paymentTransactionId, final boolean isSuccess, final CallContext callContext) throws PaymentApiException {
         checkNotNullParameter(account, "account");
         checkNotNullParameter(paymentTransactionId, "paymentTransactionId");
diff --git a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
index c57de1c..e8981f9 100644
--- a/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
+++ b/payment/src/main/java/org/killbill/billing/payment/core/PaymentProcessor.java
@@ -353,6 +353,43 @@ public class PaymentProcessor extends ProcessorBase {
                                   );
     }
 
+    public void cancelScheduledPaymentTransaction(@Nullable final UUID paymentTransactionId, @Nullable final String paymentTransactionExternalKey, final CallContext callContext) throws PaymentApiException {
+
+        final InternalCallContext internalCallContextWithoutAccountRecordId = internalCallContextFactory.createInternalCallContextWithoutAccountRecordId(callContext);
+        final String effectivePaymentTransactionExternalKey;
+        if (paymentTransactionExternalKey == null) {
+            final PaymentTransactionModelDao transaction = paymentDao.getPaymentTransaction(paymentTransactionId, internalCallContextWithoutAccountRecordId);
+            effectivePaymentTransactionExternalKey = transaction.getTransactionExternalKey();
+        } else {
+            effectivePaymentTransactionExternalKey = paymentTransactionExternalKey;
+        }
+
+        final List<PaymentAttemptModelDao> attempts = paymentDao.getPaymentAttemptByTransactionExternalKey(effectivePaymentTransactionExternalKey, internalCallContextWithoutAccountRecordId);
+        if (attempts.isEmpty()) {
+            return;
+        }
+
+        final PaymentAttemptModelDao lastPaymentAttempt =  attempts.get(attempts.size() - 1);
+        final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(lastPaymentAttempt.getAccountId(), callContext);
+
+        try {
+            final NotificationQueue retryQueue = notificationQueueService.getNotificationQueue(DefaultPaymentService.SERVICE_NAME, DefaultRetryService.QUEUE_NAME);
+            final List<NotificationEventWithMetadata<NotificationEvent>> notificationEventWithMetadatas =
+                    retryQueue.getFutureNotificationForSearchKeys(internalCallContext.getAccountRecordId(), internalCallContext.getTenantRecordId());
+
+            for (final NotificationEventWithMetadata<NotificationEvent> notificationEvent : notificationEventWithMetadatas) {
+                if (((PaymentRetryNotificationKey) notificationEvent.getEvent()).getAttemptId().equals(lastPaymentAttempt.getId())) {
+                    retryQueue.removeNotification(notificationEvent.getRecordId());
+                    break;
+                }
+            }
+        } catch (final NoSuchNotificationQueue noSuchNotificationQueue) {
+            log.error("ERROR Loading Notification Queue - " + noSuchNotificationQueue.getMessage());
+            throw new IllegalStateException(noSuchNotificationQueue);
+        }
+    }
+
+
     private Payment performOperation(final boolean isApiPayment,
                                      @Nullable final UUID attemptId,
                                      final TransactionType transactionType,

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 03d6a18..5927275 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.124-SNAPSHOT</version>
+        <version>0.125-SNAPSHOT</version>
     </parent>
     <artifactId>killbill</artifactId>
     <version>0.17.3-SNAPSHOT</version>
diff --git a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
index 9c418c8..0baeb5e 100644
--- a/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
+++ b/profiles/killbill/src/test/java/org/killbill/billing/jaxrs/TestPayment.java
@@ -172,8 +172,16 @@ public class TestPayment extends TestJaxrsBase {
 
         Assert.assertEquals(invoicePayments.get(0).getTargetInvoiceId(), failedInvoiceId);
         Assert.assertNotNull(invoicePayments.get(0).getPaymentAttempts());
+        Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().size(), 2);
         Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
         Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(1).getStateName(), "SCHEDULED");
+
+
+        // Remove the future notification and check SCHEDULED does not appear any longer
+        killBillClient.cancelScheduledPaymentTransaction(null, invoicePayments.get(0).getPaymentAttempts().get(1).getTransactionExternalKey(), inputOptions);
+        invoicePayments = killBillClient.getInvoicePayment(failedInvoiceId, inputOptions);
+        Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().size(), 1);
+        Assert.assertEquals(invoicePayments.get(0).getPaymentAttempts().get(0).getStateName(), "RETRIED");
     }
 
     @Test(groups = "slow")