Search in sources :

Example 1 with PaymentAttemptModelDao

use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.

the class PaymentProcessor method getPaymentAttempts.

private List<PaymentAttempt> getPaymentAttempts(final List<PaymentAttemptModelDao> pastPaymentAttempts, final InternalTenantContext internalTenantContext) {
    List<PaymentAttempt> paymentAttempts = new ArrayList<PaymentAttempt>();
    // Add Past Payment Attempts
    for (PaymentAttemptModelDao pastPaymentAttempt : pastPaymentAttempts) {
        DefaultPaymentAttempt paymentAttempt = new DefaultPaymentAttempt(pastPaymentAttempt.getAccountId(), pastPaymentAttempt.getPaymentMethodId(), pastPaymentAttempt.getId(), pastPaymentAttempt.getCreatedDate(), pastPaymentAttempt.getUpdatedDate(), pastPaymentAttempt.getCreatedDate(), pastPaymentAttempt.getPaymentExternalKey(), pastPaymentAttempt.getTransactionId(), pastPaymentAttempt.getTransactionExternalKey(), pastPaymentAttempt.getTransactionType(), pastPaymentAttempt.getStateName(), pastPaymentAttempt.getAmount(), pastPaymentAttempt.getCurrency(), pastPaymentAttempt.getPluginName(), buildPluginProperties(pastPaymentAttempt));
        paymentAttempts.add(paymentAttempt);
    }
    // Get Future Payment Attempts from Notification Queue and add them to the list
    try {
        final NotificationQueue retryQueue = notificationQueueService.getNotificationQueue(DefaultPaymentService.SERVICE_NAME, DefaultRetryService.QUEUE_NAME);
        final Iterable<NotificationEventWithMetadata<NotificationEvent>> notificationEventWithMetadatas = retryQueue.getFutureNotificationForSearchKeys(internalTenantContext.getAccountRecordId(), internalTenantContext.getTenantRecordId());
        for (final NotificationEventWithMetadata<NotificationEvent> notificationEvent : notificationEventWithMetadatas) {
            // Last Attempt
            PaymentAttemptModelDao lastPaymentAttempt = getLastPaymentAttempt(pastPaymentAttempts, ((PaymentRetryNotificationKey) notificationEvent.getEvent()).getAttemptId());
            if (lastPaymentAttempt != null) {
                DefaultPaymentAttempt futurePaymentAttempt = new DefaultPaymentAttempt(// accountId
                lastPaymentAttempt.getAccountId(), // paymentMethodId
                lastPaymentAttempt.getPaymentMethodId(), // id
                ((PaymentRetryNotificationKey) notificationEvent.getEvent()).getAttemptId(), // createdDate
                null, // updatedDate
                null, // effectiveDate
                notificationEvent.getEffectiveDate(), // paymentExternalKey
                lastPaymentAttempt.getPaymentExternalKey(), // transactionId
                null, // transactionExternalKey
                lastPaymentAttempt.getTransactionExternalKey(), // transactionType
                lastPaymentAttempt.getTransactionType(), // stateName
                SCHEDULED, // amount
                lastPaymentAttempt.getAmount(), // currency
                lastPaymentAttempt.getCurrency(), // pluginName,
                ((PaymentRetryNotificationKey) notificationEvent.getEvent()).getPaymentControlPluginNames().get(0), // pluginProperties
                buildPluginProperties(lastPaymentAttempt));
                paymentAttempts.add(futurePaymentAttempt);
            }
        }
    } catch (NoSuchNotificationQueue noSuchNotificationQueue) {
        log.error("ERROR Loading Notification Queue - " + noSuchNotificationQueue.getMessage());
    }
    return paymentAttempts;
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) NoSuchNotificationQueue(org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue) DefaultPaymentAttempt(org.killbill.billing.payment.api.DefaultPaymentAttempt) ArrayList(java.util.ArrayList) PaymentRetryNotificationKey(org.killbill.billing.payment.retry.PaymentRetryNotificationKey) DefaultPaymentAttempt(org.killbill.billing.payment.api.DefaultPaymentAttempt) PaymentAttempt(org.killbill.billing.payment.api.PaymentAttempt) NotificationEventWithMetadata(org.killbill.notificationq.api.NotificationEventWithMetadata) NotificationEvent(org.killbill.notificationq.api.NotificationEvent) NotificationQueue(org.killbill.notificationq.api.NotificationQueue) NoSuchNotificationQueue(org.killbill.notificationq.api.NotificationQueueService.NoSuchNotificationQueue)

Example 2 with PaymentAttemptModelDao

use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.

the class TestDefaultAdminPaymentApi method testFixPaymentTransactionState.

@Test(groups = "slow")
public void testFixPaymentTransactionState() throws PaymentApiException {
    final PaymentOptions paymentOptions = new PaymentOptions() {

        @Override
        public boolean isExternalPayment() {
            return false;
        }

        @Override
        public List<String> getPaymentControlPluginNames() {
            return ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME);
        }
    };
    final Payment payment = paymentApi.createAuthorizationWithPaymentControl(account, account.getPaymentMethodId(), null, BigDecimal.TEN, Currency.EUR, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), paymentOptions, callContext);
    Assert.assertEquals(payment.getTransactions().size(), 1);
    final PaymentModelDao paymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao.getStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(paymentModelDao.getLastSuccessStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
    Assert.assertEquals(paymentTransactionModelDao.getProcessedAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(paymentTransactionModelDao.getProcessedCurrency(), Currency.EUR);
    Assert.assertEquals(paymentTransactionModelDao.getGatewayErrorCode(), "");
    Assert.assertEquals(paymentTransactionModelDao.getGatewayErrorMsg(), "");
    final List<PaymentAttemptModelDao> paymentAttemptModelDaos = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey(), internalCallContext);
    Assert.assertEquals(paymentAttemptModelDaos.size(), 1);
    Assert.assertEquals(paymentAttemptModelDaos.get(0).getStateName(), "SUCCESS");
    Assert.assertEquals(paymentAttemptModelDaos.get(0).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(paymentAttemptModelDaos.get(0).getCurrency(), Currency.EUR);
    adminPaymentApi.fixPaymentTransactionState(payment, payment.getTransactions().get(0), TransactionStatus.PAYMENT_FAILURE, null, "AUTH_ERRORED", ImmutableList.<PluginProperty>of(), callContext);
    Assert.assertEquals(paymentApi.getPayment(payment.getId(), false, false, ImmutableList.<PluginProperty>of(), callContext).getTransactions().size(), 1);
    final PaymentModelDao refreshedPaymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao refreshedPaymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
    Assert.assertEquals(refreshedPaymentModelDao.getStateName(), "AUTH_ERRORED");
    Assert.assertNull(refreshedPaymentModelDao.getLastSuccessStateName());
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getProcessedAmount().compareTo(BigDecimal.ZERO), 0);
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getProcessedCurrency(), Currency.EUR);
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getGatewayErrorCode(), "");
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getGatewayErrorMsg(), "");
    final List<PaymentAttemptModelDao> refreshedPaymentAttemptModelDaos = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey(), internalCallContext);
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.size(), 1);
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.get(0).getStateName(), "ABORTED");
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.get(0).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.get(0).getCurrency(), Currency.EUR);
    // Advance the clock to make sure the effective date of the new transaction is after the first one
    clock.addDays(1);
    assertListenerStatus();
    // Verify subsequent payment retries work
    retryService.retryPaymentTransaction(refreshedPaymentTransactionModelDao.getAttemptId(), ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME), internalCallContext);
    final Payment retriedPayment = paymentApi.getPayment(payment.getId(), false, false, ImmutableList.<PluginProperty>of(), callContext);
    Assert.assertEquals(retriedPayment.getTransactions().size(), 2);
    final PaymentModelDao retriedPaymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao retriedPaymentTransactionModelDao = paymentDao.getPaymentTransaction(retriedPayment.getTransactions().get(1).getId(), internalCallContext);
    Assert.assertEquals(retriedPaymentModelDao.getStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(retriedPaymentModelDao.getLastSuccessStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(retriedPaymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
    Assert.assertEquals(retriedPaymentTransactionModelDao.getProcessedAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(retriedPaymentTransactionModelDao.getProcessedCurrency(), Currency.EUR);
    Assert.assertEquals(retriedPaymentTransactionModelDao.getGatewayErrorCode(), "");
    Assert.assertEquals(retriedPaymentTransactionModelDao.getGatewayErrorMsg(), "");
    final List<PaymentAttemptModelDao> retriedPaymentAttemptModelDaos = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey(), internalCallContext);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.size(), 2);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(0).getStateName(), "ABORTED");
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(0).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(0).getCurrency(), Currency.EUR);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(1).getStateName(), "SUCCESS");
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(1).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(1).getCurrency(), Currency.EUR);
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) Test(org.testng.annotations.Test)

Example 3 with PaymentAttemptModelDao

use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.

the class TestJanitor method testCreateSuccessPurchaseWithPaymentControl.

@Test(groups = "slow")
public void testCreateSuccessPurchaseWithPaymentControl() throws PaymentApiException, InvoiceApiException, EventBusException {
    final BigDecimal requestedAmount = BigDecimal.TEN;
    final UUID subscriptionId = UUID.randomUUID();
    final UUID bundleId = UUID.randomUUID();
    final LocalDate now = clock.getUTCToday();
    testListener.pushExpectedEvent(NextEvent.INVOICE);
    final Invoice invoice = testHelper.createTestInvoice(account, now, Currency.USD);
    testListener.assertListenerStatus();
    final String paymentExternalKey = invoice.getId().toString();
    final String transactionExternalKey = "wouf wouf";
    invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(), account.getId(), subscriptionId, bundleId, "test plan", "test phase", null, now, now.plusMonths(1), requestedAmount, new BigDecimal("1.0"), Currency.USD));
    testListener.pushExpectedEvent(NextEvent.PAYMENT);
    invoicePaymentApi.createPurchaseForInvoicePayment(account, invoice.getId(), account.getPaymentMethodId(), null, requestedAmount, Currency.USD, null, paymentExternalKey, transactionExternalKey, ImmutableList.<PluginProperty>of(), INVOICE_PAYMENT, callContext);
    final Payment payment = paymentApi.getPaymentByExternalKey(paymentExternalKey, false, false, ImmutableList.<PluginProperty>of(), callContext);
    testListener.assertListenerStatus();
    assertEquals(payment.getTransactions().size(), 1);
    assertEquals(payment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.SUCCESS);
    assertEquals(payment.getTransactions().get(0).getTransactionType(), TransactionType.PURCHASE);
    final List<PaymentAttemptModelDao> attempts = paymentDao.getPaymentAttempts(paymentExternalKey, internalCallContext);
    assertEquals(attempts.size(), 1);
    final PaymentAttemptModelDao attempt = attempts.get(0);
    assertEquals(attempt.getStateName(), "SUCCESS");
    assertEquals(attempt.getAmount().compareTo(requestedAmount), 0);
    assertEquals(attempt.getCurrency(), Currency.USD);
    // Ok now the fun part starts... we modify the attempt state to be 'INIT' and wait the the Janitor to do its job.
    paymentDao.updatePaymentAttemptWithProperties(attempt.getId(), attempt.getPaymentMethodId(), attempt.getTransactionId(), "INIT", null, null, null, internalCallContext);
    final PaymentAttemptModelDao attempt2 = paymentDao.getPaymentAttempt(attempt.getId(), internalCallContext);
    assertEquals(attempt2.getStateName(), "INIT");
    assertNull(attempt2.getAmount());
    assertNull(attempt2.getCurrency());
    clock.addDays(1);
    Awaitility.await().atMost(5, TimeUnit.SECONDS).until(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            final PaymentAttemptModelDao attempt3 = paymentDao.getPaymentAttempt(attempt.getId(), internalCallContext);
            return "SUCCESS".equals(attempt3.getStateName());
        }
    });
    final PaymentAttemptModelDao attempt3 = paymentDao.getPaymentAttempt(attempt.getId(), internalCallContext);
    assertEquals(attempt3.getStateName(), "SUCCESS");
    assertEquals(attempt3.getAmount().compareTo(requestedAmount), 0);
    assertEquals(attempt3.getCurrency(), Currency.USD);
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) Invoice(org.killbill.billing.invoice.api.Invoice) LocalDate(org.joda.time.LocalDate) BigDecimal(java.math.BigDecimal) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) EventBusException(org.killbill.bus.api.PersistentBus.EventBusException) Payment(org.killbill.billing.payment.api.Payment) UUID(java.util.UUID) Test(org.testng.annotations.Test)

Example 4 with PaymentAttemptModelDao

use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.

the class TestRetryService method testAbortedPlugin.

// PLUGIN_EXCEPTION will lead to UNKNOWN row that will not be retried by the plugin
@Test(groups = "fast")
public void testAbortedPlugin() throws Exception {
    final Account account = testHelper.createTestAccount("yiyi.gmail.com", true);
    final Invoice invoice = testHelper.createTestInvoice(account, clock.getUTCToday(), Currency.USD);
    final BigDecimal amount = new BigDecimal("10.00");
    final UUID subscriptionId = UUID.randomUUID();
    final UUID bundleId = UUID.randomUUID();
    final LocalDate startDate = clock.getUTCToday();
    final LocalDate endDate = startDate.plusMonths(1);
    invoice.addInvoiceItem(new MockRecurringInvoiceItem(invoice.getId(), account.getId(), subscriptionId, bundleId, "test plan", "test phase", null, startDate, endDate, amount, new BigDecimal("1.0"), Currency.USD));
    setPaymentFailure(FailureType.PLUGIN_EXCEPTION);
    boolean failed = false;
    final String paymentExternalKey = UUID.randomUUID().toString();
    final String transactionExternalKey = UUID.randomUUID().toString();
    try {
        invoicePaymentInternalApi.createPurchaseForInvoicePayment(false, account, invoice.getId(), account.getPaymentMethodId(), null, amount, Currency.USD, null, paymentExternalKey, transactionExternalKey, NO_PROPERTIES, PAYMENT_OPTIONS, internalCallContext);
    } catch (final PaymentApiException e) {
        failed = true;
    }
    assertTrue(failed);
    Payment payment = getPaymentForExternalKey(paymentExternalKey);
    List<PaymentAttemptModelDao> attempts = paymentDao.getPaymentAttempts(paymentExternalKey, internalCallContext);
    assertEquals(attempts.size(), 1);
    final List<PaymentTransactionModelDao> transactions = paymentDao.getTransactionsForPayment(payment.getId(), internalCallContext);
    assertEquals(transactions.size(), 1);
    attempts = paymentDao.getPaymentAttempts(payment.getExternalKey(), internalCallContext);
    final int expectedAttempts = 1;
    assertEquals(attempts.size(), expectedAttempts);
    assertEquals(attempts.get(0).getStateName(), "ABORTED");
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) LocalDate(org.joda.time.LocalDate) BigDecimal(java.math.BigDecimal) Payment(org.killbill.billing.payment.api.Payment) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) UUID(java.util.UUID) Test(org.testng.annotations.Test)

Example 5 with PaymentAttemptModelDao

use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.

the class TestRetryablePayment method testInitToSuccessWithPaymentExceptionAndRetries.

@Test(groups = "fast")
public void testInitToSuccessWithPaymentExceptionAndRetries() {
    mockRetryProviderPlugin.setAborted(false).setNextRetryDate(new DateTime(clock.getUTCNow().plusDays(1)));
    mockRetryAuthorizeOperationCallback.setResult(null).setException(new PaymentApiException(ErrorCode.__UNKNOWN_ERROR_CODE, "bla bla"));
    runner.setOperationCallback(mockRetryAuthorizeOperationCallback).setContext(paymentStateContext);
    try {
        runner.run(true, TransactionType.AUTHORIZE, ControlOperation.AUTHORIZE, account, paymentMethodId, null, paymentExternalKey, paymentTransactionExternalKey, amount, currency, null, emptyProperties, null, callContext, internalCallContext);
        fail("Expected PaymentApiException...");
    } catch (final PaymentApiException e) {
        final PaymentAttemptModelDao pa = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionExternalKey, internalCallContext).get(0);
        assertEquals(pa.getTransactionExternalKey(), paymentTransactionExternalKey);
        assertEquals(pa.getStateName(), "RETRIED");
        assertEquals(pa.getTransactionType(), TransactionType.AUTHORIZE);
    }
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Aggregations

PaymentAttemptModelDao (org.killbill.billing.payment.dao.PaymentAttemptModelDao)33 Test (org.testng.annotations.Test)24 UUID (java.util.UUID)16 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)15 PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)12 BigDecimal (java.math.BigDecimal)10 LocalDate (org.joda.time.LocalDate)10 Invoice (org.killbill.billing.invoice.api.Invoice)10 Account (org.killbill.billing.account.api.Account)8 Payment (org.killbill.billing.payment.api.Payment)8 DateTime (org.joda.time.DateTime)7 State (org.killbill.automaton.State)7 Predicate (com.google.common.base.Predicate)6 ArrayList (java.util.ArrayList)6 PaymentModelDao (org.killbill.billing.payment.dao.PaymentModelDao)6 ImmutableList (com.google.common.collect.ImmutableList)5 List (java.util.List)5 AccountData (org.killbill.billing.account.api.AccountData)3 ExpectedInvoiceItemCheck (org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck)3 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)3