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));
}
}
});
}
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());
}
}
}
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);
}
}
}
}
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);
}
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(), ""));
}
}
}
Aggregations