diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
index 0194e58..3070fd2 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/BlockingCalculator.java
@@ -28,7 +28,6 @@ import java.util.concurrent.atomic.AtomicLong;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
-import com.google.inject.Inject;
import com.ning.billing.account.api.Account;
import com.ning.billing.account.api.BillCycleDay;
import com.ning.billing.catalog.api.BillingPeriod;
@@ -41,7 +40,8 @@ import com.ning.billing.entitlement.api.billing.BillingModeType;
import com.ning.billing.entitlement.api.user.Subscription;
import com.ning.billing.junction.api.BlockingApi;
import com.ning.billing.junction.api.BlockingState;
-import com.ning.billing.junction.api.DefaultBlockingState;
+
+import com.google.inject.Inject;
public class BlockingCalculator {
private static final AtomicLong globaltotalOrder = new AtomicLong();
@@ -72,6 +72,11 @@ public class BlockingCalculator {
this.blockingApi = blockingApi;
}
+ /**
+ * 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)
+ */
public void insertBlockingEvents(final SortedSet<BillingEvent> billingEvents) {
if (billingEvents.size() <= 0) {
return;
@@ -102,7 +107,6 @@ public class BlockingCalculator {
for (final BillingEvent eventToRemove : billingEventsToRemove) {
billingEvents.remove(eventToRemove);
}
-
}
protected SortedSet<BillingEvent> eventsToRemove(final List<DisabledDuration> disabledDuration,
@@ -127,7 +131,9 @@ public class BlockingCalculator {
protected SortedSet<BillingEvent> createNewEvents(final List<DisabledDuration> disabledDuration, final SortedSet<BillingEvent> billingEvents, final Account account, final Subscription subscription) {
final SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
for (final DisabledDuration duration : disabledDuration) {
+ // The first one before the blocked duration
final BillingEvent precedingInitialEvent = precedingBillingEventForSubscription(duration.getStart(), billingEvents, subscription);
+ // The last one during of before the duration
final BillingEvent precedingFinalEvent = precedingBillingEventForSubscription(duration.getEnd(), billingEvents, subscription);
if (precedingInitialEvent != null) { // there is a preceding billing event
@@ -163,7 +169,7 @@ public class BlockingCalculator {
}
for (final BillingEvent event : filteredBillingEvents) {
- if (event.getEffectiveDate().isAfter(datetime)) { // found it its the previous event
+ if (!event.getEffectiveDate().isBefore(datetime)) { // found it its the previous event
return result;
} else { // still looking
result = event;
@@ -237,7 +243,7 @@ public class BlockingCalculator {
subs = new ArrayList<Subscription>();
result.put(bundleId, subs);
}
- if (!result.contains(event.getSubscription())) {
+ if (!result.get(bundleId).contains(event.getSubscription())) {
subs.add(event.getSubscription());
}
}
@@ -245,14 +251,18 @@ public class BlockingCalculator {
}
+ // In ascending order
protected List<DisabledDuration> createBlockingDurations(final List<BlockingState> overdueBundleEvents) {
final List<DisabledDuration> result = new ArrayList<BlockingCalculator.DisabledDuration>();
+ // Earliest blocking event
BlockingState first = null;
for (final BlockingState e : overdueBundleEvents) {
- if (e.isBlockBilling() && first == null) { // found a transition to disabled
+ if (e.isBlockBilling() && first == null) {
+ // First blocking event of contiguous series of blocking events
first = e;
- } else if (first != null && !e.isBlockBilling()) { // found a transition from disabled
+ } else if (first != null && !e.isBlockBilling()) {
+ // End of the interval
result.add(new DisabledDuration(first.getTimestamp(), e.getTimestamp()));
first = null;
}
diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
index 705d8ac..466900d 100644
--- a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBlockingCalculator.java
@@ -722,4 +722,40 @@ public class TestBlockingCalculator extends JunctionTestSuite {
assertNotNull(pairs.get(0).getEnd());
assertEquals(pairs.get(0).getEnd(), now.plusDays(4));
}
+
+ @Test(groups = "fast")
+ public void testSimpleWithClearBlockingDuration() throws Exception {
+ final UUID ovdId = UUID.randomUUID();
+
+ final BillingEvent trial = createRealEvent(new LocalDate(2012, 5, 1).toDateTimeAtStartOfDay(DateTimeZone.UTC), subscription1, SubscriptionTransitionType.CREATE);
+ final BillingEvent phase = createRealEvent(new LocalDate(2012, 5, 31).toDateTimeAtStartOfDay(DateTimeZone.UTC), subscription1, SubscriptionTransitionType.PHASE);
+ final BillingEvent upgrade = createRealEvent(new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC), subscription1, SubscriptionTransitionType.CHANGE);
+ final SortedSet<BillingEvent> billingEvents = new TreeSet<BillingEvent>();
+ billingEvents.add(trial);
+ billingEvents.add(phase);
+ billingEvents.add(upgrade);
+
+ final List<BlockingState> blockingEvents = new ArrayList<BlockingState>();
+ blockingEvents.add(new DefaultBlockingState(ovdId, DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", true, false, false, new LocalDate(2012, 7, 5).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+ blockingEvents.add(new DefaultBlockingState(ovdId, DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 15).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+ blockingEvents.add(new DefaultBlockingState(ovdId, DISABLED_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", true, true, true, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+ blockingEvents.add(new DefaultBlockingState(ovdId, CLEAR_BUNDLE, Type.SUBSCRIPTION_BUNDLE, "test", false, false, false, new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC)));
+
+ Mockito.when(blockingApi.getBlockingHistory(bundleId1)).thenReturn(blockingEvents);
+
+ odc.insertBlockingEvents(billingEvents);
+
+ assertEquals(billingEvents.size(), 5);
+ final List<BillingEvent> events = new ArrayList<BillingEvent>(billingEvents);
+ assertEquals(events.get(0).getEffectiveDate(), new LocalDate(2012, 5, 1).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+ assertEquals(events.get(0).getTransitionType(), SubscriptionTransitionType.CREATE);
+ assertEquals(events.get(1).getEffectiveDate(), new LocalDate(2012, 5, 31).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+ assertEquals(events.get(1).getTransitionType(), SubscriptionTransitionType.PHASE);
+ assertEquals(events.get(2).getEffectiveDate(), new LocalDate(2012, 7, 15).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+ assertEquals(events.get(2).getTransitionType(), SubscriptionTransitionType.START_BILLING_DISABLED);
+ assertEquals(events.get(3).getEffectiveDate(), new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+ assertEquals(events.get(3).getTransitionType(), SubscriptionTransitionType.END_BILLING_DISABLED);
+ assertEquals(events.get(4).getEffectiveDate(), new LocalDate(2012, 7, 25).toDateTimeAtStartOfDay(DateTimeZone.UTC));
+ assertEquals(events.get(4).getTransitionType(), SubscriptionTransitionType.CHANGE);
+ }
}