killbill-aplcache

Details

diff --git a/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
new file mode 100644
index 0000000..d0b97bf
--- /dev/null
+++ b/junction/src/test/java/com/ning/billing/junction/plumbing/billing/TestBillingApi.java
@@ -0,0 +1,561 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.junction.plumbing.billing;
+
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.catalog.MockCatalog;
+import com.ning.billing.catalog.MockCatalogService;
+import com.ning.billing.catalog.api.BillingAlignment;
+import com.ning.billing.catalog.api.CatalogApiException;
+import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.catalog.api.CurrencyValueNull;
+import com.ning.billing.catalog.api.InternationalPrice;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.Price;
+import com.ning.billing.catalog.api.PriceList;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.billing.BillingEvent;
+import com.ning.billing.entitlement.api.billing.BillingModeType;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionEvent;
+import com.ning.billing.junction.api.BillingApi;
+import com.ning.billing.junction.api.BillingEventSet;
+import com.ning.billing.junction.api.Blockable;
+import com.ning.billing.junction.api.BlockingApi;
+import com.ning.billing.junction.api.BlockingState;
+import com.ning.billing.junction.api.DefaultBlockingState;
+import com.ning.billing.lifecycle.KillbillService.ServiceException;
+import com.ning.billing.mock.BrainDeadProxyFactory;
+import com.ning.billing.mock.BrainDeadProxyFactory.ZombieControl;
+import com.ning.billing.util.api.TagUserApi;
+import com.ning.billing.util.callcontext.CallContextFactory;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.ClockMock;
+import com.ning.billing.util.dao.ObjectType;
+import com.ning.billing.util.tag.ControlTagType;
+import com.ning.billing.util.tag.Tag;
+
+public class TestBillingApi {
+    
+    class MockPrice implements InternationalPrice {
+        private final BigDecimal price;
+        
+        public MockPrice(String val) {
+            price = new BigDecimal(val);
+        }
+        
+        @Override
+        public boolean isZero() {
+            return price.compareTo(BigDecimal.ZERO) == 0;
+        }
+        
+        @Override
+        public Price[] getPrices() {
+            return new Price[]{ 
+                    new Price() {
+
+                        @Override
+                        public Currency getCurrency() {
+                            return Currency.USD;
+                        }
+
+                        @Override
+                        public BigDecimal getValue() throws CurrencyValueNull {
+                            return price;
+                        }
+
+                    }
+            };
+        }
+        
+        @Override
+        public BigDecimal getPrice(Currency currency) throws CatalogApiException {
+             return price;
+        }
+    };
+    
+    private static final String DISABLED_BUNDLE = "disabled-bundle";
+    private static final String CLEAR_BUNDLE = "clear-bundle";
+
+	private static final UUID eventId = new UUID(0L,0L);
+	private static final UUID subId = new UUID(1L,0L);
+	private static final UUID bunId = new UUID(2L,0L);
+
+	private CatalogService catalogService;
+	private List<SubscriptionBundle> bundles;
+	private List<Subscription> subscriptions;
+
+	private List<SubscriptionEvent> subscriptionTransitions;
+	private EntitlementUserApi entitlementApi;
+
+    private BlockingCalculator blockCalculator = new BlockingCalculator(null) {
+        @Override
+        public void insertBlockingEvents(SortedSet<BillingEvent> billingEvents) {
+           
+        }
+        
+    };
+
+
+
+	private Clock clock;
+	private Subscription subscription;
+	private DateTime subscriptionStartDate;
+    private Plan subscriptionPlan;
+    private TagUserApi tagApi;
+
+	@BeforeSuite(groups={"fast", "slow"})
+	public void setup() throws ServiceException {
+        catalogService = new MockCatalogService(new MockCatalog());
+        clock = new ClockMock();
+	}
+
+	@BeforeMethod(groups={"fast", "slow"})
+	public void setupEveryTime() {
+		bundles = new ArrayList<SubscriptionBundle>();
+		final SubscriptionBundle bundle = BrainDeadProxyFactory.createBrainDeadProxyFor(SubscriptionBundle.class);
+		((ZombieControl)bundle).addResult("getId", bunId);
+		        
+		        //new SubscriptionBundleData( eventId,"TestKey", subId,  clock.getUTCNow().minusDays(4), null);
+		bundles.add(bundle);
+
+
+		subscriptionTransitions = new LinkedList<SubscriptionEvent>();
+		subscriptions = new LinkedList<Subscription>();
+
+		subscriptionStartDate = clock.getUTCNow().minusDays(3);
+		subscription = new MockSubscription() {
+		    @Override
+            public List<SubscriptionEvent> getBillingTransitions() {
+		    	return subscriptionTransitions;
+		    }
+
+            @Override
+            public Plan getCurrentPlan() {
+                return subscriptionPlan;
+            }
+
+            @Override
+            public UUID getId() {
+                return subId;
+            }
+
+            @Override
+            public UUID getBundleId() {
+                return bunId;
+            }
+
+            @Override
+            public DateTime getStartDate() {
+                return subscriptionStartDate;
+            }
+            
+		    
+		};
+
+		subscriptions.add(subscription);
+
+        entitlementApi = BrainDeadProxyFactory.createBrainDeadProxyFor(EntitlementUserApi.class);
+        ((ZombieControl) entitlementApi).addResult("getBundlesForAccount", bundles);
+        ((ZombieControl) entitlementApi).addResult("getSubscriptionsForBundle", subscriptions);
+        ((ZombieControl) entitlementApi).addResult("getSubscriptionFromId", subscription);
+        ((ZombieControl) entitlementApi).addResult("getBundleFromId", bundle);
+        ((ZombieControl) entitlementApi).addResult("getBaseSubscription", subscription);
+        
+        tagApi = mock(TagUserApi.class);
+
+        assertTrue(true);
+	}
+
+    @Test(enabled=true, groups="fast")
+	public void testBillingEventsEmpty() {
+        UUID accountId = UUID.randomUUID();
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ((ZombieControl) account).addResult("getId", accountId).addResult("getCurrency", Currency.USD);
+
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        ((ZombieControl) accountApi).addResult("getAccountById", account);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+
+		BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService, tagApi);
+
+		SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+		Assert.assertEquals(events.size(), 0);
+	}
+
+    @Test(enabled=true, groups="fast")
+	public void testBillingEventsNoBillingPeriod() throws CatalogApiException {
+		DateTime now = clock.getUTCNow();
+		DateTime then = now.minusDays(1);
+		Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+		PlanPhase nextPhase = nextPlan.getAllPhases()[0]; // The trial has no billing period
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+
+        SubscriptionEvent t = new MockSubscriptionEvent(
+                eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE, 
+                nextPlan.getName(), nextPhase.getName(), 
+                nextPriceList.getName(), 1L,null, 
+                SubscriptionTransitionType.CREATE, 0, null); 
+
+		subscriptionTransitions.add(t);
+
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ((ZombieControl)account).addResult("getBillCycleDay", 32);
+        ((ZombieControl)account).addResult("getCurrency", Currency.USD);
+        ((ZombieControl)account).addResult("getId", UUID.randomUUID());
+        ((ZombieControl)accountApi).addResult("getAccountById", account);
+		       
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService, tagApi);
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
+		checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
+	}
+
+    @Test(enabled=false, groups="fast")
+	public void testBillingEventsAnnual() throws CatalogApiException {
+		DateTime now = clock.getUTCNow();
+		DateTime then = now.minusDays(1);
+		Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+		PlanPhase nextPhase = nextPlan.getAllPhases()[1];
+		PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+        SubscriptionEvent t = new MockSubscriptionEvent(
+                eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE, 
+                nextPlan.getName(), nextPhase.getName(), 
+                nextPriceList.getName(), 1L,null, 
+                SubscriptionTransitionType.CREATE, 0, null); 
+
+		subscriptionTransitions.add(t);
+
+		Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+		((ZombieControl)account).addResult("getBillCycleDay", 1).addResult("getTimeZone", DateTimeZone.UTC)
+                                .addResult("getCurrency", Currency.USD);
+
+        ((MockCatalog)catalogService.getFullCatalog()).setBillingAlignment(BillingAlignment.SUBSCRIPTION);
+        
+		AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+		((ZombieControl)accountApi).addResult("getAccountById", account);
+
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+
+        BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService, tagApi);
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
+		checkFirstEvent(events, nextPlan, subscription.getStartDate().plusDays(30).getDayOfMonth(), subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
+	}
+
+    @Test(enabled=true, groups="fast")
+	public void testBillingEventsMonthly() throws CatalogApiException {
+		DateTime now = clock.getUTCNow();
+		DateTime then = now.minusDays(1);
+		Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+		PlanPhase nextPhase = nextPlan.getAllPhases()[1];
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+
+        SubscriptionEvent t = new MockSubscriptionEvent(
+                eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE, 
+                nextPlan.getName(), nextPhase.getName(), 
+                nextPriceList.getName(), 1L,null, 
+                SubscriptionTransitionType.CREATE, 0, null); 
+
+
+		subscriptionTransitions.add(t);
+
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ((ZombieControl)account).addResult("getBillCycleDay", 32);
+        ((ZombieControl)account).addResult("getCurrency", Currency.USD);
+        ((ZombieControl)account).addResult("getId", UUID.randomUUID());
+        ((ZombieControl)accountApi).addResult("getAccountById", account);
+
+        ((MockCatalog)catalogService.getFullCatalog()).setBillingAlignment(BillingAlignment.ACCOUNT);
+        
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService, tagApi);
+
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
+		checkFirstEvent(events, nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
+	}
+
+    @Test(enabled=false, groups="fast")
+	public void testBillingEventsAddOn() throws CatalogApiException {
+		DateTime now = clock.getUTCNow();
+		DateTime then = now.minusDays(1);
+		Plan nextPlan = catalogService.getFullCatalog().findPlan("Horn1USD", now);
+		PlanPhase nextPhase = nextPlan.getAllPhases()[0];
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+
+        SubscriptionEvent t = new MockSubscriptionEvent(
+                eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE, 
+                nextPlan.getName(), nextPhase.getName(), 
+                nextPriceList.getName(), 1L,null, 
+                SubscriptionTransitionType.CREATE, 0, null); 
+
+		subscriptionTransitions.add(t);
+
+		Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+		((ZombieControl)account).addResult("getBillCycleDay", 1).addResult("getTimeZone", DateTimeZone.UTC);
+        ((ZombieControl)account).addResult("getCurrency", Currency.USD);
+        ((ZombieControl)account).addResult("getId", UUID.randomUUID());
+
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        ((ZombieControl)accountApi).addResult("getAccountById", account);
+             
+        ((MockCatalog)catalogService.getFullCatalog()).setBillingAlignment(BillingAlignment.BUNDLE);
+        
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        
+        BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService, tagApi);
+        subscriptionPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
+		checkFirstEvent(events, nextPlan, subscription.getStartDate().plusDays(30).getDayOfMonth(), subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString());
+	}
+
+    @Test(enabled=true, groups="fast")
+    public void testBillingEventsWithBlock() throws CatalogApiException {
+        DateTime now = clock.getUTCNow();
+        DateTime then = now.minusDays(1);
+        Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+        PlanPhase nextPhase = nextPlan.getAllPhases()[1];
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+
+        
+        SubscriptionEvent t = new MockSubscriptionEvent(
+                eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE, 
+                nextPlan.getName(), nextPhase.getName(), 
+                nextPriceList.getName(), 1L,null, 
+                SubscriptionTransitionType.CREATE, 0, null); 
+
+        subscriptionTransitions.add(t);
+
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ((ZombieControl)account).addResult("getBillCycleDay", 32);
+        ((ZombieControl)account).addResult("getCurrency", Currency.USD);
+        ((ZombieControl)accountApi).addResult("getAccountById", account);
+        ((ZombieControl)account).addResult("getId", UUID.randomUUID());
+
+        ((MockCatalog)catalogService.getFullCatalog()).setBillingAlignment(BillingAlignment.ACCOUNT);
+        
+        final SortedSet<BlockingState> blockingStates = new TreeSet<BlockingState>();
+        blockingStates.add(new DefaultBlockingState(bunId,DISABLED_BUNDLE, Blockable.Type.SUBSCRIPTION_BUNDLE, "test", true, true, true, now.plusDays(1)));
+        blockingStates.add(new DefaultBlockingState(bunId,CLEAR_BUNDLE, Blockable.Type.SUBSCRIPTION_BUNDLE, "test", false, false, false, now.plusDays(2)));
+        
+        BlockingCalculator blockingCal = new BlockingCalculator(new BlockingApi() {
+            
+            @Override
+            public <T extends Blockable> void setBlockingState(BlockingState state) {}
+            
+            @Override
+            public BlockingState getBlockingStateFor(UUID overdueableId) {
+                return null;
+            }
+            
+            @Override
+            public BlockingState getBlockingStateFor(Blockable overdueable) {
+                return null;
+            }
+            
+            @Override
+            public SortedSet<BlockingState> getBlockingHistory(UUID overdueableId) {
+                if(overdueableId == bunId) {
+                    return blockingStates;
+                }
+                return new TreeSet<BlockingState>();
+            }
+            
+            @Override
+            public SortedSet<BlockingState> getBlockingHistory(Blockable overdueable) {
+                return new TreeSet<BlockingState>();
+            }
+        });
+        
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockingCal, catalogService, tagApi);
+        SortedSet<BillingEvent> events = api.getBillingEventsForAccountAndUpdateAccountBCD(new UUID(0L,0L));
+
+        Assert.assertEquals(events.size(), 3);
+        Iterator<BillingEvent> it = events.iterator();
+       
+        checkEvent(it.next(), nextPlan, 32, subId, now, nextPhase, SubscriptionTransitionType.CREATE.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
+        checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(1), nextPhase, SubscriptionTransitionType.CANCEL.toString(), new MockPrice("0"), new MockPrice("0"));
+        checkEvent(it.next(), nextPlan, 32, subId, now.plusDays(2), nextPhase, SubscriptionTransitionType.RE_CREATE.toString(), nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
+        
+    }
+    
+    @Test(enabled=true, groups="fast")
+    public void testBillingEventsAutoInvoicingOffAccount() throws CatalogApiException {
+        DateTime now = clock.getUTCNow();
+        DateTime then = now.minusDays(1);
+        Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+        PlanPhase nextPhase = nextPlan.getAllPhases()[1];
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+
+        SubscriptionEvent t = new MockSubscriptionEvent(
+                eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE, 
+                nextPlan.getName(), nextPhase.getName(), 
+                nextPriceList.getName(), 1L,null, 
+                SubscriptionTransitionType.CREATE, 0, null); 
+
+
+        subscriptionTransitions.add(t);
+
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ((ZombieControl)account).addResult("getBillCycleDay", 32);
+        ((ZombieControl)account).addResult("getCurrency", Currency.USD);
+        ((ZombieControl)account).addResult("getId", UUID.randomUUID());
+        ((ZombieControl)accountApi).addResult("getAccountById", account);
+        
+         Map<String, Tag> tags = new HashMap<String, Tag>();
+        Tag aioTag = mock(Tag.class);
+        when(aioTag.getTagDefinitionName()).thenReturn(ControlTagType.AUTO_INVOICING_OFF.name());
+        tags.put(ControlTagType.AUTO_INVOICING_OFF.name(),aioTag);
+        when(tagApi.getTags(account.getId(), ObjectType.ACCOUNT)).thenReturn(tags);
+        assertEquals(tagApi.getTags(account.getId(), ObjectType.ACCOUNT), tags);
+
+        ((MockCatalog)catalogService.getFullCatalog()).setBillingAlignment(BillingAlignment.ACCOUNT);
+        
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService, tagApi);
+
+        BillingEventSet events = api.getBillingEventsForAccountAndUpdateAccountBCD(account.getId());
+        
+        assertEquals(events.isAccountAutoInvoiceOff(), true);
+        assertEquals(events.size(),0);
+    }
+
+    
+    @Test(enabled=true, groups="fast")
+    public void testBillingEventsAutoInvoicingOffBundle() throws CatalogApiException {
+        DateTime now = clock.getUTCNow();
+        DateTime then = now.minusDays(1);
+        Plan nextPlan = catalogService.getFullCatalog().findPlan("PickupTrialEvergreen10USD", now);
+        PlanPhase nextPhase = nextPlan.getAllPhases()[1];
+        PriceList nextPriceList = catalogService.getFullCatalog().findPriceList(PriceListSet.DEFAULT_PRICELIST_NAME, now);
+
+        SubscriptionEvent t = new MockSubscriptionEvent(
+                eventId, subId, bunId, then, now, null, null, null, null, SubscriptionState.ACTIVE, 
+                nextPlan.getName(), nextPhase.getName(), 
+                nextPriceList.getName(), 1L,null, 
+                SubscriptionTransitionType.CREATE, 0, null); 
+
+
+        subscriptionTransitions.add(t);
+
+        AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ((ZombieControl)account).addResult("getBillCycleDay", 32);
+        ((ZombieControl)account).addResult("getCurrency", Currency.USD);
+        ((ZombieControl)account).addResult("getId", UUID.randomUUID());
+        ((ZombieControl)accountApi).addResult("getAccountById", account);
+        
+         Map<String, Tag> tags = new HashMap<String, Tag>();
+        Tag aioTag = mock(Tag.class);
+        when(aioTag.getTagDefinitionName()).thenReturn(ControlTagType.AUTO_INVOICING_OFF.name());
+        tags.put(ControlTagType.AUTO_INVOICING_OFF.name(),aioTag);
+        when(tagApi.getTags(bunId, ObjectType.BUNDLE)).thenReturn(tags);
+ 
+        ((MockCatalog)catalogService.getFullCatalog()).setBillingAlignment(BillingAlignment.ACCOUNT);
+        
+        BillCycleDayCalculator bcdCalculator = new BillCycleDayCalculator(catalogService, entitlementApi);
+        CallContextFactory factory = new DefaultCallContextFactory(clock);
+        BillingApi api = new DefaultBillingApi(null, factory, accountApi, bcdCalculator, entitlementApi, blockCalculator, catalogService, tagApi);
+
+        BillingEventSet events = api.getBillingEventsForAccountAndUpdateAccountBCD(account.getId());
+        
+        assertEquals(events.getSubscriptionAndBundleIdsWithAutoInvoiceOff().size(), 1);
+        assertEquals(events.getSubscriptionAndBundleIdsWithAutoInvoiceOff().get(0), subId);
+        assertEquals(events.size(),0);
+    }
+
+    private void checkFirstEvent(SortedSet<BillingEvent> events, Plan nextPlan,
+            int BCD, UUID id, DateTime time, PlanPhase nextPhase, String desc) throws CatalogApiException {
+		Assert.assertEquals(events.size(), 1);
+		checkEvent(events.first(), nextPlan,
+	            BCD, id, time, nextPhase, desc, nextPhase.getFixedPrice(), nextPhase.getRecurringPrice());
+	}
+
+	private void checkEvent(BillingEvent event, Plan nextPlan,
+	            int BCD, UUID id, DateTime time, PlanPhase nextPhase, String desc, InternationalPrice fixedPrice, InternationalPrice recurringPrice) throws CatalogApiException {
+        if(fixedPrice != null) {
+			Assert.assertEquals(fixedPrice.getPrice(Currency.USD), event.getFixedPrice());
+        } else {
+            assertNull(event.getFixedPrice());
+		}
+
+		if(recurringPrice != null) {
+			Assert.assertEquals(recurringPrice.getPrice(Currency.USD), event.getRecurringPrice());
+        } else {
+            assertNull(event.getRecurringPrice());
+		}
+
+		Assert.assertEquals(BCD, event.getBillCycleDay());
+		Assert.assertEquals(id, event.getSubscription().getId());
+		Assert.assertEquals(time, event.getEffectiveDate());
+		Assert.assertEquals(nextPhase, event.getPlanPhase());
+		Assert.assertEquals(nextPlan, event.getPlan());
+		Assert.assertEquals(nextPhase.getBillingPeriod(), event.getBillingPeriod());
+		Assert.assertEquals(BillingModeType.IN_ADVANCE, event.getBillingMode());
+		Assert.assertEquals(desc, event.getTransitionType().toString());
+	}
+}