Search in sources :

Example 1 with CallContext

use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.

the class DefaultSubscriptionInternalApi method createBaseSubscriptionsWithAddOns.

@Override
public List<SubscriptionBaseWithAddOns> createBaseSubscriptionsWithAddOns(final UUID accountId, final Iterable<BaseEntitlementWithAddOnsSpecifier> baseEntitlementWithAddOnsSpecifier, final InternalCallContext context) throws SubscriptionBaseApiException {
    try {
        final Catalog catalog = catalogService.getFullCatalog(true, true, context);
        final CallContext callContext = internalCallContextFactory.createCallContext(context);
        final DateTime now = clock.getUTCNow();
        final Collection<SubscriptionAndAddOnsSpecifier> subscriptionAndAddOns = new ArrayList<SubscriptionAndAddOnsSpecifier>();
        for (final BaseEntitlementWithAddOnsSpecifier entitlementWithAddOnsSpecifier : baseEntitlementWithAddOnsSpecifier) {
            final DateTime effectiveDate = (entitlementWithAddOnsSpecifier.getBillingEffectiveDate() != null) ? DefaultClock.truncateMs(entitlementWithAddOnsSpecifier.getBillingEffectiveDate().toDateTimeAtStartOfDay()) : now;
            final SubscriptionBaseBundle bundle = createBundleForAccount(accountId, entitlementWithAddOnsSpecifier.getExternalKey(), context);
            final SubscriptionAndAddOnsSpecifier subscriptionAndAddOnsSpecifier = new SubscriptionAndAddOnsSpecifier(bundle.getId(), effectiveDate, verifyAndBuildSubscriptionSpecifiers(bundle.getId(), bundle.getExternalKey(), entitlementWithAddOnsSpecifier.getEntitlementSpecifier(), entitlementWithAddOnsSpecifier.isMigrated(), context, now, effectiveDate, catalog, callContext));
            subscriptionAndAddOns.add(subscriptionAndAddOnsSpecifier);
        }
        return apiService.createPlansWithAddOns(accountId, subscriptionAndAddOns, callContext);
    } catch (final CatalogApiException e) {
        throw new SubscriptionBaseApiException(e);
    }
}
Also used : CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) ArrayList(java.util.ArrayList) SubscriptionAndAddOnsSpecifier(org.killbill.billing.subscription.api.user.SubscriptionAndAddOnsSpecifier) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) BaseEntitlementWithAddOnsSpecifier(org.killbill.billing.entitlement.api.BaseEntitlementWithAddOnsSpecifier) PlanPhasePriceOverridesWithCallContext(org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) Catalog(org.killbill.billing.catalog.api.Catalog) DateTime(org.joda.time.DateTime) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride)

Example 2 with CallContext

use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.

the class DefaultSubscriptionInternalApi method getDryRunChangePlanEffectiveDate.

@Override
public DateTime getDryRunChangePlanEffectiveDate(final SubscriptionBase subscription, final PlanSpecifier spec, final DateTime requestedDateWithMs, final BillingActionPolicy requestedPolicy, final List<PlanPhasePriceOverride> overrides, final InternalCallContext context) throws SubscriptionBaseApiException, CatalogApiException {
    final TenantContext tenantContext = internalCallContextFactory.createTenantContext(context);
    final CallContext callContext = internalCallContextFactory.createCallContext(context);
    // verify the number of subscriptions (of the same kind) allowed per bundle
    final Catalog catalog = catalogService.getFullCatalog(true, true, context);
    final DateTime now = clock.getUTCNow();
    final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
    final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, callContext);
    final Plan plan = catalog.createOrFindPlan(spec, overridesWithContext, effectiveDate);
    if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
        if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0 && addonUtils.countExistingAddOnsWithSamePlanName(getSubscriptionsForBundle(subscription.getBundleId(), null, context), plan.getName()) >= plan.getPlansAllowedInBundle()) {
            // the plan can be changed to the new value, because it has reached its limit by bundle
            throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
        }
    }
    return apiService.dryRunChangePlan((DefaultSubscriptionBase) subscription, spec, requestedDateWithMs, requestedPolicy, tenantContext);
}
Also used : PlanPhasePriceOverridesWithCallContext(org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext) InternalTenantContext(org.killbill.billing.callcontext.InternalTenantContext) TenantContext(org.killbill.billing.util.callcontext.TenantContext) Plan(org.killbill.billing.catalog.api.Plan) PlanPhasePriceOverridesWithCallContext(org.killbill.billing.catalog.api.PlanPhasePriceOverridesWithCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) Catalog(org.killbill.billing.catalog.api.Catalog) DateTime(org.joda.time.DateTime) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride)

Example 3 with CallContext

use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.

the class DefaultSubscriptionBaseService method processEventReady.

@Override
public void processEventReady(final SubscriptionBaseEvent event, final int seqId, final InternalCallContext context) {
    if (!event.isActive()) {
        return;
    }
    try {
        final DefaultSubscriptionBase subscription = (DefaultSubscriptionBase) dao.getSubscriptionFromId(event.getSubscriptionId(), context);
        if (subscription == null) {
            log.warn("Error retrieving subscriptionId='{}'", event.getSubscriptionId());
            return;
        }
        final SubscriptionBaseTransitionData transition = subscription.getTransitionFromEvent(event, seqId);
        if (transition == null) {
            log.warn("Skipping event ='{}', no matching transition was built", event.getType());
            return;
        }
        boolean eventSent = false;
        if (event.getType() == EventType.PHASE) {
            eventSent = onPhaseEvent(subscription, event, context);
        } else if (event.getType() == EventType.API_USER && subscription.getCategory() == ProductCategory.BASE) {
            final CallContext callContext = internalCallContextFactory.createCallContext(context);
            eventSent = onBasePlanEvent(subscription, event, callContext);
        } else if (event.getType() == EventType.BCD_UPDATE) {
            eventSent = false;
        }
        if (!eventSent) {
            // Methods above invoking the DAO will send this event directly from the transaction
            final BusEvent busEvent = new DefaultEffectiveSubscriptionEvent(transition, subscription.getAlignStartDate(), context.getUserToken(), context.getAccountRecordId(), context.getTenantRecordId());
            eventBus.post(busEvent);
        }
    } catch (final EventBusException e) {
        log.warn("Failed to post event {}", event, e);
    } catch (final CatalogApiException e) {
        log.warn("Failed to post event {}", event, e);
    }
}
Also used : SubscriptionBaseTransitionData(org.killbill.billing.subscription.api.user.SubscriptionBaseTransitionData) DefaultEffectiveSubscriptionEvent(org.killbill.billing.subscription.api.user.DefaultEffectiveSubscriptionEvent) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) EventBusException(org.killbill.bus.api.PersistentBus.EventBusException) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) BusEvent(org.killbill.bus.api.BusEvent)

Example 4 with CallContext

use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.

the class TestDefaultInvoiceUserApi method testOriginalAmountCharged.

@Test(groups = "slow")
public void testOriginalAmountCharged() throws Exception {
    final Invoice initialInvoice = invoiceUserApi.getInvoice(invoiceId, callContext);
    final BigDecimal originalAmountCharged = initialInvoice.getOriginalChargedAmount();
    final BigDecimal amountCharged = initialInvoice.getChargedAmount();
    Assert.assertEquals(originalAmountCharged.compareTo(amountCharged), 0);
    ((ClockMock) clock).addDays(1);
    // Sleep at least one sec to make sure created_date for the external charge is different than the created date for the invoice itself
    CallContext newCallContextLater = new DefaultCallContext(callContext.getTenantId(), callContext.getUserName(), callContext.getCallOrigin(), callContext.getUserType(), callContext.getUserToken(), clock);
    // Post an external charge
    final BigDecimal externalChargeAmount = BigDecimal.TEN;
    final InvoiceItem externalCharge = new ExternalChargeInvoiceItem(invoiceId, accountId, null, UUID.randomUUID().toString(), clock.getUTCToday(), externalChargeAmount, accountCurrency);
    final InvoiceItem externalChargeInvoiceItem = invoiceUserApi.insertExternalCharges(accountId, clock.getUTCToday(), ImmutableList.<InvoiceItem>of(externalCharge), true, newCallContextLater).get(0);
    final Invoice newInvoice = invoiceUserApi.getInvoice(invoiceId, callContext);
    final BigDecimal newOriginalAmountCharged = newInvoice.getOriginalChargedAmount();
    final BigDecimal newAmountCharged = newInvoice.getChargedAmount();
    final BigDecimal expectedChargedAmount = newInvoice.getOriginalChargedAmount().add(externalChargeInvoiceItem.getAmount());
    Assert.assertEquals(originalAmountCharged.compareTo(newOriginalAmountCharged), 0);
    Assert.assertEquals(newAmountCharged.compareTo(expectedChargedAmount), 0);
}
Also used : Invoice(org.killbill.billing.invoice.api.Invoice) InvoiceItem(org.killbill.billing.invoice.api.InvoiceItem) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) DefaultCallContext(org.killbill.billing.callcontext.DefaultCallContext) ClockMock(org.killbill.clock.ClockMock) ExternalChargeInvoiceItem(org.killbill.billing.invoice.model.ExternalChargeInvoiceItem) CallContext(org.killbill.billing.util.callcontext.CallContext) DefaultCallContext(org.killbill.billing.callcontext.DefaultCallContext) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Example 5 with CallContext

use of org.killbill.billing.util.callcontext.CallContext in project killbill by killbill.

the class PluginControlPaymentProcessor method retryPaymentTransaction.

public void retryPaymentTransaction(final UUID attemptId, final List<String> paymentControlPluginNames, final InternalCallContext internalCallContext) {
    final PaymentAttemptModelDao attempt = paymentDao.getPaymentAttempt(attemptId, internalCallContext);
    log.info("Retrying attemptId='{}', paymentExternalKey='{}', transactionExternalKey='{}'. paymentControlPluginNames='{}'", attemptId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), paymentControlPluginNames);
    final PaymentModelDao paymentModelDao = paymentDao.getPaymentByExternalKey(attempt.getPaymentExternalKey(), internalCallContext);
    final UUID paymentId = paymentModelDao != null ? paymentModelDao.getId() : null;
    final CallContext callContext = buildCallContext(internalCallContext);
    final String transactionType = TransactionType.PURCHASE.name();
    Account account = null;
    Payment payment = null;
    PaymentTransaction paymentTransaction = null;
    try {
        account = accountInternalApi.getAccountById(attempt.getAccountId(), internalCallContext);
        final State state = paymentControlStateMachineHelper.getState(attempt.getStateName());
        final Iterable<PluginProperty> pluginProperties = PluginPropertySerializer.deserialize(attempt.getPluginProperties());
        logEnterAPICall(log, transactionType, account, attempt.getPaymentMethodId(), paymentId, null, attempt.getAmount(), attempt.getCurrency(), attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), null, paymentControlPluginNames);
        payment = pluginControlledPaymentAutomatonRunner.run(state, false, attempt.getTransactionType(), ControlOperation.valueOf(attempt.getTransactionType().toString()), account, attempt.getPaymentMethodId(), paymentId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), attempt.getAmount(), attempt.getCurrency(), pluginProperties, paymentControlPluginNames, callContext, internalCallContext);
        paymentTransaction = Iterables.<PaymentTransaction>find(Lists.<PaymentTransaction>reverse(payment.getTransactions()), new Predicate<PaymentTransaction>() {

            @Override
            public boolean apply(final PaymentTransaction input) {
                return attempt.getTransactionExternalKey().equals(input.getExternalKey());
            }
        });
    } catch (final AccountApiException e) {
        log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
    } catch (final PaymentApiException e) {
        // Log exception unless nothing left to be paid
        if (e.getCode() == ErrorCode.PAYMENT_PLUGIN_API_ABORTED.getCode() && paymentControlPluginNames != null && paymentControlPluginNames.size() == 1 && InvoicePaymentControlPluginApi.PLUGIN_NAME.equals(paymentControlPluginNames.get(0))) {
            log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'. Invoice has already been paid", attemptId, toPluginNamesOnError(paymentControlPluginNames));
        } else {
            log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
        }
    } catch (final PluginPropertySerializerException e) {
        log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
    } catch (final MissingEntryException e) {
        log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), 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, paymentControlPluginNames, null);
    }
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) Account(org.killbill.billing.account.api.Account) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PluginPropertySerializerException(org.killbill.billing.payment.dao.PluginPropertySerializer.PluginPropertySerializerException) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) CallContext(org.killbill.billing.util.callcontext.CallContext) Predicate(com.google.common.base.Predicate) PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) PluginProperty(org.killbill.billing.payment.api.PluginProperty) Payment(org.killbill.billing.payment.api.Payment) State(org.killbill.automaton.State) AccountApiException(org.killbill.billing.account.api.AccountApiException) MissingEntryException(org.killbill.automaton.MissingEntryException) UUID(java.util.UUID)

Aggregations

CallContext (org.killbill.billing.util.callcontext.CallContext)82 ApiOperation (io.swagger.annotations.ApiOperation)51 ApiResponses (io.swagger.annotations.ApiResponses)51 Produces (javax.ws.rs.Produces)48 TimedResource (org.killbill.commons.metrics.TimedResource)48 Consumes (javax.ws.rs.Consumes)47 Path (javax.ws.rs.Path)43 UUID (java.util.UUID)40 Account (org.killbill.billing.account.api.Account)38 POST (javax.ws.rs.POST)35 PluginProperty (org.killbill.billing.payment.api.PluginProperty)29 LocalDate (org.joda.time.LocalDate)16 Payment (org.killbill.billing.payment.api.Payment)15 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)14 DefaultCallContext (org.killbill.billing.callcontext.DefaultCallContext)11 Invoice (org.killbill.billing.invoice.api.Invoice)10 PaymentOptions (org.killbill.billing.payment.api.PaymentOptions)10 PUT (javax.ws.rs.PUT)9 Entitlement (org.killbill.billing.entitlement.api.Entitlement)9 DELETE (javax.ws.rs.DELETE)7