Search in sources :

Example 56 with InternalCallContext

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);
    }
}
Also used : InternalCallContext(org.killbill.billing.callcontext.InternalCallContext)

Example 57 with InternalCallContext

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);
    }
}
Also used : Account(org.killbill.billing.account.api.Account) ArrayList(java.util.ArrayList) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) BigDecimal(java.math.BigDecimal) PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) PluginProperty(org.killbill.billing.payment.api.PluginProperty) Payment(org.killbill.billing.payment.api.Payment) AccountApiException(org.killbill.billing.account.api.AccountApiException) AllowConcurrentEvents(com.google.common.eventbus.AllowConcurrentEvents) Subscribe(com.google.common.eventbus.Subscribe)

Example 58 with InternalCallContext

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);
}
Also used : InputStreamReader(java.io.InputStreamReader) InputStream(java.io.InputStream) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) URI(java.net.URI) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) InvocationOnMock(org.mockito.invocation.InvocationOnMock) OverdueConfig(org.killbill.billing.overdue.api.OverdueConfig) Test(org.testng.annotations.Test)

Example 59 with InternalCallContext

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);
    }
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) Predicate(com.google.common.base.Predicate)

Example 60 with InternalCallContext

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);
    }
}
Also used : InternalCallContext(org.killbill.billing.callcontext.InternalCallContext)

Aggregations

InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)110 PlanPhasePriceOverride (org.killbill.billing.catalog.api.PlanPhasePriceOverride)26 DateTime (org.joda.time.DateTime)25 UUID (java.util.UUID)24 ArrayList (java.util.ArrayList)21 SubscriptionBaseApiException (org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)17 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)14 CallContext (org.killbill.billing.util.callcontext.CallContext)14 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)13 WithEntitlementPlugin (org.killbill.billing.entitlement.api.EntitlementPluginExecution.WithEntitlementPlugin)13 EntitlementContext (org.killbill.billing.entitlement.plugin.api.EntitlementContext)13 AccountApiException (org.killbill.billing.account.api.AccountApiException)12 DefaultBlockingState (org.killbill.billing.junction.DefaultBlockingState)12 NotificationEvent (org.killbill.notificationq.api.NotificationEvent)9 BigDecimal (java.math.BigDecimal)8 LinkedList (java.util.LinkedList)8 InternalTenantContext (org.killbill.billing.callcontext.InternalTenantContext)8 Invoice (org.killbill.billing.invoice.api.Invoice)8 AllowConcurrentEvents (com.google.common.eventbus.AllowConcurrentEvents)7 Subscribe (com.google.common.eventbus.Subscribe)7