diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
index b3ac142..17f87de 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionApi.java
@@ -26,12 +26,16 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import org.joda.time.DateTimeZone;
+import org.joda.time.Interval;
import org.joda.time.LocalDate;
+import org.joda.time.Period;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.ObjectType;
+import org.killbill.billing.OrderingType;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.account.api.AccountInternalApi;
import org.killbill.billing.account.api.ImmutableAccountData;
@@ -41,6 +45,7 @@ import org.killbill.billing.entitlement.AccountEntitlements;
import org.killbill.billing.entitlement.EntitlementInternalApi;
import org.killbill.billing.entitlement.EntitlementService;
import org.killbill.billing.entitlement.api.EntitlementPluginExecution.WithEntitlementPlugin;
+import org.killbill.billing.entitlement.dao.BlockingStateDao;
import org.killbill.billing.entitlement.engine.core.EntitlementUtils;
import org.killbill.billing.entitlement.plugin.api.EntitlementContext;
import org.killbill.billing.entitlement.plugin.api.OperationType;
@@ -64,6 +69,7 @@ import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import static org.killbill.billing.util.entity.dao.DefaultPaginationHelper.getEntityPaginationNoException;
@@ -97,6 +103,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
private final EntitlementUtils entitlementUtils;
private final Clock clock;
private final EntitlementPluginExecution pluginExecution;
+ private final BlockingStateDao blockingStateDao;
@Inject
@@ -106,6 +113,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
final InternalCallContextFactory internalCallContextFactory,
final Clock clock,
final EntitlementPluginExecution pluginExecution,
+ final BlockingStateDao blockingStateDao,
final EntitlementUtils entitlementUtils) {
this.accountApi = accountApi;
this.entitlementInternalApi = entitlementInternalApi;
@@ -113,6 +121,7 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
this.internalCallContextFactory = internalCallContextFactory;
this.clock = clock;
this.pluginExecution = pluginExecution;
+ this.blockingStateDao = blockingStateDao;
this.entitlementUtils = entitlementUtils;
}
@@ -375,6 +384,52 @@ public class DefaultSubscriptionApi implements SubscriptionApi {
pluginExecution.executeWithPlugin(addBlockingStateWithPlugin, pluginContext);
}
+ @Override
+ public Iterable<BlockingState> getBlockingStates(final UUID accountId, @Nullable final List<BlockingStateType> typeFilter, @Nullable final List<String> svcsFilter, final OrderingType orderingType, final int timeFilter, final TenantContext tenantContext) throws EntitlementApiException {
+
+ try {
+
+ final InternalTenantContext internalTenantContextWithValidAccountRecordId = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext);
+ final List<BlockingState> allBlockingStates = blockingStateDao.getBlockingAllForAccountRecordId(internalTenantContextWithValidAccountRecordId);
+
+ final ImmutableAccountData account = accountApi.getImmutableAccountDataById(accountId, internalTenantContextWithValidAccountRecordId);
+
+ final Iterable<BlockingState> filteredByTypes = typeFilter != null && !typeFilter.isEmpty() ?
+ Iterables.filter(allBlockingStates, new Predicate<BlockingState>() {
+ @Override
+ public boolean apply(final BlockingState input) {
+ return typeFilter.contains(input.getType());
+ }
+ }) : allBlockingStates;
+
+ final Iterable<BlockingState> filteredByTypesAndSvcs = svcsFilter != null && !svcsFilter.isEmpty() ?
+ Iterables.filter(filteredByTypes, new Predicate<BlockingState>() {
+ @Override
+ public boolean apply(final BlockingState input) {
+ return svcsFilter.contains(input.getService());
+ }
+ }) : filteredByTypes;
+
+ final LocalDate localDateNowInAccountTimezone = new LocalDate(clock.getUTCNow(), account.getTimeZone());
+ final List<BlockingState> result = new ArrayList<BlockingState>();
+ for (final BlockingState cur : filteredByTypesAndSvcs) {
+
+ final LocalDate eventDate = new LocalDate(cur.getEffectiveDate(), account.getTimeZone());
+ final int comp = eventDate.compareTo(localDateNowInAccountTimezone);
+ if ((comp <= 1 && ((timeFilter & SubscriptionApi.PAST_EVENTS) == SubscriptionApi.PAST_EVENTS)) ||
+ (comp == 0 && ((timeFilter & SubscriptionApi.PRESENT_EVENTS) == SubscriptionApi.PRESENT_EVENTS)) ||
+ (comp >= 1 && ((timeFilter & SubscriptionApi.FUTURE_EVENTS) == SubscriptionApi.FUTURE_EVENTS))) {
+ result.add(cur);
+ }
+ }
+
+ return orderingType == OrderingType.ASCENDING ? result : Lists.reverse(result);
+
+ } catch (AccountApiException e) {
+ throw new EntitlementApiException(e);
+ }
+ }
+
private List<SubscriptionBundle> getSubscriptionBundlesForAccount(final UUID accountId, final TenantContext tenantContext) throws SubscriptionApiException {
// Retrieve entitlements
final AccountEntitlements accountEntitlements;
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
index 3b74850..7c212d1 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -16,10 +16,13 @@
package org.killbill.billing.entitlement.api;
+import java.util.Iterator;
import java.util.List;
import java.util.UUID;
+import org.joda.time.DateTime;
import org.joda.time.LocalDate;
+import org.killbill.billing.OrderingType;
import org.killbill.billing.catalog.api.BillingActionPolicy;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
import org.killbill.billing.entitlement.api.Entitlement.EntitlementState;
@@ -354,6 +357,61 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
updateEntitlement = entitlementApi.getEntitlementForId(createdEntitlement.getId(), callContext);
Assert.assertEquals(updateEntitlement.getState(), EntitlementState.BLOCKED);
+ // Now we remove the blocking state for the same service but at the SUBSCRIPTION level
+ testListener.pushExpectedEvent(NextEvent.BLOCK);
+ final BlockingState state3 = new DefaultBlockingState(createdEntitlement.getId(), BlockingStateType.SUBSCRIPTION, "subscriptionUnBlock", "svc1", false, false, false, clock.getUTCNow());
+ subscriptionApi.addBlockingState(state3, ImmutableList.<PluginProperty>of(), callContext);
+ assertListenerStatus();
+
+ updateEntitlement = entitlementApi.getEntitlementForId(createdEntitlement.getId(), callContext);
+ Assert.assertEquals(updateEntitlement.getState(), EntitlementState.BLOCKED);
+
+
+ final DateTime futureEffectiveDate = clock.getUTCNow().plusDays(1);
+ final BlockingState state4 = new DefaultBlockingState(createdEntitlement.getBundleId(), BlockingStateType.SUBSCRIPTION_BUNDLE, "blockBilling", "svc1", true, false, false, futureEffectiveDate);
+ subscriptionApi.addBlockingState(state4, ImmutableList.<PluginProperty>of(), callContext);
+
+
+ final Iterable<BlockingState> blockingStates1 = subscriptionApi.getBlockingStates(account.getId(), ImmutableList.of(BlockingStateType.ACCOUNT, BlockingStateType.SUBSCRIPTION), ImmutableList.of("svc1", "svc2"), OrderingType.ASCENDING, SubscriptionApi.PAST_OR_PRESENT_EVENTS, callContext);
+ verifyBlockingStates(blockingStates1, ImmutableList.<BlockingState>of(state1, state2, state3));
+
+ final Iterable<BlockingState> blockingStates3 = subscriptionApi.getBlockingStates(account.getId(), ImmutableList.of(BlockingStateType.SUBSCRIPTION), ImmutableList.of("svc1", "svc2"), OrderingType.DESCENDING, SubscriptionApi.PAST_OR_PRESENT_EVENTS, callContext);
+ verifyBlockingStates(blockingStates3, ImmutableList.<BlockingState>of(state3, state2));
+
+ final Iterable<BlockingState> blockingStates4 = subscriptionApi.getBlockingStates(account.getId(), ImmutableList.of(BlockingStateType.SUBSCRIPTION), ImmutableList.of("svc2"), OrderingType.DESCENDING, SubscriptionApi.PAST_OR_PRESENT_EVENTS, callContext);
+ verifyBlockingStates(blockingStates4, ImmutableList.<BlockingState>of(state2));
+
+ final Iterable<BlockingState> blockingStates2 = subscriptionApi.getBlockingStates(account.getId(), null, null, OrderingType.DESCENDING, SubscriptionApi.ALL_EVENTS, callContext);
+ verifyBlockingStates(blockingStates2, ImmutableList.<BlockingState>of(state4, state3, state2, state1));
+
+ final Iterable<BlockingState> blockingStates6 = subscriptionApi.getBlockingStates(account.getId(), ImmutableList.of(BlockingStateType.SUBSCRIPTION_BUNDLE), null, OrderingType.ASCENDING, SubscriptionApi.FUTURE_EVENTS, callContext);
+ verifyBlockingStates(blockingStates6, ImmutableList.<BlockingState>of(state4));
+
+ testListener.pushExpectedEvent(NextEvent.BLOCK);
+ clock.addDays(1);
+ assertListenerStatus();
+
+ final Iterable<BlockingState> blockingStates5 = subscriptionApi.getBlockingStates(account.getId(), null, null, OrderingType.ASCENDING, SubscriptionApi.PAST_OR_PRESENT_EVENTS, callContext);
+ verifyBlockingStates(blockingStates5, ImmutableList.<BlockingState>of(state1, state2, state3, state4));
+
+ }
+
+ private void verifyBlockingStates(final Iterable<BlockingState> result, final List<BlockingState> expected) {
+ int i = 0;
+ final Iterator<BlockingState> iterator = result.iterator();
+ while (iterator.hasNext()) {
+ final BlockingState cur = iterator.next();
+ final BlockingState expectedItem = expected.get(i);
+ assertEquals(cur.isBlockBilling(), expectedItem.isBlockBilling());
+ assertEquals(cur.isBlockEntitlement(), expectedItem.isBlockEntitlement());
+ assertEquals(cur.isBlockChange(), expectedItem.isBlockChange());
+ assertEquals(cur.getService(), expectedItem.getService());
+ assertEquals(cur.getStateName(), expectedItem.getStateName());
+ assertEquals(cur.getBlockedId(), expectedItem.getBlockedId());
+ assertEquals(cur.getEffectiveDate().compareTo(expectedItem.getEffectiveDate()), 0);
+ i++;
+ }
+ assertEquals(i, expected.size());
}