use of org.killbill.billing.control.plugin.api.PaymentControlContext in project killbill by killbill.
the class ControlPluginRunner method executePluginPriorCalls.
public PriorPaymentControlResult executePluginPriorCalls(final Account account, final UUID paymentMethodId, final String pluginName, final UUID paymentAttemptId, final UUID paymentId, final String paymentExternalKey, final UUID paymentTransactionId, final String paymentTransactionExternalKey, final PaymentApiType paymentApiType, final TransactionType transactionType, final HPPType hppType, final BigDecimal amount, final Currency currency, final BigDecimal processedAmount, final Currency processedCurrency, final boolean isApiPayment, final List<String> paymentControlPluginNames, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) throws PaymentControlApiException {
// Return as soon as the first plugin aborts, or the last result for the last plugin
PriorPaymentControlResult prevResult = new DefaultPriorPaymentControlResult(false, amount, currency, paymentMethodId, null, pluginProperties);
// Those values are adjusted prior each call with the result of what previous call to plugin returned
UUID inputPaymentMethodId = paymentMethodId;
String inputPaymentMethodName = pluginName;
BigDecimal inputAmount = amount;
Currency inputCurrency = currency;
Iterable<PluginProperty> inputPluginProperties = pluginProperties;
final UUID accountId = account != null ? account.getId() : null;
for (final String controlPluginName : paymentControlPluginNames) {
final PaymentControlContext inputPaymentControlContext = new DefaultPaymentControlContext(accountId, inputPaymentMethodId, controlPluginName, paymentAttemptId, paymentId, paymentExternalKey, paymentTransactionId, paymentTransactionExternalKey, paymentApiType, transactionType, hppType, inputAmount, inputCurrency, processedAmount, processedCurrency, isApiPayment, callContext);
final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(controlPluginName);
if (plugin == null) {
// First call to plugin, we log warn, if plugin is not registered
log.warn("Skipping unknown payment control plugin {} when fetching results", controlPluginName);
continue;
}
log.debug("Calling priorCall of plugin {}", controlPluginName);
prevResult = plugin.priorCall(inputPaymentControlContext, inputPluginProperties);
log.debug("Successful executed priorCall of plugin {}", controlPluginName);
if (prevResult == null) {
// Nothing returned by the plugin
continue;
}
if (prevResult.getAdjustedPaymentMethodId() != null) {
// unless the property isAllowedToOverwritePaymentMethodId was explicitly configured to allow this
if (!paymentConfig.isAllowedToOverwritePaymentMethodId() && paymentMethodId != null) {
throw new PaymentControlApiException(String.format("Not allowed to overwrite paymentMethodId '%s' for payment '%s'", paymentMethodId, paymentId));
}
inputPaymentMethodId = prevResult.getAdjustedPaymentMethodId();
}
if (prevResult.getAdjustedPluginName() != null) {
inputPaymentMethodName = prevResult.getAdjustedPluginName();
}
if (prevResult.getAdjustedAmount() != null) {
inputAmount = prevResult.getAdjustedAmount();
}
if (prevResult.getAdjustedCurrency() != null) {
inputCurrency = prevResult.getAdjustedCurrency();
}
if (prevResult.getAdjustedPluginProperties() != null) {
inputPluginProperties = prevResult.getAdjustedPluginProperties();
}
if (prevResult.isAborted()) {
throw new PaymentControlApiAbortException(controlPluginName);
}
}
// Rebuild latest result to include inputPluginProperties
prevResult = new DefaultPriorPaymentControlResult(prevResult != null && prevResult.isAborted(), inputPaymentMethodId, inputPaymentMethodName, inputAmount, inputCurrency, inputPluginProperties);
return prevResult;
}
use of org.killbill.billing.control.plugin.api.PaymentControlContext in project killbill by killbill.
the class ControlPluginRunner method executePluginOnFailureCalls.
public OnFailurePaymentControlResult executePluginOnFailureCalls(final Account account, final UUID paymentMethodId, final String pluginName, final UUID paymentAttemptId, final UUID paymentId, final String paymentExternalKey, final UUID transactionId, final String paymentTransactionExternalKey, final PaymentApiType paymentApiType, final TransactionType transactionType, final HPPType hppType, final BigDecimal amount, final Currency currency, final BigDecimal processedAmount, final Currency processedCurrency, final boolean isApiPayment, final List<String> paymentControlPluginNames, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) {
final UUID accountId = account != null ? account.getId() : null;
final PaymentControlContext inputPaymentControlContext = new DefaultPaymentControlContext(accountId, paymentMethodId, pluginName, paymentAttemptId, paymentId, paymentExternalKey, transactionId, paymentTransactionExternalKey, paymentApiType, transactionType, hppType, amount, currency, processedAmount, processedCurrency, isApiPayment, callContext);
DateTime candidate = null;
Iterable<PluginProperty> inputPluginProperties = pluginProperties;
for (final String controlPluginName : paymentControlPluginNames) {
final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(controlPluginName);
if (plugin != null) {
try {
log.debug("Calling onSuccessCall of plugin {}", controlPluginName);
final OnFailurePaymentControlResult result = plugin.onFailureCall(inputPaymentControlContext, inputPluginProperties);
log.debug("Successful executed onSuccessCall of plugin {}", controlPluginName);
if (result == null) {
// Nothing returned by the plugin
continue;
}
if (candidate == null) {
candidate = result.getNextRetryDate();
} else if (result.getNextRetryDate() != null) {
candidate = candidate.compareTo(result.getNextRetryDate()) > 0 ? result.getNextRetryDate() : candidate;
}
if (result.getAdjustedPluginProperties() != null) {
inputPluginProperties = result.getAdjustedPluginProperties();
}
} catch (final PaymentControlApiException e) {
log.warn("Error during onFailureCall for plugin='{}', paymentExternalKey='{}'", controlPluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
return new DefaultFailureCallResult(candidate, inputPluginProperties);
}
}
}
return new DefaultFailureCallResult(candidate, inputPluginProperties);
}
use of org.killbill.billing.control.plugin.api.PaymentControlContext in project killbill by killbill.
the class OperationControlCallback method doOperationCallback.
@Override
public OperationResult doOperationCallback() throws OperationException {
final List<String> pluginNameList = paymentStateControlContext.getPaymentControlPluginNames();
final String pluginNames = JOINER.join(pluginNameList);
return dispatchWithAccountLockAndTimeout(pluginNames, new DispatcherCallback<PluginDispatcherReturnType<OperationResult>, OperationException>() {
@Override
public PluginDispatcherReturnType<OperationResult> doOperation() throws OperationException {
final Account account = paymentStateContext.getAccount();
final UUID accountId = account != null ? account.getId() : null;
final PaymentControlContext paymentControlContext = new DefaultPaymentControlContext(accountId, paymentStateContext.getPaymentMethodId(), paymentStateControlContext.getOriginalPaymentPluginName(), paymentStateControlContext.getAttemptId(), paymentStateContext.getPaymentId(), paymentStateContext.getPaymentExternalKey(), paymentStateContext.getTransactionId(), paymentStateContext.getPaymentTransactionExternalKey(), PaymentApiType.PAYMENT_TRANSACTION, paymentStateContext.getTransactionType(), null, paymentStateContext.getAmount(), paymentStateContext.getCurrency(), paymentStateControlContext.getProcessedAmount(), paymentStateControlContext.getProcessedCurrency(), paymentStateControlContext.isApiPayment(), paymentStateContext.getCallContext());
try {
executePluginPriorCalls(paymentStateControlContext.getPaymentControlPluginNames(), paymentControlContext);
} catch (final PaymentControlApiAbortException e) {
// Transition to ABORTED
final PaymentApiException paymentAbortedException = new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_API_ABORTED, e.getPluginName());
throw new OperationException(paymentAbortedException, OperationResult.EXCEPTION);
} catch (final PaymentControlApiException e) {
// Transition to ABORTED and throw PaymentControlApiException to caller.
throw new OperationException(e, OperationResult.EXCEPTION);
}
final boolean success;
try {
final Payment result = doCallSpecificOperationCallback();
((PaymentStateControlContext) paymentStateContext).setResult(result);
final PaymentTransaction transaction = ((PaymentStateControlContext) paymentStateContext).getCurrentTransaction();
success = transaction.getTransactionStatus() == TransactionStatus.SUCCESS || transaction.getTransactionStatus() == TransactionStatus.PENDING;
final PaymentControlContext updatedPaymentControlContext = new DefaultPaymentControlContext(accountId, paymentStateContext.getPaymentMethodId(), null, paymentStateControlContext.getAttemptId(), result.getId(), result.getExternalKey(), transaction.getId(), paymentStateContext.getPaymentTransactionExternalKey(), PaymentApiType.PAYMENT_TRANSACTION, paymentStateContext.getTransactionType(), null, transaction.getAmount(), transaction.getCurrency(), transaction.getProcessedAmount(), transaction.getProcessedCurrency(), paymentStateControlContext.isApiPayment(), paymentStateContext.getCallContext());
if (success) {
executePluginOnSuccessCalls(paymentStateControlContext.getPaymentControlPluginNames(), updatedPaymentControlContext);
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(paymentControlContext));
} catch (final RuntimeException e) {
// Attempts to set the retry date in context if needed.
throw new OperationException(e, executePluginOnFailureCallsAndSetRetryDate(paymentControlContext));
}
}
});
}
use of org.killbill.billing.control.plugin.api.PaymentControlContext 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.control.plugin.api.PaymentControlContext in project killbill by killbill.
the class ControlPluginRunner method executePluginOnSuccessCalls.
public OnSuccessPaymentControlResult executePluginOnSuccessCalls(final Account account, final UUID paymentMethodId, final String pluginName, final UUID paymentAttemptId, final UUID paymentId, final String paymentExternalKey, final UUID paymentTransactionId, final String paymentTransactionExternalKey, final PaymentApiType paymentApiType, final TransactionType transactionType, final HPPType hppType, final BigDecimal amount, final Currency currency, final BigDecimal processedAmount, final Currency processedCurrency, final boolean isApiPayment, final List<String> paymentControlPluginNames, final Iterable<PluginProperty> pluginProperties, final CallContext callContext) {
final UUID accountId = account != null ? account.getId() : null;
final PaymentControlContext inputPaymentControlContext = new DefaultPaymentControlContext(accountId, paymentMethodId, pluginName, paymentAttemptId, paymentId, paymentExternalKey, paymentTransactionId, paymentTransactionExternalKey, paymentApiType, transactionType, hppType, amount, currency, processedAmount, processedCurrency, isApiPayment, callContext);
Iterable<PluginProperty> inputPluginProperties = pluginProperties;
for (final String controlPluginName : paymentControlPluginNames) {
final PaymentControlPluginApi plugin = paymentControlPluginRegistry.getServiceForName(controlPluginName);
if (plugin != null) {
try {
log.debug("Calling onSuccessCall of plugin {}", controlPluginName);
final OnSuccessPaymentControlResult result = plugin.onSuccessCall(inputPaymentControlContext, inputPluginProperties);
log.debug("Successful executed onSuccessCall of plugin {}", controlPluginName);
if (result == null) {
// Nothing returned by the plugin
continue;
}
if (result.getAdjustedPluginProperties() != null) {
inputPluginProperties = result.getAdjustedPluginProperties();
}
// Exceptions from the control plugins are ignored (and logged) because the semantics on what to do are undefined.
} catch (final PaymentControlApiException e) {
log.warn("Error during onSuccessCall for plugin='{}', paymentExternalKey='{}'", controlPluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
} catch (final RuntimeException e) {
log.warn("Error during onSuccessCall for plugin='{}', paymentExternalKey='{}'", controlPluginName, inputPaymentControlContext.getPaymentExternalKey(), e);
}
}
}
return new DefaultOnSuccessPaymentControlResult(inputPluginProperties);
}
Aggregations