Search in sources :

Example 11 with PaymentModelDao

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

the class TestPaymentLeavingStateCallback method testLeaveStateForNewPayment.

@Test(groups = "slow")
public void testLeaveStateForNewPayment() throws Exception {
    setUp(null);
    callback.leavingState(state);
    // Verify a new transaction was created
    verifyPaymentTransaction();
    // Verify a new payment was created
    final PaymentModelDao payment = paymentDao.getPayment(paymentStateContext.getPaymentTransactionModelDao().getPaymentId(), internalCallContext);
    Assert.assertEquals(payment.getExternalKey(), paymentStateContext.getPaymentExternalKey());
    Assert.assertNull(payment.getStateName());
    // Verify the payment has only one transaction
    Assert.assertEquals(paymentDao.getTransactionsForPayment(payment.getId(), internalCallContext).size(), 1);
}
Also used : PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) Test(org.testng.annotations.Test)

Example 12 with PaymentModelDao

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

the class TestPaymentLeavingStateCallback method setUp.

private void setUp(@Nullable final UUID paymentId) throws Exception {
    account = Mockito.mock(Account.class);
    Mockito.when(account.getId()).thenReturn(UUID.randomUUID());
    paymentStateContext = new PaymentStateContext(true, paymentId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), TransactionType.CAPTURE, account, UUID.randomUUID(), new BigDecimal("192.3920111"), Currency.BRL, null, null, null, false, null, ImmutableList.<PluginProperty>of(), internalCallContext, callContext);
    if (paymentId != null) {
        // Create the first payment manually
        final PaymentModelDao newPaymentModelDao = new PaymentModelDao(paymentId, clock.getUTCNow(), clock.getUTCNow(), paymentStateContext.getAccount().getId(), paymentStateContext.getPaymentMethodId(), 1, paymentStateContext.getPaymentExternalKey());
        final PaymentTransactionModelDao newPaymentTransactionModelDao = new PaymentTransactionModelDao(clock.getUTCNow(), clock.getUTCNow(), null, paymentStateContext.getPaymentTransactionExternalKey(), paymentId, paymentStateContext.getTransactionType(), clock.getUTCNow(), TransactionStatus.UNKNOWN, paymentStateContext.getAmount(), paymentStateContext.getCurrency(), null, null);
        paymentDao.insertPaymentWithFirstTransaction(newPaymentModelDao, newPaymentTransactionModelDao, internalCallContext);
    }
    final PaymentAutomatonDAOHelper daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
    callback = new PaymentLeavingStateTestCallback(daoHelper, paymentStateContext);
    Mockito.when(state.getName()).thenReturn("NEW_STATE");
}
Also used : Account(org.killbill.billing.account.api.Account) PluginProperty(org.killbill.billing.payment.api.PluginProperty) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) BigDecimal(java.math.BigDecimal)

Example 13 with PaymentModelDao

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

the class PaymentRefresher method invokeJanitor.

// Invoke the Janitor on-the-fly for all GET operations and for most payment operations (except notifyPendingPaymentOfStateChanged)
public PaymentModelDao invokeJanitor(final PaymentModelDao curPaymentModelDao, final Collection<PaymentTransactionModelDao> curTransactionsModelDao, @Nullable final Iterable<PaymentTransactionInfoPlugin> pluginTransactions, final boolean isApiPayment, final InternalTenantContext internalTenantContext) {
    PaymentModelDao newPaymentModelDao = curPaymentModelDao;
    final Collection<PaymentTransactionModelDao> transactionsModelDao = new LinkedList<PaymentTransactionModelDao>();
    for (final PaymentTransactionModelDao curPaymentTransactionModelDao : curTransactionsModelDao) {
        PaymentTransactionModelDao newPaymentTransactionModelDao = curPaymentTransactionModelDao;
        final PaymentTransactionInfoPlugin paymentTransactionInfoPlugin = findPaymentTransactionInfoPlugin(newPaymentTransactionModelDao, pluginTransactions);
        if (paymentTransactionInfoPlugin != null) {
            // Make sure to invoke the Janitor task in case the plugin fixes its state on the fly
            // See https://github.com/killbill/killbill/issues/341
            final boolean hasChanged = invokeJanitor(newPaymentModelDao.getAccountId(), newPaymentTransactionModelDao, paymentTransactionInfoPlugin, isApiPayment, internalTenantContext);
            if (hasChanged) {
                newPaymentModelDao = paymentDao.getPayment(newPaymentModelDao.getId(), internalTenantContext);
                newPaymentTransactionModelDao = paymentDao.getPaymentTransaction(newPaymentTransactionModelDao.getId(), internalTenantContext);
            }
        } else {
            log.debug("Unable to find transaction={} from pluginTransactions={}", curPaymentTransactionModelDao, pluginTransactions);
        }
        transactionsModelDao.add(newPaymentTransactionModelDao);
    }
    curTransactionsModelDao.clear();
    curTransactionsModelDao.addAll(transactionsModelDao);
    return newPaymentModelDao;
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) LinkedList(java.util.LinkedList)

Example 14 with PaymentModelDao

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

the class PluginControlPaymentProcessor method retryPaymentTransaction.

public void retryPaymentTransaction(final UUID attemptId, final List<String> paymentControlPluginNames, final InternalCallContext internalCallContext) {
    final PaymentAttemptModelDao attempt = paymentDao.getPaymentAttempt(attemptId, internalCallContext);
    log.info("Retrying attemptId='{}', paymentExternalKey='{}', transactionExternalKey='{}'. paymentControlPluginNames='{}'", attemptId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), paymentControlPluginNames);
    final PaymentModelDao paymentModelDao = paymentDao.getPaymentByExternalKey(attempt.getPaymentExternalKey(), internalCallContext);
    final UUID paymentId = paymentModelDao != null ? paymentModelDao.getId() : null;
    final CallContext callContext = buildCallContext(internalCallContext);
    final String transactionType = TransactionType.PURCHASE.name();
    Account account = null;
    Payment payment = null;
    PaymentTransaction paymentTransaction = null;
    try {
        account = accountInternalApi.getAccountById(attempt.getAccountId(), internalCallContext);
        final State state = paymentControlStateMachineHelper.getState(attempt.getStateName());
        final Iterable<PluginProperty> pluginProperties = PluginPropertySerializer.deserialize(attempt.getPluginProperties());
        logEnterAPICall(log, transactionType, account, attempt.getPaymentMethodId(), paymentId, null, attempt.getAmount(), attempt.getCurrency(), attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), null, paymentControlPluginNames);
        payment = pluginControlledPaymentAutomatonRunner.run(state, false, attempt.getTransactionType(), ControlOperation.valueOf(attempt.getTransactionType().toString()), account, attempt.getPaymentMethodId(), paymentId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), // The amount on the payment attempt drives the amount of the new payment transaction
        attempt.getAmount(), attempt.getCurrency(), null, pluginProperties, paymentControlPluginNames, callContext, internalCallContext);
        log.debug("retryPaymentTransaction result: payment='{}'", payment);
        paymentTransaction = Iterables.<PaymentTransaction>find(Lists.<PaymentTransaction>reverse(payment.getTransactions()), new Predicate<PaymentTransaction>() {

            @Override
            public boolean apply(final PaymentTransaction input) {
                return attempt.getTransactionExternalKey().equals(input.getExternalKey());
            }
        });
    } catch (final AccountApiException e) {
        log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
    } catch (final PaymentApiException e) {
        // Log exception unless nothing left to be paid
        if (e.getCode() == ErrorCode.PAYMENT_PLUGIN_API_ABORTED.getCode() && paymentControlPluginNames != null && paymentControlPluginNames.size() == 1 && InvoicePaymentControlPluginApi.PLUGIN_NAME.equals(paymentControlPluginNames.get(0))) {
            log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames));
        } else {
            log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
        }
    } catch (final PluginPropertySerializerException e) {
        log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
    } catch (final MissingEntryException e) {
        log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
    } finally {
        logExitAPICall(log, transactionType, account, payment != null ? payment.getPaymentMethodId() : null, payment != null ? payment.getId() : null, paymentTransaction != null ? paymentTransaction.getId() : null, paymentTransaction != null ? paymentTransaction.getProcessedAmount() : null, paymentTransaction != null ? paymentTransaction.getProcessedCurrency() : null, payment != null ? payment.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null, paymentControlPluginNames, null);
    }
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) Account(org.killbill.billing.account.api.Account) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PluginPropertySerializerException(org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) Predicate(com.google.common.base.Predicate) PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) PluginProperty(org.killbill.billing.payment.api.PluginProperty) Payment(org.killbill.billing.payment.api.Payment) State(org.killbill.automaton.State) AccountApiException(org.killbill.billing.account.api.AccountApiException) MissingEntryException(org.killbill.automaton.MissingEntryException) UUID(java.util.UUID)

Example 15 with PaymentModelDao

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

the class PaymentAutomatonRunner method retrievePaymentId.

// TODO Could we cache these to avoid extra queries in PaymentAutomatonDAOHelper?
private UUID retrievePaymentId(@Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey, final InternalCallContext internalCallContext) throws PaymentApiException {
    if (paymentExternalKey != null) {
        final PaymentModelDao payment = paymentDao.getPaymentByExternalKey(paymentExternalKey, internalCallContext);
        if (payment != null) {
            return payment.getId();
        }
    }
    if (paymentTransactionExternalKey == null) {
        return null;
    }
    final List<PaymentTransactionModelDao> paymentTransactionModelDaos = paymentDao.getPaymentTransactionsByExternalKey(paymentTransactionExternalKey, internalCallContext);
    for (final PaymentTransactionModelDao paymentTransactionModelDao : paymentTransactionModelDaos) {
        if (paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.SUCCESS || paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.PENDING || paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.UNKNOWN) {
            return paymentTransactionModelDao.getPaymentId();
        }
    }
    UUID paymentIdCandidate = null;
    for (final PaymentTransactionModelDao paymentTransactionModelDao : paymentTransactionModelDaos) {
        if (paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.PAYMENT_FAILURE || paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.PLUGIN_FAILURE) {
            if (paymentIdCandidate == null) {
                paymentIdCandidate = paymentTransactionModelDao.getPaymentId();
            } else if (!paymentIdCandidate.equals(paymentTransactionModelDao.getPaymentId())) {
                throw new PaymentApiException(ErrorCode.PAYMENT_INTERNAL_ERROR, "Multiple failed payments sharing the same transaction external key - this should never happen");
            }
        }
    }
    return paymentIdCandidate;
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) UUID(java.util.UUID)

Aggregations

PaymentModelDao (org.killbill.billing.payment.dao.PaymentModelDao)28 PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)21 Test (org.testng.annotations.Test)11 UUID (java.util.UUID)10 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)9 PaymentTransactionInfoPlugin (org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin)9 Predicate (com.google.common.base.Predicate)8 PaymentAttemptModelDao (org.killbill.billing.payment.dao.PaymentAttemptModelDao)6 PluginProperty (org.killbill.billing.payment.api.PluginProperty)5 LinkedList (java.util.LinkedList)4 State (org.killbill.automaton.State)4 PaymentPluginApi (org.killbill.billing.payment.plugin.api.PaymentPluginApi)4 DefaultNoOpPaymentInfoPlugin (org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin)4 BigDecimal (java.math.BigDecimal)3 ImmutableList (com.google.common.collect.ImmutableList)2 List (java.util.List)2 DateTime (org.joda.time.DateTime)2 Account (org.killbill.billing.account.api.Account)2 AccountApiException (org.killbill.billing.account.api.AccountApiException)2 InternalTenantContext (org.killbill.billing.callcontext.InternalTenantContext)2