use of org.killbill.billing.callcontext.InternalCallContext in project killbill by killbill.
the class DefaultPaymentApi method createPurchase.
@Override
public Payment createPurchase(final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency, @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey, final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
checkNotNullParameter(account, "account");
checkNotNullParameter(paymentMethodId, "paymentMethodId");
if (paymentId == null) {
checkNotNullParameter(amount, "amount");
checkNotNullParameter(currency, "currency");
}
checkNotNullParameter(properties, "plugin properties");
checkExternalKeyLength(paymentTransactionExternalKey);
final String transactionType = TransactionType.PURCHASE.name();
Payment payment = null;
PaymentTransaction paymentTransaction = null;
PaymentApiException exception = null;
try {
logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
payment = paymentProcessor.createPurchase(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null, SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
return payment;
} catch (PaymentApiException e) {
exception = e;
throw e;
} finally {
logExitAPICall(log, transactionType, account, payment != null ? payment.getPaymentMethodId() : null, payment != null ? payment.getId() : null, paymentTransaction != null ? paymentTransaction.getId() : null, paymentTransaction != null ? paymentTransaction.getProcessedAmount() : null, paymentTransaction != null ? paymentTransaction.getProcessedCurrency() : null, payment != null ? payment.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null, null, exception);
}
}
use of org.killbill.billing.callcontext.InternalCallContext in project killbill by killbill.
the class PaymentBusEventHandler method processInvoiceEvent.
@AllowConcurrentEvents
@Subscribe
public void processInvoiceEvent(final InvoiceCreationInternalEvent event) {
log.info("Received invoice creation notification for accountId='{}', invoiceId='{}'", event.getAccountId(), event.getInvoiceId());
final Collection<PluginProperty> properties = new ArrayList<PluginProperty>();
final PluginProperty propertyInvoiceId = new PluginProperty(InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID, event.getInvoiceId().toString(), false);
properties.add(propertyInvoiceId);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(event.getSearchKey2(), event.getSearchKey1(), "PaymentRequestProcessor", CallOrigin.INTERNAL, UserType.SYSTEM, event.getUserToken());
final CallContext callContext = internalCallContextFactory.createCallContext(internalContext);
// 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>();
paymentControlPluginNames.add(InvoicePaymentControlPluginApi.PLUGIN_NAME);
final String transactionType = TransactionType.PURCHASE.name();
Account account = null;
Payment payment = null;
PaymentTransaction paymentTransaction = null;
try {
account = accountApi.getAccountById(event.getAccountId(), internalContext);
logEnterAPICall(log, transactionType, account, account.getPaymentMethodId(), null, null, amountToBePaid, account.getCurrency(), null, null, null, paymentControlPluginNames);
payment = pluginControlPaymentProcessor.createPurchase(false, account, account.getPaymentMethodId(), null, amountToBePaid, account.getCurrency(), null, null, properties, paymentControlPluginNames, callContext, internalContext);
paymentTransaction = payment.getTransactions().get(payment.getTransactions().size() - 1);
} 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.toString());
}
} finally {
logExitAPICall(log, transactionType, account, payment != null ? payment.getPaymentMethodId() : null, payment != null ? payment.getId() : null, paymentTransaction != null ? paymentTransaction.getId() : null, paymentTransaction != null ? paymentTransaction.getProcessedAmount() : null, paymentTransaction != null ? paymentTransaction.getProcessedCurrency() : null, payment != null ? payment.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null, paymentControlPluginNames, null);
}
}
use of org.killbill.billing.callcontext.InternalCallContext in project killbill by killbill.
the class TestEhCacheOverdueConfigCache method testExistingTenantOverdue.
//
// Verify OverdueConfigCache returns per tenant overdue config:
// 1. We first mock TenantInternalApi to return a different overdue config than the default one
// 2. We then mock TenantInternalApi to throw RuntimeException which means overdue config was cached and there was no additional call
// to the TenantInternalApi api (otherwise test would fail with RuntimeException)
//
@Test(groups = "fast")
public void testExistingTenantOverdue() throws OverdueApiException, URISyntaxException, IOException {
final InternalCallContext differentMultiTenantContext = Mockito.mock(InternalCallContext.class);
Mockito.when(differentMultiTenantContext.getTenantRecordId()).thenReturn(55667788L);
final AtomicBoolean shouldThrow = new AtomicBoolean(false);
final Long multiTenantRecordId = multiTenantContext.getTenantRecordId();
final Long otherMultiTenantRecordId = otherMultiTenantContext.getTenantRecordId();
final InputStream tenantInputOverdueConfig = UriAccessor.accessUri(new URI(Resources.getResource("OverdueConfig2.xml").toExternalForm()));
final String tenantOverdueConfigXML = CharStreams.toString(new InputStreamReader(tenantInputOverdueConfig, "UTF-8"));
final InputStream otherTenantInputOverdueConfig = UriAccessor.accessUri(new URI(Resources.getResource("OverdueConfig.xml").toExternalForm()));
final String otherTenantOverdueConfigXML = CharStreams.toString(new InputStreamReader(otherTenantInputOverdueConfig, "UTF-8"));
Mockito.when(tenantInternalApi.getTenantOverdueConfig(Mockito.any(InternalTenantContext.class))).thenAnswer(new Answer<String>() {
@Override
public String answer(final InvocationOnMock invocation) throws Throwable {
if (shouldThrow.get()) {
throw new RuntimeException();
}
final InternalTenantContext internalContext = (InternalTenantContext) invocation.getArguments()[0];
if (multiTenantRecordId.equals(internalContext.getTenantRecordId())) {
return tenantOverdueConfigXML;
} else if (otherMultiTenantRecordId.equals(internalContext.getTenantRecordId())) {
return otherTenantOverdueConfigXML;
} else {
return null;
}
}
});
// Verify the lookup for a non-cached tenant. No system config is set yet but EhCacheOverdueConfigCache returns a default no-op one
OverdueConfig differentResult = overdueConfigCache.getOverdueConfig(differentMultiTenantContext);
Assert.assertNotNull(differentResult);
Assert.assertEquals(differentResult.getOverdueStatesAccount().getStates().length, 1);
Assert.assertTrue(differentResult.getOverdueStatesAccount().getStates()[0].isClearState());
// Make sure the cache loader isn't invoked, see https://github.com/killbill/killbill/issues/298
shouldThrow.set(true);
differentResult = overdueConfigCache.getOverdueConfig(differentMultiTenantContext);
Assert.assertNotNull(differentResult);
Assert.assertEquals(differentResult.getOverdueStatesAccount().getStates().length, 1);
Assert.assertTrue(differentResult.getOverdueStatesAccount().getStates()[0].isClearState());
shouldThrow.set(false);
// Set a default config
overdueConfigCache.loadDefaultOverdueConfig(Resources.getResource("OverdueConfig.xml").toExternalForm());
// Verify the lookup for this tenant
final OverdueConfig result = overdueConfigCache.getOverdueConfig(multiTenantContext);
Assert.assertNotNull(result);
Assert.assertEquals(result.getOverdueStatesAccount().getStates().length, 1);
Assert.assertFalse(result.getOverdueStatesAccount().getStates()[0].isClearState());
// Verify the lookup for another tenant
final OverdueConfig otherResult = overdueConfigCache.getOverdueConfig(otherMultiTenantContext);
Assert.assertNotNull(otherResult);
Assert.assertEquals(otherResult.getOverdueStatesAccount().getStates().length, 1);
Assert.assertTrue(otherResult.getOverdueStatesAccount().getStates()[0].isClearState());
shouldThrow.set(true);
// Verify the lookup for this tenant
final OverdueConfig result2 = overdueConfigCache.getOverdueConfig(multiTenantContext);
Assert.assertEquals(result2, result);
// Verify the lookup with another context for the same tenant
final InternalCallContext sameMultiTenantContext = Mockito.mock(InternalCallContext.class);
Mockito.when(sameMultiTenantContext.getAccountRecordId()).thenReturn(9102L);
Mockito.when(sameMultiTenantContext.getTenantRecordId()).thenReturn(multiTenantRecordId);
Assert.assertEquals(overdueConfigCache.getOverdueConfig(sameMultiTenantContext), result);
// Verify the lookup with the other tenant
Assert.assertEquals(overdueConfigCache.getOverdueConfig(otherMultiTenantContext), otherResult);
}
use of org.killbill.billing.callcontext.InternalCallContext in project killbill by killbill.
the class DefaultAdminPaymentApi method fixPaymentTransactionState.
@Override
public void fixPaymentTransactionState(final Payment payment, final PaymentTransaction paymentTransaction, @Nullable final TransactionStatus transactionStatusOrNull, @Nullable final String lastSuccessPaymentStateOrNull, @Nullable final String currentPaymentStateNameOrNull, final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(payment.getAccountId(), callContext);
TransactionStatus transactionStatus = transactionStatusOrNull;
if (transactionStatusOrNull == null) {
checkNotNullParameter(paymentTransaction.getPaymentInfoPlugin(), "PaymentTransactionInfoPlugin");
transactionStatus = PaymentTransactionInfoPluginConverter.toTransactionStatus(paymentTransaction.getPaymentInfoPlugin());
}
String currentPaymentStateName = currentPaymentStateNameOrNull;
if (currentPaymentStateName == null) {
switch(transactionStatus) {
case PENDING:
currentPaymentStateName = paymentSMHelper.getPendingStateForTransaction(paymentTransaction.getTransactionType());
break;
case SUCCESS:
currentPaymentStateName = paymentSMHelper.getSuccessfulStateForTransaction(paymentTransaction.getTransactionType());
break;
case PAYMENT_FAILURE:
currentPaymentStateName = paymentSMHelper.getFailureStateForTransaction(paymentTransaction.getTransactionType());
break;
case PLUGIN_FAILURE:
case UNKNOWN:
default:
currentPaymentStateName = paymentSMHelper.getErroredStateForTransaction(paymentTransaction.getTransactionType());
break;
}
}
String lastSuccessPaymentState = lastSuccessPaymentStateOrNull;
if (lastSuccessPaymentState == null && // Verify we are not updating an older transaction (only the last one has an impact on lastSuccessPaymentState)
paymentTransaction.getId().equals(payment.getTransactions().get(payment.getTransactions().size() - 1).getId())) {
if (paymentSMHelper.isSuccessState(currentPaymentStateName)) {
lastSuccessPaymentState = currentPaymentStateName;
} else {
for (int i = payment.getTransactions().size() - 2; i >= 0; i--) {
final PaymentTransaction transaction = payment.getTransactions().get(i);
if (TransactionStatus.SUCCESS.equals(transaction.getTransactionStatus())) {
lastSuccessPaymentState = paymentSMHelper.getSuccessfulStateForTransaction(transaction.getTransactionType());
break;
}
}
}
}
paymentDao.updatePaymentAndTransactionOnCompletion(payment.getAccountId(), null, payment.getId(), paymentTransaction.getTransactionType(), currentPaymentStateName, lastSuccessPaymentState, paymentTransaction.getId(), transactionStatus, paymentTransaction.getProcessedAmount(), paymentTransaction.getProcessedCurrency(), paymentTransaction.getGatewayErrorCode(), paymentTransaction.getGatewayErrorMsg(), internalCallContext);
// If there is a payment attempt associated with that transaction, we need to update it as well
final List<PaymentAttemptModelDao> paymentAttemptsModelDao = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransaction.getExternalKey(), internalCallContext);
final PaymentAttemptModelDao paymentAttemptModelDao = Iterables.<PaymentAttemptModelDao>tryFind(paymentAttemptsModelDao, new Predicate<PaymentAttemptModelDao>() {
@Override
public boolean apply(final PaymentAttemptModelDao input) {
return paymentTransaction.getId().equals(input.getTransactionId());
}
}).orNull();
if (paymentAttemptModelDao != null) {
// We can re-use the logic from IncompletePaymentAttemptTask as it is doing very similar work (i.e. run the completion part of
// the state machine to call the plugins and update the attempt in the right terminal state)
incompletePaymentAttemptTask.doIteration(paymentAttemptModelDao);
}
}
use of org.killbill.billing.callcontext.InternalCallContext in project killbill by killbill.
the class DefaultPaymentApi method createAuthorization.
@Override
public Payment createAuthorization(final Account account, final UUID paymentMethodId, @Nullable final UUID paymentId, final BigDecimal amount, final Currency currency, @Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey, final Iterable<PluginProperty> properties, final CallContext callContext) throws PaymentApiException {
checkNotNullParameter(account, "account");
checkNotNullParameter(paymentMethodId, "paymentMethodId");
if (paymentId == null) {
checkNotNullParameter(amount, "amount");
checkNotNullParameter(currency, "currency");
}
checkNotNullParameter(properties, "plugin properties");
checkExternalKeyLength(paymentExternalKey);
final String transactionType = TransactionType.AUTHORIZE.name();
Payment payment = null;
PaymentTransaction paymentTransaction = null;
PaymentApiException exception = null;
try {
logEnterAPICall(log, transactionType, account, paymentMethodId, paymentId, null, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null);
final InternalCallContext internalCallContext = internalCallContextFactory.createInternalCallContext(account.getId(), callContext);
payment = paymentProcessor.createAuthorization(IS_API_PAYMENT, NULL_ATTEMPT_ID, account, paymentMethodId, paymentId, amount, currency, paymentExternalKey, paymentTransactionExternalKey, null, null, SHOULD_LOCK_ACCOUNT, properties, callContext, internalCallContext);
paymentTransaction = findPaymentTransaction(payment, paymentTransactionExternalKey);
return payment;
} catch (PaymentApiException e) {
exception = e;
throw e;
} finally {
logExitAPICall(log, transactionType, account, payment != null ? payment.getPaymentMethodId() : null, payment != null ? payment.getId() : null, paymentTransaction != null ? paymentTransaction.getId() : null, paymentTransaction != null ? paymentTransaction.getProcessedAmount() : null, paymentTransaction != null ? paymentTransaction.getProcessedCurrency() : null, payment != null ? payment.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null, null, exception);
}
}
Aggregations