Search in sources :

Example 31 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class JunctionTestSuiteNoDB method subscription.

protected SubscriptionBase subscription(final UUID id) {
    final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
    Mockito.when(subscription.getId()).thenReturn(id);
    return subscription;
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase)

Example 32 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class BlockingCalculator method insertBlockingEvents.

/**
 * Given a set of billing events, add corresponding blocking (overdue) billing events.
 *
 * @param billingEvents the original list of billing events to update (without overdue events)
 * @param cutoffDt an optional cutoffDt to filter out billing events
 */
public boolean insertBlockingEvents(final SortedSet<BillingEvent> billingEvents, final Set<UUID> skippedSubscriptions, final Map<UUID, List<SubscriptionBase>> subscriptionsForAccount, final VersionedCatalog catalog, @Nullable final LocalDate cutoffDt, final InternalTenantContext context) throws CatalogApiException {
    if (billingEvents.size() <= 0) {
        return false;
    }
    final Collection<BillingEvent> billingEventsToAdd = new TreeSet<BillingEvent>();
    final Collection<BillingEvent> billingEventsToRemove = new TreeSet<BillingEvent>();
    final List<BlockingState> blockingEvents = blockingApi.getBlockingActiveForAccount(catalog, cutoffDt, context);
    // Group blocking states per type
    final Collection<BlockingState> accountBlockingEvents = new LinkedList<BlockingState>();
    final Map<UUID, List<BlockingState>> perBundleBlockingEvents = new HashMap<UUID, List<BlockingState>>();
    final Map<UUID, List<BlockingState>> perSubscriptionBlockingEvents = new HashMap<UUID, List<BlockingState>>();
    for (final BlockingState blockingEvent : blockingEvents) {
        if (blockingEvent.getType() == BlockingStateType.ACCOUNT) {
            accountBlockingEvents.add(blockingEvent);
        } else if (blockingEvent.getType() == BlockingStateType.SUBSCRIPTION_BUNDLE) {
            perBundleBlockingEvents.putIfAbsent(blockingEvent.getBlockedId(), new LinkedList<BlockingState>());
            perBundleBlockingEvents.get(blockingEvent.getBlockedId()).add(blockingEvent);
        } else if (blockingEvent.getType() == BlockingStateType.SUBSCRIPTION) {
            perSubscriptionBlockingEvents.putIfAbsent(blockingEvent.getBlockedId(), new LinkedList<BlockingState>());
            perSubscriptionBlockingEvents.get(blockingEvent.getBlockedId()).add(blockingEvent);
        }
    }
    // Group billing events per subscriptionId
    final Map<UUID, SortedSet<BillingEvent>> perSubscriptionBillingEvents = new HashMap<UUID, SortedSet<BillingEvent>>();
    for (final BillingEvent event : billingEvents) {
        if (!perSubscriptionBillingEvents.containsKey(event.getSubscriptionId())) {
            perSubscriptionBillingEvents.put(event.getSubscriptionId(), new TreeSet<BillingEvent>());
        }
        perSubscriptionBillingEvents.get(event.getSubscriptionId()).add(event);
    }
    for (final Entry<UUID, List<SubscriptionBase>> entry : subscriptionsForAccount.entrySet()) {
        final UUID bundleId = entry.getKey();
        final List<BlockingState> bundleBlockingEvents = perBundleBlockingEvents.get(bundleId) != null ? perBundleBlockingEvents.get(bundleId) : ImmutableList.<BlockingState>of();
        for (final SubscriptionBase subscription : entry.getValue()) {
            // Avoid inserting additional events for subscriptions that don't even have a START event
            if (skippedSubscriptions.contains(subscription.getId())) {
                continue;
            }
            final List<BlockingState> subscriptionBlockingEvents = perSubscriptionBlockingEvents.get(subscription.getId()) != null ? perSubscriptionBlockingEvents.get(subscription.getId()) : ImmutableList.<BlockingState>of();
            final List<BlockingState> aggregateSubscriptionBlockingEvents = getAggregateBlockingEventsPerSubscription(subscription.getEndDate(), subscriptionBlockingEvents, bundleBlockingEvents, accountBlockingEvents);
            final List<DisabledDuration> accountBlockingDurations = createBlockingDurations(aggregateSubscriptionBlockingEvents);
            final SortedSet<BillingEvent> subscriptionBillingEvents = perSubscriptionBillingEvents.getOrDefault(subscription.getId(), ImmutableSortedSet.<BillingEvent>of());
            final SortedSet<BillingEvent> newEvents = createNewEvents(accountBlockingDurations, subscriptionBillingEvents, context);
            billingEventsToAdd.addAll(newEvents);
            final SortedSet<BillingEvent> removedEvents = eventsToRemove(accountBlockingDurations, subscriptionBillingEvents);
            billingEventsToRemove.addAll(removedEvents);
        }
    }
    billingEvents.addAll(billingEventsToAdd);
    for (final BillingEvent eventToRemove : billingEventsToRemove) {
        billingEvents.remove(eventToRemove);
    }
    return !(billingEventsToAdd.isEmpty() && billingEventsToRemove.isEmpty());
}
Also used : HashMap(java.util.HashMap) BlockingState(org.killbill.billing.entitlement.api.BlockingState) SortedSet(java.util.SortedSet) ImmutableSortedSet(com.google.common.collect.ImmutableSortedSet) LinkedList(java.util.LinkedList) SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) TreeSet(java.util.TreeSet) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) List(java.util.List) BillingEvent(org.killbill.billing.junction.BillingEvent) UUID(java.util.UUID)

Example 33 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class TestDefaultInternalBillingApi method testBlockingStatesWithSameEffectiveDate.

// This test was originally for https://github.com/killbill/killbill/issues/123.
// The invocationCount > 0 was to trigger an issue where events would come out-of-order randomly.
// While the bug shouldn't occur anymore, we're keeping it just in case (the test will also try to insert the events out-of-order manually).
// This test also checks we don't generate billing events for blocking durations less than a day (https://github.com/killbill/killbill/issues/267).
@Test(groups = "slow", description = "Check blocking states with same effective date are correctly handled", invocationCount = 10)
public void testBlockingStatesWithSameEffectiveDate() throws Exception {
    final LocalDate initialDate = new LocalDate(2013, 8, 7);
    clock.setDay(initialDate);
    final Account account = createAccount(getAccountData(7));
    testListener.pushExpectedEvents(NextEvent.CREATE, NextEvent.BLOCK);
    final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
    final UUID entitlementId = entitlementApi.createBaseEntitlement(account.getId(), new DefaultEntitlementSpecifier(spec), account.getExternalKey(), null, null, false, true, ImmutableList.<PluginProperty>of(), callContext);
    final Entitlement entitlement = entitlementApi.getEntitlementForId(entitlementId, callContext);
    final SubscriptionBase subscription = subscriptionInternalApi.getSubscriptionFromId(entitlement.getId(), internalCallContext);
    assertListenerStatus();
    final DateTime block1Date = clock.getUTCNow();
    testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.BLOCK);
    final DefaultBlockingState state1 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_BLOCKED, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), true, true, true, block1Date);
    blockingInternalApi.setBlockingState(state1, internalCallContext);
    // Same date, we'll order by record id asc
    final DefaultBlockingState state2 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_CLEAR, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), false, false, false, block1Date);
    blockingInternalApi.setBlockingState(state2, internalCallContext);
    assertListenerStatus();
    clock.addDays(5);
    final DateTime block2Date = clock.getUTCNow();
    testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.BLOCK);
    final DefaultBlockingState state3 = new DefaultBlockingState(entitlement.getBundleId(), BlockingStateType.SUBSCRIPTION_BUNDLE, DefaultEntitlementApi.ENT_STATE_BLOCKED, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), true, true, true, block2Date);
    blockingInternalApi.setBlockingState(state3, internalCallContext);
    // Same date, we'll order by record id asc
    final DefaultBlockingState state4 = new DefaultBlockingState(entitlement.getBundleId(), BlockingStateType.SUBSCRIPTION_BUNDLE, DefaultEntitlementApi.ENT_STATE_CLEAR, KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), false, false, false, block2Date);
    blockingInternalApi.setBlockingState(state4, internalCallContext);
    assertListenerStatus();
    final DateTime block3Date = block2Date.plusDays(3);
    // Pass the phase
    testListener.pushExpectedEvent(NextEvent.PHASE);
    clock.addDays(50);
    assertListenerStatus();
    final DateTime block4Date = clock.getUTCNow();
    final DateTime block5Date = block4Date.plusDays(3);
    // Only one event on the bus (for state5)
    testListener.pushExpectedEvents(NextEvent.BLOCK);
    // Insert the clear state first, to make sure the order in which we insert blocking states doesn't matter
    // Since we are already in an ENT_STATE_CLEAR state for service ENTITLEMENT_SERVICE_NAME, we need to use a different
    // state name to simulate this behavior (otherwise, by design, this event won't be created)
    final DefaultBlockingState state6 = new DefaultBlockingState(entitlement.getBundleId(), BlockingStateType.SUBSCRIPTION_BUNDLE, DefaultEntitlementApi.ENT_STATE_CLEAR + "-something", KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), false, false, false, block5Date);
    blockingInternalApi.setBlockingState(state6, internalCallContext);
    final DefaultBlockingState state5 = new DefaultBlockingState(entitlement.getBundleId(), BlockingStateType.SUBSCRIPTION_BUNDLE, DefaultEntitlementApi.ENT_STATE_BLOCKED + "-something", KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), true, true, true, block4Date);
    blockingInternalApi.setBlockingState(state5, internalCallContext);
    assertListenerStatus();
    // Now, add back blocking states at an earlier date, for a different blockable id, to make sure the effective
    // date ordering is correctly respected when computing blocking durations
    testListener.pushExpectedEvents(NextEvent.BLOCK, NextEvent.BLOCK);
    final DefaultBlockingState state7 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_BLOCKED + "-something2", KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), true, true, true, block3Date);
    blockingInternalApi.setBlockingState(state7, internalCallContext);
    final DefaultBlockingState state8 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_CLEAR + "-something2", KILLBILL_SERVICES.ENTITLEMENT_SERVICE.getServiceName(), false, false, false, block4Date);
    blockingInternalApi.setBlockingState(state8, internalCallContext);
    assertListenerStatus();
    // Advance for state6 to be active
    testListener.pushExpectedEvents(NextEvent.BLOCK);
    clock.addDays(5);
    assertListenerStatus();
    // Expected blocking duration:
    // * 2013-08-15 to 2013-10-04 [2013-08-15 to 2013-10-01 (block3Date -> block4Date) and 2013-10-01 to 2013-10-04 (block4Date -> block5Date)]
    final List<BillingEvent> events = ImmutableList.<BillingEvent>copyOf(billingInternalApi.getBillingEventsForAccountAndUpdateAccountBCD(account.getId(), null, null, internalCallContext));
    Assert.assertEquals(events.size(), 3);
    Assert.assertEquals(events.get(0).getTransitionType(), SubscriptionBaseTransitionType.CREATE);
    Assert.assertEquals(events.get(0).getEffectiveDate(), subscription.getStartDate());
    Assert.assertEquals(events.get(1).getTransitionType(), SubscriptionBaseTransitionType.START_BILLING_DISABLED);
    Assert.assertEquals(events.get(1).getEffectiveDate().compareTo(block3Date), 0);
    Assert.assertEquals(events.get(2).getTransitionType(), SubscriptionBaseTransitionType.END_BILLING_DISABLED);
    Assert.assertEquals(events.get(2).getEffectiveDate().compareTo(block5Date), 0);
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) DefaultEntitlementSpecifier(org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier) SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) Account(org.killbill.billing.account.api.Account) BillingEvent(org.killbill.billing.junction.BillingEvent) UUID(java.util.UUID) Entitlement(org.killbill.billing.entitlement.api.Entitlement) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) DefaultBlockingState(org.killbill.billing.junction.DefaultBlockingState) Test(org.testng.annotations.Test)

Example 34 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class DefaultSubscriptionInternalApi method getSubscriptionFromExternalKey.

@Override
public SubscriptionBase getSubscriptionFromExternalKey(final String externalKey, final InternalTenantContext context) throws SubscriptionBaseApiException {
    try {
        final SubscriptionCatalog catalog = subscriptionCatalogApi.getFullCatalog(context);
        final SubscriptionBase result = dao.getSubscriptionFromExternalKey(externalKey, catalog, context);
        if (result == null) {
            throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_SUBSCRIPTION_EXTERNAL_KEY, externalKey);
        }
        return createSubscriptionForApiUse(result);
    } catch (final CatalogApiException e) {
        throw new SubscriptionBaseApiException(e);
    }
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) SubscriptionCatalog(org.killbill.billing.subscription.catalog.SubscriptionCatalog) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)

Example 35 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class DefaultSubscriptionBaseTimelineApi method createGetSubscriptionRepairList.

private List<SubscriptionBaseTimeline> createGetSubscriptionRepairList(final List<DefaultSubscriptionBase> subscriptions, final List<SubscriptionBaseTimeline> inRepair, final SubscriptionCatalog catalog, final InternalTenantContext tenantContext) throws CatalogApiException {
    final List<SubscriptionBaseTimeline> result = new LinkedList<SubscriptionBaseTimeline>();
    final Set<UUID> repairIds = new TreeSet<UUID>();
    for (final SubscriptionBaseTimeline cur : inRepair) {
        repairIds.add(cur.getId());
        result.add(cur);
    }
    for (final SubscriptionBase cur : subscriptions) {
        if (!repairIds.contains(cur.getId())) {
            result.add(new DefaultSubscriptionBaseTimeline((DefaultSubscriptionBase) cur, catalog, clock));
        }
    }
    return result;
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) TreeSet(java.util.TreeSet) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) UUID(java.util.UUID) LinkedList(java.util.LinkedList)

Aggregations

SubscriptionBase (org.killbill.billing.subscription.api.SubscriptionBase)120 Test (org.testng.annotations.Test)47 UUID (java.util.UUID)46 DateTime (org.joda.time.DateTime)40 Plan (org.killbill.billing.catalog.api.Plan)37 ArrayList (java.util.ArrayList)35 LocalDate (org.joda.time.LocalDate)33 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)32 BillingEvent (org.killbill.billing.junction.BillingEvent)30 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)26 MockPlan (org.killbill.billing.catalog.MockPlan)24 MockPlanPhase (org.killbill.billing.catalog.MockPlanPhase)24 MockBillingEventSet (org.killbill.billing.invoice.MockBillingEventSet)23 SubscriptionBaseApiException (org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)23 BigDecimal (java.math.BigDecimal)22 LinkedList (java.util.LinkedList)21 Invoice (org.killbill.billing.invoice.api.Invoice)21 AccountInvoices (org.killbill.billing.invoice.optimizer.InvoiceOptimizerBase.AccountInvoices)21 BillingEventSet (org.killbill.billing.junction.BillingEventSet)21 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)20