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;
}
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);
}
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));
}
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));
}
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);
}
Aggregations