Search in sources :

Example 1 with DefaultNoOpPaymentInfoPlugin

use of org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin in project killbill by killbill.

the class IncompletePaymentTransactionTask method getLatestPaymentTransactionInfoPlugin.

private PaymentTransactionInfoPlugin getLatestPaymentTransactionInfoPlugin(final PaymentTransactionModelDao paymentTransaction, final InternalTenantContext internalTenantContext) {
    final TenantContext tenantContext = internalCallContextFactory.createTenantContext(internalTenantContext);
    final PaymentModelDao payment = paymentDao.getPayment(paymentTransaction.getPaymentId(), internalTenantContext);
    final PaymentTransactionInfoPlugin undefinedPaymentTransaction = new DefaultNoOpPaymentInfoPlugin(payment.getId(), paymentTransaction.getId(), paymentTransaction.getTransactionType(), paymentTransaction.getAmount(), paymentTransaction.getCurrency(), paymentTransaction.getCreatedDate(), paymentTransaction.getCreatedDate(), PaymentPluginStatus.UNDEFINED, null, null);
    PaymentTransactionInfoPlugin paymentTransactionInfoPlugin;
    try {
        final PaymentPluginApi paymentPluginApi = paymentPluginServiceRegistration.getPaymentPluginApi(payment.getPaymentMethodId(), false, internalTenantContext);
        final List<PaymentTransactionInfoPlugin> result = paymentPluginApi.getPaymentInfo(payment.getAccountId(), payment.getId(), ImmutableList.<PluginProperty>of(), tenantContext);
        paymentTransactionInfoPlugin = Iterables.tryFind(result, new Predicate<PaymentTransactionInfoPlugin>() {

            @Override
            public boolean apply(final PaymentTransactionInfoPlugin input) {
                return input.getKbTransactionPaymentId().equals(paymentTransaction.getId());
            }
        }).or(new Supplier<PaymentTransactionInfoPlugin>() {

            @Override
            public PaymentTransactionInfoPlugin get() {
                return undefinedPaymentTransaction;
            }
        });
    } catch (final Exception e) {
        paymentTransactionInfoPlugin = undefinedPaymentTransaction;
    }
    return paymentTransactionInfoPlugin;
}
Also used : PaymentPluginApi(org.killbill.billing.payment.plugin.api.PaymentPluginApi) DefaultNoOpPaymentInfoPlugin(org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) TenantContext(org.killbill.billing.util.callcontext.TenantContext) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) Supplier(com.google.common.base.Supplier) AccountApiException(org.killbill.billing.account.api.AccountApiException) LockFailedException(org.killbill.commons.locker.LockFailedException)

Example 2 with DefaultNoOpPaymentInfoPlugin

use of org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin in project killbill by killbill.

the class IncompletePaymentTransactionTask method tryToProcessNotification.

public void tryToProcessNotification(final JanitorNotificationKey notificationKey, final UUID userToken, final Long accountRecordId, final long tenantRecordId) throws LockFailedException {
    final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(tenantRecordId, accountRecordId);
    tryToDoJanitorOperationWithAccountLock(new JanitorIterationCallback() {

        @Override
        public Void doIteration() {
            // State may have changed since we originally retrieved with no lock
            final PaymentTransactionModelDao rehydratedPaymentTransaction = paymentDao.getPaymentTransaction(notificationKey.getUuidKey(), internalTenantContext);
            final TenantContext tenantContext = internalCallContextFactory.createTenantContext(internalTenantContext);
            final PaymentModelDao payment = paymentDao.getPayment(rehydratedPaymentTransaction.getPaymentId(), internalTenantContext);
            final PaymentTransactionInfoPlugin undefinedPaymentTransaction = new DefaultNoOpPaymentInfoPlugin(payment.getId(), rehydratedPaymentTransaction.getId(), rehydratedPaymentTransaction.getTransactionType(), rehydratedPaymentTransaction.getAmount(), rehydratedPaymentTransaction.getCurrency(), rehydratedPaymentTransaction.getCreatedDate(), rehydratedPaymentTransaction.getCreatedDate(), PaymentPluginStatus.UNDEFINED, null, null);
            PaymentTransactionInfoPlugin paymentTransactionInfoPlugin;
            try {
                final PaymentPluginApi paymentPluginApi = paymentPluginServiceRegistration.getPaymentPluginApi(payment.getPaymentMethodId(), false, internalTenantContext);
                final List<PaymentTransactionInfoPlugin> result = paymentPluginApi.getPaymentInfo(payment.getAccountId(), payment.getId(), ImmutableList.<PluginProperty>of(), tenantContext);
                paymentTransactionInfoPlugin = Iterables.tryFind(result, new Predicate<PaymentTransactionInfoPlugin>() {

                    @Override
                    public boolean apply(final PaymentTransactionInfoPlugin input) {
                        return input.getKbTransactionPaymentId().equals(rehydratedPaymentTransaction.getId());
                    }
                }).or(new Supplier<PaymentTransactionInfoPlugin>() {

                    @Override
                    public PaymentTransactionInfoPlugin get() {
                        return undefinedPaymentTransaction;
                    }
                });
            } catch (final Exception e) {
                paymentTransactionInfoPlugin = undefinedPaymentTransaction;
            }
            updatePaymentAndTransactionIfNeeded(payment, notificationKey.getAttemptNumber(), userToken, rehydratedPaymentTransaction, paymentTransactionInfoPlugin, internalTenantContext);
            return null;
        }
    }, internalTenantContext);
}
Also used : DefaultNoOpPaymentInfoPlugin(org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) TenantContext(org.killbill.billing.util.callcontext.TenantContext) LockFailedException(org.killbill.commons.locker.LockFailedException) IOException(java.io.IOException) Predicate(com.google.common.base.Predicate) PaymentPluginApi(org.killbill.billing.payment.plugin.api.PaymentPluginApi) PluginProperty(org.killbill.billing.payment.api.PluginProperty) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List)

Example 3 with DefaultNoOpPaymentInfoPlugin

use of org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin in project killbill by killbill.

the class TestJanitor method testPendingEntriesThatDontMove.

// The test will check that when a PENDING entry stays PENDING, we go through all our retries and eventually give up (no infinite loop of retries)
// Flaky, see https://github.com/killbill/killbill/issues/860
@Test(groups = "slow", retryAnalyzer = FlakyRetryAnalyzer.class)
public void testPendingEntriesThatDontMove() throws Exception {
    final BigDecimal requestedAmount = BigDecimal.TEN;
    final String paymentExternalKey = "haha";
    final String transactionExternalKey = "hoho!";
    testListener.pushExpectedEvent(NextEvent.PAYMENT);
    final Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, requestedAmount, account.getCurrency(), null, paymentExternalKey, transactionExternalKey, ImmutableList.<PluginProperty>of(), callContext);
    testListener.assertListenerStatus();
    // Artificially move the transaction status to PENDING AND update state on the plugin as well
    final List<PaymentTransactionInfoPlugin> paymentTransactions = mockPaymentProviderPlugin.getPaymentInfo(account.getId(), payment.getId(), ImmutableList.<PluginProperty>of(), callContext);
    final PaymentTransactionInfoPlugin oTx = paymentTransactions.remove(0);
    final PaymentTransactionInfoPlugin updatePaymentTransaction = new DefaultNoOpPaymentInfoPlugin(oTx.getKbPaymentId(), oTx.getKbTransactionPaymentId(), oTx.getTransactionType(), oTx.getAmount(), oTx.getCurrency(), oTx.getCreatedDate(), oTx.getCreatedDate(), PaymentPluginStatus.PENDING, null, null);
    paymentTransactions.add(updatePaymentTransaction);
    mockPaymentProviderPlugin.updatePaymentTransactions(payment.getId(), paymentTransactions);
    final String paymentStateName = paymentSMHelper.getPendingStateForTransaction(TransactionType.AUTHORIZE).toString();
    testListener.pushExpectedEvent(NextEvent.PAYMENT);
    paymentDao.updatePaymentAndTransactionOnCompletion(account.getId(), null, payment.getId(), TransactionType.AUTHORIZE, paymentStateName, paymentStateName, payment.getTransactions().get(0).getId(), TransactionStatus.PENDING, requestedAmount, account.getCurrency(), "loup", "chat", true, internalCallContext);
    testListener.assertListenerStatus();
    // 1h, 1d
    for (final TimeSpan cur : paymentConfig.getPendingTransactionsRetries(internalCallContext)) {
        // Verify there is a notification to retry updating the value
        assertEquals(getPendingNotificationCnt(internalCallContext), 1);
        clock.addDeltaFromReality(cur.getMillis() + 1000);
        assertNotificationsCompleted(internalCallContext, 5);
        // We add a sleep here to make sure the notification gets processed. Note that calling assertNotificationsCompleted alone would not work
        // because there is a point in time where the notification queue is empty (showing notification was processed), but the processing of the notification
        // will itself enter a new notification, and so the synchronization is difficult without writing *too much code*.
        Thread.sleep(1500);
        assertNotificationsCompleted(internalCallContext, 5);
        final Payment updatedPayment = paymentApi.getPayment(payment.getId(), false, false, ImmutableList.<PluginProperty>of(), callContext);
        Assert.assertEquals(updatedPayment.getTransactions().get(0).getTransactionStatus(), TransactionStatus.PENDING);
    }
    await().atMost(TIMEOUT, TimeUnit.SECONDS).until(new Callable<Boolean>() {

        @Override
        public Boolean call() throws Exception {
            return getPendingNotificationCnt(internalCallContext) == 0;
        }
    });
}
Also used : TimeSpan(org.skife.config.TimeSpan) Payment(org.killbill.billing.payment.api.Payment) DefaultNoOpPaymentInfoPlugin(org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) 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) Test(org.testng.annotations.Test)

Example 4 with DefaultNoOpPaymentInfoPlugin

use of org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin in project killbill by killbill.

the class TestDefaultAdminPaymentApi method testFixPaymentTransactionStateFromPaymentTransactionInfoPlugin.

@Test(groups = "slow", description = "https://github.com/killbill/killbill/issues/551")
public void testFixPaymentTransactionStateFromPaymentTransactionInfoPlugin() throws PaymentApiException {
    final Payment payment = paymentApi.createAuthorization(account, account.getPaymentMethodId(), null, BigDecimal.TEN, Currency.EUR, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
    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 PaymentTransactionInfoPlugin infoPlugin = new DefaultNoOpPaymentInfoPlugin(paymentTransactionModelDao.getPaymentId(), paymentTransactionModelDao.getId(), paymentTransactionModelDao.getTransactionType(), paymentTransactionModelDao.getAmount(), paymentTransactionModelDao.getCurrency(), paymentTransactionModelDao.getEffectiveDate(), paymentTransactionModelDao.getCreatedDate(), PaymentPluginStatus.ERROR, "error-code", "error-msg");
    final PaymentTransaction newPaymentTransaction = new DefaultPaymentTransaction(paymentTransactionModelDao.getId(), paymentTransactionModelDao.getAttemptId(), paymentTransactionModelDao.getTransactionExternalKey(), paymentTransactionModelDao.getCreatedDate(), paymentTransactionModelDao.getUpdatedDate(), paymentTransactionModelDao.getPaymentId(), paymentTransactionModelDao.getTransactionType(), paymentTransactionModelDao.getEffectiveDate(), TransactionStatus.PAYMENT_FAILURE, paymentTransactionModelDao.getAmount(), paymentTransactionModelDao.getCurrency(), paymentTransactionModelDao.getProcessedAmount(), paymentTransactionModelDao.getProcessedCurrency(), infoPlugin.getGatewayErrorCode(), infoPlugin.getGatewayError(), infoPlugin);
    adminPaymentApi.fixPaymentTransactionState(payment, newPaymentTransaction, null, null, "AUTH_ERRORED", ImmutableList.<PluginProperty>of(), callContext);
    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(), "error-code");
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getGatewayErrorMsg(), "error-msg");
}
Also used : DefaultNoOpPaymentInfoPlugin(org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) Test(org.testng.annotations.Test)

Example 5 with DefaultNoOpPaymentInfoPlugin

use of org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin in project killbill by killbill.

the class PaymentOperation method doOperation.

private OperationResult doOperation() throws PaymentApiException {
    try {
        // 
        if (paymentStateContext.getOverridePluginOperationResult() == null) {
            final PaymentTransactionInfoPlugin paymentInfoPlugin = doCallSpecificOperationCallback();
            // 
            if (paymentInfoPlugin == null) {
                throw new IllegalStateException("Payment plugin returned a null result");
            }
            logger.debug("Plugin returned paymentTransactionInfoPlugin='{}'", paymentInfoPlugin);
            paymentStateContext.setPaymentTransactionInfoPlugin(paymentInfoPlugin);
            return PaymentTransactionInfoPluginConverter.toOperationResult(paymentStateContext.getPaymentTransactionInfoPlugin());
        } else {
            final PaymentTransactionInfoPlugin paymentInfoPlugin = new DefaultNoOpPaymentInfoPlugin(paymentStateContext.getPaymentId(), paymentStateContext.getTransactionId(), paymentStateContext.getTransactionType(), paymentStateContext.getPaymentTransactionModelDao().getProcessedAmount(), paymentStateContext.getPaymentTransactionModelDao().getProcessedCurrency(), paymentStateContext.getPaymentTransactionModelDao().getEffectiveDate(), paymentStateContext.getPaymentTransactionModelDao().getCreatedDate(), buildPaymentPluginStatusFromOperationResult(paymentStateContext.getOverridePluginOperationResult()), null, null);
            logger.debug("Plugin bypassed, paymentTransactionInfoPlugin='{}'", paymentInfoPlugin);
            paymentStateContext.setPaymentTransactionInfoPlugin(paymentInfoPlugin);
            return paymentStateContext.getOverridePluginOperationResult();
        }
    } catch (final PaymentPluginApiException e) {
        throw new PaymentApiException(e, ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
    }
}
Also used : DefaultNoOpPaymentInfoPlugin(org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin) PaymentPluginApiException(org.killbill.billing.payment.plugin.api.PaymentPluginApiException) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException)

Aggregations

PaymentTransactionInfoPlugin (org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin)7 DefaultNoOpPaymentInfoPlugin (org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin)7 PaymentModelDao (org.killbill.billing.payment.dao.PaymentModelDao)4 PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)3 Test (org.testng.annotations.Test)3 InternalTenantContext (org.killbill.billing.callcontext.InternalTenantContext)2 Payment (org.killbill.billing.payment.api.Payment)2 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)2 PluginProperty (org.killbill.billing.payment.api.PluginProperty)2 PaymentPluginApi (org.killbill.billing.payment.plugin.api.PaymentPluginApi)2 TenantContext (org.killbill.billing.util.callcontext.TenantContext)2 LockFailedException (org.killbill.commons.locker.LockFailedException)2 Predicate (com.google.common.base.Predicate)1 Supplier (com.google.common.base.Supplier)1 ImmutableList (com.google.common.collect.ImmutableList)1 IOException (java.io.IOException)1 BigDecimal (java.math.BigDecimal)1 List (java.util.List)1 UUID (java.util.UUID)1 OperationException (org.killbill.automaton.OperationException)1