Search in sources :

Example 46 with PaymentApiException

use of org.killbill.billing.payment.api.PaymentApiException in project killbill by killbill.

the class CompletionControlOperation method doOperationCallback.

@Override
public OperationResult doOperationCallback() throws OperationException {
    final List<String> controlPluginNameList = paymentStateControlContext.getPaymentControlPluginNames();
    final String controlPluginNames = JOINER.join(controlPluginNameList);
    return dispatchWithAccountLockAndTimeout(controlPluginNames, new DispatcherCallback<PluginDispatcherReturnType<OperationResult>, OperationException>() {

        @Override
        public PluginDispatcherReturnType<OperationResult> doOperation() throws OperationException {
            final PaymentTransactionModelDao transaction = paymentStateContext.getPaymentTransactionModelDao();
            final Account account = paymentStateContext.getAccount();
            final UUID accountId = account != null ? account.getId() : null;
            final PaymentControlContext updatedPaymentControlContext = new DefaultPaymentControlContext(accountId, paymentStateContext.getPaymentMethodId(), null, paymentStateControlContext.getAttemptId(), transaction.getPaymentId(), paymentStateContext.getPaymentExternalKey(), transaction.getId(), paymentStateContext.getPaymentTransactionExternalKey(), PaymentApiType.PAYMENT_TRANSACTION, paymentStateContext.getTransactionType(), null, transaction.getAmount(), transaction.getCurrency(), transaction.getProcessedAmount(), transaction.getProcessedCurrency(), paymentStateControlContext.isApiPayment(), paymentStateContext.getCallContext());
            try {
                final Payment result = doCallSpecificOperationCallback();
                logger.debug("doOperationCallback payment='{}', transaction='{}'", result, transaction);
                ((PaymentStateControlContext) paymentStateContext).setResult(result);
                final boolean success = transaction.getTransactionStatus() == TransactionStatus.SUCCESS || transaction.getTransactionStatus() == TransactionStatus.PENDING;
                if (success) {
                    executePluginOnSuccessCalls(paymentStateControlContext.getPaymentControlPluginNames(), updatedPaymentControlContext);
                    // Remove scheduled retry, if any
                    paymentProcessor.cancelScheduledPaymentTransaction(paymentStateControlContext.getAttemptId(), paymentStateControlContext.getInternalCallContext());
                    return PluginDispatcher.createPluginDispatcherReturnType(OperationResult.SUCCESS);
                } else {
                    throw new OperationException(null, executePluginOnFailureCallsAndSetRetryDate(updatedPaymentControlContext));
                }
            } catch (final PaymentApiException e) {
                // Wrap PaymentApiException, and throw a new OperationException with an ABORTED/FAILURE state based on the retry result.
                throw new OperationException(e, executePluginOnFailureCallsAndSetRetryDate(updatedPaymentControlContext));
            } catch (final RuntimeException e) {
                // Attempts to set the retry date in context if needed.
                throw new OperationException(e, executePluginOnFailureCallsAndSetRetryDate(updatedPaymentControlContext));
            }
        }
    });
}
Also used : PluginDispatcherReturnType(org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType) Account(org.killbill.billing.account.api.Account) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) Payment(org.killbill.billing.payment.api.Payment) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) DefaultPaymentControlContext(org.killbill.billing.payment.core.sm.control.ControlPluginRunner.DefaultPaymentControlContext) PaymentControlContext(org.killbill.billing.control.plugin.api.PaymentControlContext) DefaultPaymentControlContext(org.killbill.billing.payment.core.sm.control.ControlPluginRunner.DefaultPaymentControlContext) UUID(java.util.UUID) OperationException(org.killbill.automaton.OperationException)

Example 47 with PaymentApiException

use of org.killbill.billing.payment.api.PaymentApiException in project killbill by killbill.

the class PaymentGatewayProcessor method buildFormDescriptor.

public HostedPaymentPageFormDescriptor buildFormDescriptor(final boolean shouldDispatch, final Account account, final UUID paymentMethodId, final Iterable<PluginProperty> customFields, final Iterable<PluginProperty> properties, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
    final String pluginName = getPaymentMethodById(paymentMethodId, true, internalCallContext).getPluginName();
    final PaymentPluginApi plugin = getPaymentPluginApi(pluginName);
    if (shouldDispatch) {
        return dispatchWithExceptionHandling(account, pluginName, new Callable<PluginDispatcherReturnType<HostedPaymentPageFormDescriptor>>() {

            @Override
            public PluginDispatcherReturnType<HostedPaymentPageFormDescriptor> call() throws PaymentApiException {
                try {
                    final HostedPaymentPageFormDescriptor result = plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
                    return PluginDispatcher.createPluginDispatcherReturnType(result == null ? new DefaultNoOpHostedPaymentPageFormDescriptor(account.getId()) : result);
                } catch (final RuntimeException e) {
                    throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, MoreObjects.firstNonNull(e.getMessage(), ""));
                } catch (final PaymentPluginApiException e) {
                    throw new PaymentApiException(e, ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
                }
            }
        }, paymentPluginFormDispatcher);
    } else {
        try {
            return plugin.buildFormDescriptor(account.getId(), customFields, properties, callContext);
        } catch (final PaymentPluginApiException e) {
            throw new PaymentApiException(e, ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getErrorMessage());
        }
    }
}
Also used : PaymentPluginApi(org.killbill.billing.payment.plugin.api.PaymentPluginApi) PluginDispatcherReturnType(org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType) DefaultNoOpHostedPaymentPageFormDescriptor(org.killbill.billing.payment.provider.DefaultNoOpHostedPaymentPageFormDescriptor) HostedPaymentPageFormDescriptor(org.killbill.billing.payment.plugin.api.HostedPaymentPageFormDescriptor) DefaultNoOpHostedPaymentPageFormDescriptor(org.killbill.billing.payment.provider.DefaultNoOpHostedPaymentPageFormDescriptor) PaymentPluginApiException(org.killbill.billing.payment.plugin.api.PaymentPluginApiException) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException)

Example 48 with PaymentApiException

use of org.killbill.billing.payment.api.PaymentApiException in project killbill by killbill.

the class PaymentBusEventHandler method processInvoiceEvent.

@AllowConcurrentEvents
@Subscribe
public void processInvoiceEvent(final InvoiceCreationInternalEvent event) {
    if (busDispatcherOptimizer.shouldDispatch(event)) {
        log.info("Received invoice creation notification for accountId='{}', invoiceId='{}'", event.getAccountId(), event.getInvoiceId());
        final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
        // We let the plugin compute how much should be paid
        final BigDecimal amountToBePaid = null;
        final List<String> paymentControlPluginNames = paymentConfig.getPaymentControlPluginNames(internalContext) != null ? new LinkedList<String>(paymentConfig.getPaymentControlPluginNames(internalContext)) : new LinkedList<String>();
        final Account account;
        try {
            account = accountApi.getAccountById(event.getAccountId(), internalContext);
            invoicePaymentInternalApi.createPurchaseForInvoicePayment(false, account, event.getInvoiceId(), account.getPaymentMethodId(), null, amountToBePaid, account.getCurrency(), null, null, null, ImmutableList.<PluginProperty>of(), new PaymentOptions() {

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

                @Override
                public List<String> getPaymentControlPluginNames() {
                    return paymentControlPluginNames;
                }
            }, internalContext);
        } catch (final AccountApiException e) {
            log.warn("Failed to process invoice payment", e);
        } catch (final PaymentApiException e) {
            // Log as warn unless nothing left to be paid
            if (e.getCode() != ErrorCode.PAYMENT_PLUGIN_API_ABORTED.getCode()) {
                log.warn("Failed to process invoice payment", e);
            }
        }
    }
}
Also used : Account(org.killbill.billing.account.api.Account) AccountApiException(org.killbill.billing.account.api.AccountApiException) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) List(java.util.List) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) PaymentOptions(org.killbill.billing.payment.api.PaymentOptions) BigDecimal(java.math.BigDecimal) AllowConcurrentEvents(com.google.common.eventbus.AllowConcurrentEvents) Subscribe(com.google.common.eventbus.Subscribe)

Example 49 with PaymentApiException

use of org.killbill.billing.payment.api.PaymentApiException in project killbill by killbill.

the class ChargebackInitiated method leavingState.

@Override
public void leavingState(final State oldState) throws OperationException {
    // Sanity: chargeback reversals can only happen after a successful chargeback
    if (OperationResult.FAILURE.equals(paymentStateContext.getOverridePluginOperationResult())) {
        final List<PaymentTransactionModelDao> paymentTransactionsForCurrentPayment = paymentStateContext.getPaymentId() != null ? daoHelper.getPaymentDao().getTransactionsForPayment(paymentStateContext.getPaymentId(), paymentStateContext.getInternalCallContext()) : ImmutableList.<PaymentTransactionModelDao>of();
        final Iterable<PaymentTransactionModelDao> existingPaymentTransactionsForTransactionIdOrKey = filterExistingPaymentTransactionsForTransactionIdOrKey(paymentTransactionsForCurrentPayment, paymentStateContext.getTransactionId(), paymentStateContext.getPaymentTransactionExternalKey());
        if (Iterables.isEmpty(existingPaymentTransactionsForTransactionIdOrKey)) {
            // Chargeback reversals can only happen after a successful chargeback
            throw new OperationException(new PaymentApiException(ErrorCode.PAYMENT_NO_SUCH_SUCCESS_PAYMENT, paymentStateContext.getPaymentId()));
        }
    }
    super.leavingState(oldState);
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) OperationException(org.killbill.automaton.OperationException)

Example 50 with PaymentApiException

use of org.killbill.billing.payment.api.PaymentApiException in project killbill by killbill.

the class PaymentPluginDispatcher method dispatchWithExceptionHandling.

public static <ReturnType> ReturnType dispatchWithExceptionHandling(@Nullable final Account account, final String pluginNames, final Callable<PluginDispatcherReturnType<ReturnType>> callable, final PluginDispatcher<ReturnType> pluginDispatcher) throws PaymentApiException {
    final UUID accountId = account != null ? account.getId() : null;
    final String accountExternalKey = account != null ? account.getExternalKey() : "";
    try {
        log.debug("Calling plugin(s) {}", pluginNames);
        final ReturnType result = pluginDispatcher.dispatchWithTimeout(callable);
        log.debug("Successful plugin(s) call of {} for account {} with result {}", pluginNames, accountExternalKey, result);
        return result;
    } catch (final TimeoutException e) {
        final String errorMessage = String.format("Call TIMEOUT for accountId='%s' accountExternalKey='%s' plugin='%s'", accountId, accountExternalKey, pluginNames);
        log.warn(errorMessage);
        throw new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_TIMEOUT, accountId, errorMessage);
    } catch (final InterruptedException e) {
        Thread.currentThread().interrupt();
        final String errorMessage = String.format("Call was interrupted for accountId='%s' accountExternalKey='%s' plugin='%s'", accountId, accountExternalKey, pluginNames);
        log.warn(errorMessage, e);
        throw new PaymentApiException(ErrorCode.PAYMENT_INTERNAL_ERROR, MoreObjects.firstNonNull(e.getMessage(), errorMessage));
    } catch (final ExecutionException e) {
        if (e.getCause() instanceof PaymentApiException) {
            throw (PaymentApiException) e.getCause();
        } else if (e.getCause() instanceof LockFailedException) {
            final String format = String.format("Failed to lock accountExternalKey='%s'", accountExternalKey);
            log.warn(format);
            throw new PaymentApiException(ErrorCode.PAYMENT_INTERNAL_ERROR, format);
        } else {
            // Unwraps the ExecutionException (e.getCause()), since it's a dispatch implementation detail
            throw new PaymentApiException(e.getCause(), ErrorCode.PAYMENT_INTERNAL_ERROR, MoreObjects.firstNonNull(e.getMessage(), ""));
        }
    }
}
Also used : LockFailedException(org.killbill.commons.locker.LockFailedException) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) UUID(java.util.UUID) PluginDispatcherReturnType(org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException)

Aggregations

PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)57 UUID (java.util.UUID)20 Test (org.testng.annotations.Test)19 PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)14 Account (org.killbill.billing.account.api.Account)12 Payment (org.killbill.billing.payment.api.Payment)12 PaymentAttemptModelDao (org.killbill.billing.payment.dao.PaymentAttemptModelDao)11 BigDecimal (java.math.BigDecimal)10 OperationException (org.killbill.automaton.OperationException)10 PaymentModelDao (org.killbill.billing.payment.dao.PaymentModelDao)9 Predicate (com.google.common.base.Predicate)7 PaymentControlApiException (org.killbill.billing.control.plugin.api.PaymentControlApiException)7 PluginDispatcherReturnType (org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType)7 PaymentPluginApi (org.killbill.billing.payment.plugin.api.PaymentPluginApi)7 LinkedList (java.util.LinkedList)6 AccountApiException (org.killbill.billing.account.api.AccountApiException)6 Invoice (org.killbill.billing.invoice.api.Invoice)6 PluginProperty (org.killbill.billing.payment.api.PluginProperty)6 PaymentPluginApiException (org.killbill.billing.payment.plugin.api.PaymentPluginApiException)6 DateTime (org.joda.time.DateTime)5