Search in sources :

Example 21 with PaymentModelDao

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

the class PaymentAutomatonDAOHelper method createNewPaymentTransaction.

public void createNewPaymentTransaction() throws PaymentApiException {
    final PaymentTransactionModelDao paymentTransactionModelDao;
    final List<PaymentTransactionModelDao> existingTransactions;
    if (paymentStateContext.getPaymentId() == null) {
        final PaymentModelDao newPaymentModelDao = buildNewPaymentModelDao();
        final PaymentTransactionModelDao newPaymentTransactionModelDao = buildNewPaymentTransactionModelDao(newPaymentModelDao.getId());
        existingTransactions = ImmutableList.of();
        final PaymentAndTransactionModelDao paymentAndTransactionModelDao = paymentDao.insertPaymentWithFirstTransaction(newPaymentModelDao, newPaymentTransactionModelDao, internalCallContext);
        paymentTransactionModelDao = paymentAndTransactionModelDao.getPaymentTransactionModelDao();
    } else {
        existingTransactions = paymentDao.getTransactionsForPayment(paymentStateContext.getPaymentId(), internalCallContext);
        if (existingTransactions.isEmpty()) {
            throw new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_SUCCESS_PAYMENT, paymentStateContext.getPaymentId());
        }
        if (paymentStateContext.getCurrency() != null && existingTransactions.get(0).getCurrency() != paymentStateContext.getCurrency() && !TransactionType.CHARGEBACK.equals(paymentStateContext.getTransactionType())) {
            // Note that we allow chargebacks in a different currency
            throw new PaymentApiException(ErrorCode.PAYMENT_INVALID_PARAMETER, "currency", " should be " + existingTransactions.get(0).getCurrency() + " to match other existing transactions");
        }
        final PaymentTransactionModelDao newPaymentTransactionModelDao = buildNewPaymentTransactionModelDao(paymentStateContext.getPaymentId());
        paymentTransactionModelDao = paymentDao.updatePaymentWithNewTransaction(paymentStateContext.getPaymentId(), newPaymentTransactionModelDao, internalCallContext);
    }
    // Update the context
    paymentStateContext.setPaymentTransactionModelDao(paymentTransactionModelDao);
    paymentStateContext.setOnLeavingStateExistingTransactions(existingTransactions);
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentAndTransactionModelDao(org.killbill.billing.payment.dao.PaymentAndTransactionModelDao) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException)

Example 22 with PaymentModelDao

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

the class PaymentAutomatonDAOHelper method buildNewPaymentModelDao.

private PaymentModelDao buildNewPaymentModelDao() {
    final DateTime createdDate = utcNow;
    final DateTime updatedDate = utcNow;
    if (paymentStateContext.getPaymentIdForNewPayment() != null) {
        return new PaymentModelDao(paymentStateContext.getPaymentIdForNewPayment(), createdDate, updatedDate, paymentStateContext.getAccount().getId(), paymentStateContext.getPaymentMethodId(), paymentStateContext.getPaymentExternalKey());
    } else {
        return new PaymentModelDao(createdDate, updatedDate, paymentStateContext.getAccount().getId(), paymentStateContext.getPaymentMethodId(), paymentStateContext.getPaymentExternalKey());
    }
}
Also used : PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) DateTime(org.joda.time.DateTime)

Example 23 with PaymentModelDao

use of org.killbill.billing.payment.dao.PaymentModelDao 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)

Example 24 with PaymentModelDao

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

the class DefaultControlInitiated method leavingState.

@Override
public void leavingState(final State state) throws OperationException {
    final DateTime utcNow = pluginControlPaymentAutomatonRunner.getClock().getUTCNow();
    // Retrieve the associated payment transaction, if any
    PaymentTransactionModelDao paymentTransactionModelDaoCandidate = null;
    if (stateContext.getTransactionId() != null) {
        paymentTransactionModelDaoCandidate = paymentDao.getPaymentTransaction(stateContext.getTransactionId(), stateContext.getInternalCallContext());
        Preconditions.checkNotNull(paymentTransactionModelDaoCandidate, "paymentTransaction cannot be null for id " + stateContext.getTransactionId());
    } else if (stateContext.getPaymentTransactionExternalKey() != null) {
        final List<PaymentTransactionModelDao> paymentTransactionModelDaos = paymentDao.getPaymentTransactionsByExternalKey(stateContext.getPaymentTransactionExternalKey(), stateContext.getInternalCallContext());
        if (!paymentTransactionModelDaos.isEmpty()) {
            paymentTransactionModelDaoCandidate = paymentTransactionModelDaos.get(paymentTransactionModelDaos.size() - 1);
        }
    }
    final PaymentTransactionModelDao paymentTransactionModelDao = paymentTransactionModelDaoCandidate != null && TRANSIENT_TRANSACTION_STATUSES.contains(paymentTransactionModelDaoCandidate.getTransactionStatus()) ? paymentTransactionModelDaoCandidate : null;
    if (stateContext.getPaymentId() != null && stateContext.getPaymentExternalKey() == null) {
        final PaymentModelDao payment = paymentDao.getPayment(stateContext.getPaymentId(), stateContext.getInternalCallContext());
        Preconditions.checkNotNull(payment, "payment cannot be null for id " + stateContext.getPaymentId());
        stateContext.setPaymentExternalKey(payment.getExternalKey());
        stateContext.setPaymentMethodId(payment.getPaymentMethodId());
    } else if (stateContext.getPaymentExternalKey() == null) {
        final UUID paymentIdForNewPayment = UUIDs.randomUUID();
        stateContext.setPaymentIdForNewPayment(paymentIdForNewPayment);
        stateContext.setPaymentExternalKey(paymentIdForNewPayment.toString());
    }
    if (paymentTransactionModelDao != null) {
        stateContext.setPaymentTransactionModelDao(paymentTransactionModelDao);
        stateContext.setProcessedAmount(paymentTransactionModelDao.getProcessedAmount());
        stateContext.setProcessedCurrency(paymentTransactionModelDao.getProcessedCurrency());
    } else if (stateContext.getPaymentTransactionExternalKey() == null) {
        final UUID paymentTransactionIdForNewPaymentTransaction = UUIDs.randomUUID();
        stateContext.setPaymentTransactionIdForNewPaymentTransaction(paymentTransactionIdForNewPaymentTransaction);
        stateContext.setPaymentTransactionExternalKey(paymentTransactionIdForNewPaymentTransaction.toString());
    }
    // In this case, we also want to provide the associated plugin name
    if (stateContext.getPaymentMethodId() != null) {
        final PaymentMethodModelDao pm = paymentDao.getPaymentMethod(stateContext.getPaymentMethodId(), stateContext.getInternalCallContext());
        // Payment method was deleted
        if (pm != null) {
            stateContext.setOriginalPaymentPluginName(pm.getPluginName());
        }
    }
    if (state.getName().equals(initialState.getName()) || state.getName().equals(retriedState.getName())) {
        try {
            final PaymentAttemptModelDao attempt;
            if (paymentTransactionModelDao != null && paymentTransactionModelDao.getAttemptId() != null) {
                attempt = pluginControlPaymentAutomatonRunner.getPaymentDao().getPaymentAttempt(paymentTransactionModelDao.getAttemptId(), stateContext.getInternalCallContext());
                Preconditions.checkNotNull(attempt, "attempt cannot be null for id " + paymentTransactionModelDao.getAttemptId());
            } else {
                // 
                // We don't serialize any properties at this stage to avoid serializing sensitive information.
                // However, if after going through the control plugins, the attempt end up in RETRIED state,
                // the properties will be serialized in the enteringState callback (any plugin that sets a
                // retried date is responsible to correctly remove sensitive information such as CVV, ...)
                // 
                final byte[] serializedProperties = PluginPropertySerializer.serialize(ImmutableList.<PluginProperty>of());
                attempt = new PaymentAttemptModelDao(stateContext.getAccount().getId(), stateContext.getPaymentMethodId(), utcNow, utcNow, stateContext.getPaymentExternalKey(), stateContext.getTransactionId(), stateContext.getPaymentTransactionExternalKey(), transactionType, initialState.getName(), stateContext.getAmount(), stateContext.getCurrency(), stateContext.getPaymentControlPluginNames(), serializedProperties);
                pluginControlPaymentAutomatonRunner.getPaymentDao().insertPaymentAttemptWithProperties(attempt, stateContext.getInternalCallContext());
            }
            stateContext.setAttemptId(attempt.getId());
        } catch (final PluginPropertySerializerException e) {
            throw new OperationException(e);
        }
    }
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PluginPropertySerializerException(org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException) PaymentMethodModelDao(org.killbill.billing.payment.dao.PaymentMethodModelDao) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) UUID(java.util.UUID) DateTime(org.joda.time.DateTime) OperationException(org.killbill.automaton.OperationException)

Example 25 with PaymentModelDao

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

the class InvoicePaymentControlPluginApi method getPurchasedTransactions.

private List<PaymentTransactionModelDao> getPurchasedTransactions(final String paymentExternalKey, final InternalCallContext internalContext) {
    final PaymentModelDao payment = paymentDao.getPaymentByExternalKey(paymentExternalKey, internalContext);
    if (payment == null) {
        return Collections.emptyList();
    }
    final List<PaymentTransactionModelDao> transactions = paymentDao.getTransactionsForPayment(payment.getId(), internalContext);
    if (transactions == null || transactions.size() == 0) {
        return Collections.emptyList();
    }
    return ImmutableList.copyOf(Iterables.filter(transactions, new Predicate<PaymentTransactionModelDao>() {

        @Override
        public boolean apply(final PaymentTransactionModelDao input) {
            return input.getTransactionType() == TransactionType.PURCHASE;
        }
    }));
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) Predicate(com.google.common.base.Predicate)

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