Search in sources :

Example 1 with PaymentStateContext

use of org.killbill.billing.payment.core.sm.PaymentStateContext in project killbill by killbill.

the class PaymentProcessor method performOperation.

private Payment performOperation(final boolean isApiPayment, final boolean runJanitor, @Nullable final UUID attemptId, final TransactionType transactionType, final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID paymentId, @Nullable final UUID transactionId, @Nullable final BigDecimal amount, @Nullable final Currency currency, @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey, @Nullable final UUID paymentIdForNewPayment, @Nullable final UUID paymentTransactionIdForNewPaymentTransaction, final boolean shouldLockAccountAndDispatch, @Nullable final OperationResult overridePluginOperationResult, final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
    final PaymentStateContext paymentStateContext = paymentAutomatonRunner.buildPaymentStateContext(isApiPayment, transactionType, account, attemptId, paymentMethodId != null ? paymentMethodId : account.getPaymentMethodId(), paymentId, transactionId, paymentExternalKey, paymentTransactionExternalKey, amount, currency, paymentIdForNewPayment, paymentTransactionIdForNewPaymentTransaction, shouldLockAccountAndDispatch, overridePluginOperationResult, properties, callContext, internalCallContext);
    final PaymentAutomatonDAOHelper daoHelper = paymentAutomatonRunner.buildDaoHelper(paymentStateContext, internalCallContext);
    String currentStateName = null;
    if (paymentStateContext.getPaymentId() != null) {
        PaymentModelDao paymentModelDao = daoHelper.getPayment();
        // Sanity: verify the payment belongs to the right account (in case it was looked-up by payment or transaction external key)
        if (!paymentModelDao.getAccountRecordId().equals(internalCallContext.getAccountRecordId())) {
            throw new PaymentApiException(ErrorCode.PAYMENT_DIFFERENT_ACCOUNT_ID, paymentStateContext.getPaymentId());
        }
        // Note: the list needs to be modifiable for invokeJanitor
        final Collection<PaymentTransactionModelDao> paymentTransactionsForCurrentPayment = new LinkedList<PaymentTransactionModelDao>(daoHelper.getPaymentDao().getTransactionsForPayment(paymentStateContext.getPaymentId(), paymentStateContext.getInternalCallContext()));
        // prevent disallowed transitions in case the state couldn't be fixed (or if it's already in a final state).
        if (runJanitor) {
            final PaymentPluginApi plugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), true, internalCallContext);
            final List<PaymentTransactionInfoPlugin> pluginTransactions = getPaymentTransactionInfoPlugins(plugin, paymentModelDao, properties, callContext);
            paymentModelDao = invokeJanitor(paymentModelDao, paymentTransactionsForCurrentPayment, pluginTransactions, internalCallContext);
        }
        if (paymentStateContext.getPaymentTransactionExternalKey() != null) {
            final List<PaymentTransactionModelDao> allPaymentTransactionsForKey = daoHelper.getPaymentDao().getPaymentTransactionsByExternalKey(paymentStateContext.getPaymentTransactionExternalKey(), internalCallContext);
            runSanityOnTransactionExternalKey(allPaymentTransactionsForKey, paymentStateContext, internalCallContext);
        }
        if (paymentStateContext.getTransactionId() != null || paymentStateContext.getPaymentTransactionExternalKey() != null) {
            // If a transaction id or key is passed, we are maybe completing an existing transaction (unless a new key was provided)
            PaymentTransactionModelDao transactionToComplete = findTransactionToCompleteAndRunSanityChecks(paymentModelDao, paymentTransactionsForCurrentPayment, paymentStateContext, internalCallContext);
            if (transactionToComplete != null) {
                final UUID transactionToCompleteId = transactionToComplete.getId();
                transactionToComplete = Iterables.<PaymentTransactionModelDao>find(paymentTransactionsForCurrentPayment, new Predicate<PaymentTransactionModelDao>() {

                    @Override
                    public boolean apply(final PaymentTransactionModelDao input) {
                        return transactionToCompleteId.equals(input.getId());
                    }
                });
                // We can't tell where we should be in the state machine - bail (cannot be enforced by the state machine unfortunately because UNKNOWN and PLUGIN_FAILURE are both treated as EXCEPTION)
                if (transactionToComplete.getTransactionStatus() == TransactionStatus.UNKNOWN) {
                    throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_OPERATION, paymentStateContext.getTransactionType(), transactionToComplete.getTransactionStatus());
                }
                paymentStateContext.setPaymentTransactionModelDao(transactionToComplete);
            }
        }
        // Use the original payment method id of the payment being completed
        paymentStateContext.setPaymentMethodId(paymentModelDao.getPaymentMethodId());
        // We always take the last successful state name to permit retries on failures
        currentStateName = paymentModelDao.getLastSuccessStateName();
    }
    final UUID nonNullPaymentId = paymentAutomatonRunner.run(paymentStateContext, daoHelper, currentStateName, transactionType);
    return getPayment(nonNullPaymentId, true, false, properties, callContext, internalCallContext);
}
Also used : PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) LinkedList(java.util.LinkedList) Predicate(com.google.common.base.Predicate) PaymentPluginApi(org.killbill.billing.payment.plugin.api.PaymentPluginApi) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentAutomatonDAOHelper(org.killbill.billing.payment.core.sm.PaymentAutomatonDAOHelper) PaymentStateContext(org.killbill.billing.payment.core.sm.PaymentStateContext) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) UUID(java.util.UUID)

Example 2 with PaymentStateContext

use of org.killbill.billing.payment.core.sm.PaymentStateContext in project killbill by killbill.

the class PaymentProcessor method performOperation.

private Payment performOperation(final boolean isApiPayment, final boolean runJanitor, @Nullable final UUID attemptId, final TransactionType transactionType, final Account account, @Nullable final UUID paymentMethodId, @Nullable final UUID paymentId, @Nullable final UUID transactionId, @Nullable final BigDecimal amount, @Nullable final Currency currency, @Nullable final DateTime effectiveDate, @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey, @Nullable final UUID paymentIdForNewPayment, @Nullable final UUID paymentTransactionIdForNewPaymentTransaction, final boolean shouldLockAccountAndDispatch, @Nullable final OperationResult overridePluginOperationResult, final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
    final PaymentStateContext paymentStateContext = paymentAutomatonRunner.buildPaymentStateContext(isApiPayment, transactionType, account, attemptId, paymentMethodId != null ? paymentMethodId : account.getPaymentMethodId(), paymentId, transactionId, paymentExternalKey, paymentTransactionExternalKey, amount, currency, effectiveDate, paymentIdForNewPayment, paymentTransactionIdForNewPaymentTransaction, shouldLockAccountAndDispatch, overridePluginOperationResult, properties, callContext, internalCallContext);
    final PaymentAutomatonDAOHelper daoHelper = paymentAutomatonRunner.buildDaoHelper(paymentStateContext, internalCallContext);
    String currentStateName = null;
    if (paymentStateContext.getPaymentId() != null) {
        PaymentModelDao paymentModelDao = daoHelper.getPayment();
        // Sanity: verify the payment belongs to the right account (in case it was looked-up by payment or transaction external key)
        if (!paymentModelDao.getAccountRecordId().equals(internalCallContext.getAccountRecordId())) {
            throw new PaymentApiException(ErrorCode.PAYMENT_DIFFERENT_ACCOUNT_ID, paymentStateContext.getPaymentId());
        }
        // Note: the list needs to be modifiable for invokeJanitor
        final Collection<PaymentTransactionModelDao> paymentTransactionsForCurrentPayment = new LinkedList<PaymentTransactionModelDao>(daoHelper.getPaymentDao().getTransactionsForPayment(paymentStateContext.getPaymentId(), paymentStateContext.getInternalCallContext()));
        // prevent disallowed transitions in case the state couldn't be fixed (or if it's already in a final state).
        if (runJanitor) {
            final PaymentPluginApi plugin = getPaymentProviderPlugin(paymentModelDao.getPaymentMethodId(), true, internalCallContext);
            final List<PaymentTransactionInfoPlugin> pluginTransactions = paymentRefresher.getPaymentTransactionInfoPlugins(plugin, paymentModelDao, properties, callContext);
            paymentModelDao = paymentRefresher.invokeJanitor(paymentModelDao, paymentTransactionsForCurrentPayment, pluginTransactions, isApiPayment, internalCallContext);
        }
        if (paymentStateContext.getPaymentTransactionExternalKey() != null) {
            final List<PaymentTransactionModelDao> allPaymentTransactionsForKey = daoHelper.getPaymentDao().getPaymentTransactionsByExternalKey(paymentStateContext.getPaymentTransactionExternalKey(), internalCallContext);
            runSanityOnTransactionExternalKey(allPaymentTransactionsForKey, paymentStateContext, internalCallContext);
        }
        if (paymentStateContext.getTransactionId() != null || paymentStateContext.getPaymentTransactionExternalKey() != null) {
            // If a transaction id or key is passed, we are maybe completing an existing transaction (unless a new key was provided)
            PaymentTransactionModelDao transactionToComplete = findTransactionToCompleteAndRunSanityChecks(paymentModelDao, paymentTransactionsForCurrentPayment, paymentStateContext, internalCallContext);
            if (transactionToComplete != null) {
                final UUID transactionToCompleteId = transactionToComplete.getId();
                transactionToComplete = Iterables.<PaymentTransactionModelDao>find(paymentTransactionsForCurrentPayment, new Predicate<PaymentTransactionModelDao>() {

                    @Override
                    public boolean apply(final PaymentTransactionModelDao input) {
                        return transactionToCompleteId.equals(input.getId());
                    }
                });
                // We can't tell where we should be in the state machine - bail (cannot be enforced by the state machine unfortunately because UNKNOWN and PLUGIN_FAILURE are both treated as EXCEPTION)
                if (transactionToComplete.getTransactionStatus() == TransactionStatus.UNKNOWN) {
                    throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_OPERATION, paymentStateContext.getTransactionType(), transactionToComplete.getTransactionStatus());
                }
                paymentStateContext.setPaymentTransactionModelDao(transactionToComplete);
            }
        }
        // Use the original payment method id of the payment being completed
        paymentStateContext.setPaymentMethodId(paymentModelDao.getPaymentMethodId());
        // We always take the last successful state name to permit retries on failures
        currentStateName = paymentModelDao.getLastSuccessStateName();
    }
    paymentAutomatonRunner.run(paymentStateContext, daoHelper, currentStateName, transactionType);
    return paymentRefresher.getPayment(paymentStateContext.getPaymentModelDao(), true, false, isApiPayment, properties, callContext, internalCallContext);
}
Also used : PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) LinkedList(java.util.LinkedList) Predicate(com.google.common.base.Predicate) PaymentPluginApi(org.killbill.billing.payment.plugin.api.PaymentPluginApi) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentAutomatonDAOHelper(org.killbill.billing.payment.core.sm.PaymentAutomatonDAOHelper) PaymentStateContext(org.killbill.billing.payment.core.sm.PaymentStateContext) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) UUID(java.util.UUID)

Aggregations

Predicate (com.google.common.base.Predicate)2 LinkedList (java.util.LinkedList)2 UUID (java.util.UUID)2 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)2 PaymentAutomatonDAOHelper (org.killbill.billing.payment.core.sm.PaymentAutomatonDAOHelper)2 PaymentStateContext (org.killbill.billing.payment.core.sm.PaymentStateContext)2 PaymentModelDao (org.killbill.billing.payment.dao.PaymentModelDao)2 PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)2 PaymentPluginApi (org.killbill.billing.payment.plugin.api.PaymentPluginApi)2 PaymentTransactionInfoPlugin (org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin)2