Search in sources :

Example 26 with BillingEvent

use of org.killbill.billing.junction.BillingEvent in project killbill by killbill.

the class SubscriptionUsageInArrear method computeInArrearUsageInterval.

@VisibleForTesting
List<ContiguousIntervalUsageInArrear> computeInArrearUsageInterval() {
    final List<ContiguousIntervalUsageInArrear> usageIntervals = Lists.newLinkedList();
    final Map<String, ContiguousIntervalUsageInArrear> inFlightInArrearUsageIntervals = new HashMap<String, ContiguousIntervalUsageInArrear>();
    final Set<String> allSeenUsage = new HashSet<String>();
    for (final BillingEvent event : subscriptionBillingEvents) {
        // Extract all in arrear /consumable usage section for that billing event.
        final List<Usage> usages = findUsageInArrearUsages(event);
        allSeenUsage.addAll(Collections2.transform(usages, new Function<Usage, String>() {

            @Override
            public String apply(final Usage input) {
                return input.getName();
            }
        }));
        // All inflight usage interval are candidates to be closed unless we see that current billing event referencing the same usage section.
        final Set<String> toBeClosed = new HashSet<String>(allSeenUsage);
        for (final Usage usage : usages) {
            // Add inflight usage interval if non existent
            ContiguousIntervalUsageInArrear existingInterval = inFlightInArrearUsageIntervals.get(usage.getName());
            if (existingInterval == null) {
                existingInterval = new ContiguousIntervalUsageInArrear(usage, accountId, invoiceId, rawSubscriptionUsage, targetDate, rawUsageStartDate, internalTenantContext);
                inFlightInArrearUsageIntervals.put(usage.getName(), existingInterval);
            }
            // Add billing event for that usage interval
            existingInterval.addBillingEvent(event);
            // Remove usage interval for toBeClosed set
            toBeClosed.remove(usage.getName());
        }
        // Build the usage interval that are no longer referenced
        for (final String usageName : toBeClosed) {
            final ContiguousIntervalUsageInArrear interval = inFlightInArrearUsageIntervals.remove(usageName);
            if (interval != null) {
                interval.addBillingEvent(event);
                usageIntervals.add(interval.build(true));
            }
        }
    }
    for (final String usageName : inFlightInArrearUsageIntervals.keySet()) {
        usageIntervals.add(inFlightInArrearUsageIntervals.get(usageName).build(false));
    }
    inFlightInArrearUsageIntervals.clear();
    return usageIntervals;
}
Also used : Function(com.google.common.base.Function) Usage(org.killbill.billing.catalog.api.Usage) RawUsage(org.killbill.billing.usage.RawUsage) HashMap(java.util.HashMap) BillingEvent(org.killbill.billing.junction.BillingEvent) HashSet(java.util.HashSet) VisibleForTesting(com.google.common.annotations.VisibleForTesting)

Example 27 with BillingEvent

use of org.killbill.billing.junction.BillingEvent 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, enabled = false)
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 Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, null, null, false, ImmutableList.<PluginProperty>of(), 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, EntitlementService.ENTITLEMENT_SERVICE_NAME, 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, EntitlementService.ENTITLEMENT_SERVICE_NAME, 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, EntitlementService.ENTITLEMENT_SERVICE_NAME, 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, EntitlementService.ENTITLEMENT_SERVICE_NAME, 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", EntitlementService.ENTITLEMENT_SERVICE_NAME, false, false, false, block5Date);
    blockingInternalApi.setBlockingState(state6, internalCallContext);
    final DefaultBlockingState state5 = new DefaultBlockingState(entitlement.getBundleId(), BlockingStateType.SUBSCRIPTION_BUNDLE, DefaultEntitlementApi.ENT_STATE_BLOCKED + "-something", EntitlementService.ENTITLEMENT_SERVICE_NAME, 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", EntitlementService.ENTITLEMENT_SERVICE_NAME, true, true, true, block3Date);
    blockingInternalApi.setBlockingState(state7, internalCallContext);
    final DefaultBlockingState state8 = new DefaultBlockingState(account.getId(), BlockingStateType.ACCOUNT, DefaultEntitlementApi.ENT_STATE_CLEAR + "-something2", EntitlementService.ENTITLEMENT_SERVICE_NAME, 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, 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(), block3Date);
    Assert.assertEquals(events.get(2).getTransitionType(), SubscriptionBaseTransitionType.END_BILLING_DISABLED);
    Assert.assertEquals(events.get(2).getEffectiveDate(), block5Date);
}
Also used : PlanPhaseSpecifier(org.killbill.billing.catalog.api.PlanPhaseSpecifier) SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) Account(org.killbill.billing.account.api.Account) BillingEvent(org.killbill.billing.junction.BillingEvent) 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 28 with BillingEvent

use of org.killbill.billing.junction.BillingEvent in project killbill by killbill.

the class TestBlockingCalculator method testPrecedingBillingEventForSubscription.

@Test(groups = "fast")
public void testPrecedingBillingEventForSubscription() {
    final DateTime now = new DateTime();
    final SortedSet<BillingEvent> events = new TreeSet<BillingEvent>();
    events.add(createRealEvent(now.minusDays(10), subscription1));
    events.add(createRealEvent(now.minusDays(6), subscription1));
    events.add(createRealEvent(now.minusDays(5), subscription1));
    events.add(createRealEvent(now.minusDays(1), subscription1));
    final BillingEvent minus11 = blockingCalculator.precedingBillingEventForSubscription(now.minusDays(11), events, subscription1);
    assertNull(minus11);
    final BillingEvent minus5andAHalf = blockingCalculator.precedingBillingEventForSubscription(now.minusDays(5).minusHours(12), events, subscription1);
    assertNotNull(minus5andAHalf);
    assertEquals(minus5andAHalf.getEffectiveDate(), now.minusDays(6));
}
Also used : TreeSet(java.util.TreeSet) BillingEvent(org.killbill.billing.junction.BillingEvent) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 29 with BillingEvent

use of org.killbill.billing.junction.BillingEvent in project killbill by killbill.

the class TestBlockingCalculator method testCreateNewDisableEvent.

@Test(groups = "fast")
public void testCreateNewDisableEvent() throws CatalogApiException {
    final DateTime now = clock.getUTCNow();
    final BillingEvent event = new MockBillingEvent();
    final BillingEvent result = blockingCalculator.createNewDisableEvent(now, event, null, internalCallContext);
    assertEquals(result.getBillCycleDayLocal(), event.getBillCycleDayLocal());
    assertEquals(result.getEffectiveDate(), now);
    assertEquals(result.getPlanPhase(), event.getPlanPhase());
    assertEquals(result.getPlan(), event.getPlan());
    assertNull(result.getFixedPrice());
    assertNull(result.getRecurringPrice(null));
    assertEquals(result.getCurrency(), event.getCurrency());
    assertEquals(result.getDescription(), "");
    assertEquals(result.getBillingPeriod(), BillingPeriod.NO_BILLING_PERIOD);
    assertEquals(result.getTransitionType(), SubscriptionBaseTransitionType.START_BILLING_DISABLED);
    // TODO - ugly, fragile
    assertEquals(result.getTotalOrdering(), (Long) (BlockingCalculator.getGlobalTotalOrder().get() - 1));
}
Also used : BillingEvent(org.killbill.billing.junction.BillingEvent) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 30 with BillingEvent

use of org.killbill.billing.junction.BillingEvent in project killbill by killbill.

the class TestBlockingCalculator method testCreateNewEventsOpenFollow.

// Open with no previous event (only following)
// -----[----X-----------------------------
@Test(groups = "fast")
public void testCreateNewEventsOpenFollow() throws CatalogApiException {
    final DateTime now = clock.getUTCNow();
    final List<DisabledDuration> disabledDuration = new ArrayList<BlockingCalculator.DisabledDuration>();
    final SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
    disabledDuration.add(new DisabledDuration(now, null));
    billingEvents.add(createRealEvent(now.plusDays(1), subscription1));
    final SortedSet<BillingEvent> results = blockingCalculator.createNewEvents(disabledDuration, billingEvents, subscription1, internalCallContext);
    assertEquals(results.size(), 0);
}
Also used : DisabledDuration(org.killbill.billing.junction.plumbing.billing.BlockingCalculator.DisabledDuration) TreeSet(java.util.TreeSet) ArrayList(java.util.ArrayList) BillingEvent(org.killbill.billing.junction.BillingEvent) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Aggregations

BillingEvent (org.killbill.billing.junction.BillingEvent)98 Test (org.testng.annotations.Test)82 DateTime (org.joda.time.DateTime)52 LocalDate (org.joda.time.LocalDate)49 Plan (org.killbill.billing.catalog.api.Plan)42 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)41 MockPlan (org.killbill.billing.catalog.MockPlan)40 MockPlanPhase (org.killbill.billing.catalog.MockPlanPhase)40 BigDecimal (java.math.BigDecimal)36 ArrayList (java.util.ArrayList)36 UUID (java.util.UUID)35 MockBillingEventSet (org.killbill.billing.invoice.MockBillingEventSet)35 BillingEventSet (org.killbill.billing.junction.BillingEventSet)33 Invoice (org.killbill.billing.invoice.api.Invoice)32 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)32 TreeSet (java.util.TreeSet)30 InvoiceItem (org.killbill.billing.invoice.api.InvoiceItem)27 FixedPriceInvoiceItem (org.killbill.billing.invoice.model.FixedPriceInvoiceItem)26 DefaultPrice (org.killbill.billing.catalog.DefaultPrice)25 MockInternationalPrice (org.killbill.billing.catalog.MockInternationalPrice)25