killbill-memoizeit

Rework of beatrix test testBasePlanComplete (Added CTD check) Fix

8/23/2012 5:57:23 PM

Changes

Details

diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
index 25a643f..f4902e7 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/ChargeThruApi.java
@@ -18,7 +18,7 @@ package com.ning.billing.entitlement.api.billing;
 
 import java.util.UUID;
 
-import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
 
 import com.ning.billing.util.callcontext.CallContext;
 
@@ -37,5 +37,5 @@ public interface ChargeThruApi {
      * @param ctd
      * @param context
      */
-    public void setChargedThroughDate(UUID subscriptionId, DateTime ctd, CallContext context);
+    public void setChargedThroughDate(UUID subscriptionId, LocalDate localChargedThruDate, CallContext context);
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java
index ed59b21..e82d1bd 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/BeatrixModule.java
@@ -35,6 +35,7 @@ import com.ning.billing.beatrix.integration.overdue.IntegrationTestOverdueModule
 import com.ning.billing.beatrix.lifecycle.DefaultLifecycle;
 import com.ning.billing.beatrix.lifecycle.Lifecycle;
 import com.ning.billing.beatrix.util.InvoiceChecker;
+import com.ning.billing.beatrix.util.PaymentChecker;
 import com.ning.billing.catalog.api.CatalogService;
 import com.ning.billing.catalog.glue.CatalogModule;
 import com.ning.billing.config.PaymentConfig;
@@ -108,6 +109,7 @@ public class BeatrixModule extends AbstractModule {
         install(new IntegrationTestOverdueModule());
 
         bind(InvoiceChecker.class).asEagerSingleton();
+        bind(PaymentChecker.class).asEagerSingleton();
     }
 
     private static final class PaymentPluginMockModule extends PaymentModule {
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index 9401b39..afeb117 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -365,48 +365,44 @@ public class TestIntegration extends TestIntegrationBase {
         clock.setDeltaFromReality(initialCreationDate.getMillis() - clock.getUTCNow().getMillis());
         final SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", context);
 
+        int invoiceItemCount = 1;
 
         //
         // CREATE SUBSCRIPTION AND EXPECT BOTH EVENTS: NextEvent.CREATE NextEvent.INVOICE
         //
         SubscriptionData subscription = subscriptionDataFromSubscription(createSubscriptionAndCheckForCompletion(bundle.getId(), "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.INVOICE));
-        invoiceChecker.checkInvoice(account.getId(), 1, new ExpectedItemCheck(initialCreationDate.toLocalDate(), null, InvoiceItemType.FIXED, new BigDecimal("0")));
-
-        //
-        // VERIFY CTD HAS BEEN SET
-        //
-        DateTime startDate = subscription.getCurrentPhaseStart();
-        BigDecimal rate = subscription.getCurrentPhase().getFixedPrice().getPrice(Currency.USD);
-        int invoiceItemCount = 1;
+        invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, new ExpectedItemCheck(initialCreationDate.toLocalDate(), null, InvoiceItemType.FIXED, new BigDecimal("0")));
         // No end date for the trial item (fixed price of zero), and CTD should be today (i.e. when the trial started)
-        verifyTestResult(accountId, subscription.getId(), startDate, null, rate, clock.getUTCNow(), invoiceItemCount);
+        invoiceChecker.checkChargedThroughDate(subscription.getId(), clock.getUTCToday());
 
         //
         // CHANGE PLAN IMMEDIATELY AND EXPECT BOTH EVENTS: NextEvent.CHANGE NextEvent.INVOICE
         //
         subscription = subscriptionDataFromSubscription(changeSubscriptionAndCheckForCompletion(subscription, "Assault-Rifle", BillingPeriod.MONTHLY, NextEvent.CHANGE, NextEvent.INVOICE));
+        invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, new ExpectedItemCheck(initialCreationDate.toLocalDate(), null, InvoiceItemType.FIXED, new BigDecimal("0")));
+        invoiceChecker.checkChargedThroughDate(subscription.getId(), clock.getUTCToday());
 
         //
         // VERIFY AGAIN CTD HAS BEEN SET
         //
-        startDate = subscription.getCurrentPhaseStart();
-        invoiceItemCount = 2;
-        // No end date for the trial item (fixed price of zero), and CTD should be today (i.e. when the second trial started)
-        verifyTestResult(accountId, subscription.getId(), startDate, null, rate, clock.getUTCNow(), invoiceItemCount);
+        DateTime startDate = subscription.getCurrentPhaseStart();
 
         //
         // MOVE TIME
         //
+        final LocalDate firstRecurringDate = initialCreationDate.toLocalDate().plusDays(30);
+        final LocalDate secondRecurringDate = firstRecurringDate.plusMonths(1);
         for (final DateTime dateTimeToSet : expectedStates.keySet()) {
-            for (final NextEvent expectedEvent : expectedStates.get(dateTimeToSet)) {
-                busHandler.pushExpectedEvent(expectedEvent);
+            setDateAndCheckForCompletion(dateTimeToSet, expectedStates.get(dateTimeToSet));
+            if (expectedStates.get(dateTimeToSet).contains(NextEvent.INVOICE)) {
+                // STEPH date with BCD
+                invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, new ExpectedItemCheck(firstRecurringDate, secondRecurringDate, InvoiceItemType.RECURRING, new BigDecimal("599.95")));
+                invoiceChecker.checkChargedThroughDate(subscription.getId(), secondRecurringDate);
             }
-            clock.setTime(dateTimeToSet);
-            assertTrue(busHandler.isCompleted(DELAY));
         }
 
         startDate = subscription.getCurrentPhaseStart();
-        rate = subscription.getCurrentPhase().getRecurringPrice().getPrice(Currency.USD);
+        BigDecimal rate = subscription.getCurrentPhase().getRecurringPrice().getPrice(Currency.USD);
         BigDecimal price;
         final DateTime chargeThroughDate;
 
@@ -415,14 +411,12 @@ public class TestIntegration extends TestIntegrationBase {
                 // this will result in a 30-day pro-ration
                 price = THIRTY.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD).multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
                 chargeThroughDate = startDate.plusMonths(1).toMutableDateTime().dayOfMonth().set(billingDay).toDateTime();
-                invoiceItemCount += 1;
                 verifyTestResult(accountId, subscription.getId(), startDate, chargeThroughDate, price, chargeThroughDate, invoiceItemCount);
                 break;
             case 2:
                 // this will result in one full-period invoice item
                 price = rate;
                 chargeThroughDate = startDate.plusMonths(1);
-                invoiceItemCount += 1;
                 verifyTestResult(accountId, subscription.getId(), startDate, chargeThroughDate, price, chargeThroughDate, invoiceItemCount);
                 break;
             case 3:
@@ -430,7 +424,8 @@ public class TestIntegration extends TestIntegrationBase {
                 price = ONE.divide(TWENTY_NINE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD).multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
                 final DateTime firstEndDate = startDate.plusDays(1);
                 chargeThroughDate = firstEndDate.plusMonths(1);
-                invoiceItemCount += 2;
+                // STEPH TO BE CHECKED LATER
+                invoiceItemCount++;
                 verifyTestResult(accountId, subscription.getId(), startDate, firstEndDate, price, chargeThroughDate, invoiceItemCount);
                 verifyTestResult(accountId, subscription.getId(), firstEndDate, chargeThroughDate, rate, chargeThroughDate, invoiceItemCount);
                 break;
@@ -453,7 +448,11 @@ public class TestIntegration extends TestIntegrationBase {
         //
         // MOVE TIME AFTER CTD AND EXPECT BOTH EVENTS : NextEvent.CHANGE NextEvent.INVOICE
         //
+        final LocalDate firstRecurringPistolDate = firstRecurringDate.plusMonths(1);
+        final LocalDate secondRecurringPistolDate = firstRecurringPistolDate.plusMonths(1);
         addDaysAndCheckForCompletion(32, NextEvent.CHANGE, NextEvent.INVOICE, NextEvent.PAYMENT);
+        invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, new ExpectedItemCheck(firstRecurringPistolDate, secondRecurringPistolDate, InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+        invoiceChecker.checkChargedThroughDate(subscription.getId(), secondRecurringPistolDate);
 
         startDate = chargeThroughDate;
 
@@ -461,30 +460,30 @@ public class TestIntegration extends TestIntegrationBase {
         DateTime realChargeThroughDate = entitlementUserApi.getSubscriptionFromId(subscription.getId()).getChargedThroughDate();
         DateTime endDate = realChargeThroughDate;
         price = subscription.getCurrentPhase().getRecurringPrice().getPrice(Currency.USD);
-        invoiceItemCount += 1;
-        verifyTestResult(accountId, subscription.getId(), startDate, endDate, price, endDate, invoiceItemCount);
 
         //
         // MOVE TIME AFTER NEXT BILL CYCLE DAY AND EXPECT EVENT : NextEvent.INVOICE
         //
+
+        LocalDate prevRecurringDate = secondRecurringPistolDate;
         int maxCycles = 3;
         do {
-            busHandler.pushExpectedEvent(NextEvent.INVOICE);
-            busHandler.pushExpectedEvent(NextEvent.PAYMENT);
-            clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 1000);
-            assertTrue(busHandler.isCompleted(DELAY));
 
-            startDate = endDate;
-            endDate = startDate.plusMonths(1);
+            LocalDate nextRecurringDate = prevRecurringDate.plusMonths(1);
             if (endDate.dayOfMonth().get() != billingDay) {
                 // adjust for end of month issues
                 final int maximumDay = endDate.dayOfMonth().getMaximumValue();
                 final int newDay = (maximumDay < billingDay) ? maximumDay : billingDay;
                 endDate = endDate.toMutableDateTime().dayOfMonth().set(newDay).toDateTime();
+                nextRecurringDate = endDate.toLocalDate();
             }
 
-            invoiceItemCount += 1;
-            verifyTestResult(accountId, subscription.getId(), startDate, endDate, price, endDate, invoiceItemCount);
+
+            addDaysAndCheckForCompletion(32, NextEvent.INVOICE, NextEvent.PAYMENT);
+            invoiceChecker.checkInvoice(account.getId(), invoiceItemCount++, new ExpectedItemCheck(prevRecurringDate, nextRecurringDate, InvoiceItemType.RECURRING, new BigDecimal("29.95")));
+            invoiceChecker.checkChargedThroughDate(subscription.getId(), nextRecurringDate);
+
+            prevRecurringDate = nextRecurringDate;
         } while (maxCycles-- > 0);
 
         //
@@ -495,8 +494,7 @@ public class TestIntegration extends TestIntegrationBase {
 
         // MOVE AFTER CANCEL DATE AND EXPECT EVENT : NextEvent.CANCEL
         realChargeThroughDate = entitlementUserApi.getSubscriptionFromId(subscription.getId()).getChargedThroughDate();
-        final Interval it = new Interval(clock.getUTCNow(), realChargeThroughDate.plusSeconds(5));
-        addDaysAndCheckForCompletion((int) it.toDuration().getStandardDays(), NextEvent.CANCEL);
+        setDateAndCheckForCompletion(realChargeThroughDate.plusSeconds(5), NextEvent.CANCEL);
 
         //
         // CHECK AGAIN THERE IS NO MORE INVOICES GENERATED
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
index 6837c43..150a971 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
+import org.joda.time.Interval;
 import org.joda.time.LocalDate;
 import org.skife.jdbi.v2.IDBI;
 import org.slf4j.Logger;
@@ -46,6 +47,7 @@ import com.ning.billing.api.TestListenerStatus;
 import com.ning.billing.beatrix.BeatrixTestSuiteWithEmbeddedDB;
 import com.ning.billing.beatrix.lifecycle.Lifecycle;
 import com.ning.billing.beatrix.util.InvoiceChecker;
+import com.ning.billing.beatrix.util.PaymentChecker;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
@@ -82,6 +84,7 @@ import com.ning.billing.util.callcontext.UserType;
 import com.ning.billing.util.clock.ClockMock;
 
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.inject.Inject;
 import com.google.inject.name.Named;
 
@@ -170,6 +173,9 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
     @Inject
     protected InvoiceChecker invoiceChecker;
 
+    @Inject
+    protected PaymentChecker paymentChecker;
+
     protected TestApiListener busHandler;
 
     private boolean isListenerFailed;
@@ -230,6 +236,8 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
             final int totalInvoiceItemCount) throws EntitlementUserApiException {
         final SubscriptionData subscription = subscriptionDataFromSubscription(entitlementUserApi.getSubscriptionFromId(subscriptionId));
 
+
+        /*
         final List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(accountId);
         final List<InvoiceItem> invoiceItems = new ArrayList<InvoiceItem>();
         for (final Invoice invoice : invoices) {
@@ -254,7 +262,7 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
         if (!wasFound) {
             fail();
         }
-
+*/
         final DateTime ctd = subscription.getChargedThroughDate();
         assertNotNull(ctd);
         log.info("Checking CTD: " + ctd.toString() + "; clock is " + clock.getUTCNow().toString());
@@ -322,6 +330,23 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
         }, events);
     }
 
+    protected void setDateAndCheckForCompletion(final DateTime date, final List<NextEvent> events) {
+        setDateAndCheckForCompletion(date, events.toArray(new NextEvent[events.size()]));
+    }
+
+    protected void setDateAndCheckForCompletion(final DateTime date, final NextEvent... events) {
+        doCallAndCheckForCompletion(new Function<Void, Void>() {
+            @Override
+            public Void apply(@Nullable final Void dontcare) {
+                //final Interval it = new Interval(clock.getUTCNow(), date);
+                //final int days = it.toPeriod().toStandardDays().getDays();
+                clock.setTime(date);
+                return null;
+            }
+        }, events);
+    }
+
+
     protected void addDaysAndCheckForCompletion(final int nbDays, final NextEvent... events) {
         doCallAndCheckForCompletion(new Function<Void, Void>() {
             @Override
@@ -409,12 +434,14 @@ public class TestIntegrationBase extends BeatrixTestSuiteWithEmbeddedDB implemen
     }
 
     private <T> T doCallAndCheckForCompletion(Function<Void, T> f, final NextEvent... events) {
-        log.info("            ************    STARTING BUS HANDLER CHECK    ********************");
+
+        Joiner joiner = Joiner.on(", ");
+        log.info("            ************    STARTING BUS HANDLER CHECK : {} ********************", joiner.join(events));
 
         busHandler.pushExpectedEvents(events);
 
         final T result = f.apply(null);
-        assertTrue(busHandler.isCompleted(DELAY));
+        assertTrue(busHandler.isCompleted(DELAY), "Were expecting events " + joiner.join(events));
         assertListenerStatus();
 
         log.info("            ************    DONE WITH BUS HANDLER CHECK    ********************");
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java b/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java
index f098895..ff86dce 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/util/InvoiceChecker.java
@@ -16,15 +16,26 @@
 
 package com.ning.billing.beatrix.util;
 
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
 import java.math.BigDecimal;
 import java.util.List;
 import java.util.UUID;
 
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
+import org.joda.time.LocalTime;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.Assert;
 
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoiceItemType;
@@ -38,10 +49,12 @@ public class InvoiceChecker {
     private static final Logger log = LoggerFactory.getLogger(InvoiceChecker.class);
 
     private final InvoiceUserApi invoiceUserApi;
+    private final EntitlementUserApi entitlementApi;
 
     @Inject
-    public InvoiceChecker(final InvoiceUserApi invoiceUserApi) {
+    public InvoiceChecker(final InvoiceUserApi invoiceUserApi, final EntitlementUserApi entitlementApi) {
         this.invoiceUserApi = invoiceUserApi;
+        this.entitlementApi = entitlementApi;
     }
 
     public void checkInvoice(final UUID accountId, final int invoiceOrderingNumber, final ExpectedItemCheck... expected) {
@@ -89,6 +102,29 @@ public class InvoiceChecker {
         }
     }
 
+
+    public void checkNullChargedThroughDate(final UUID subscriptionId) {
+        checkChargedThroughDate(subscriptionId, null);
+    }
+
+    public void checkChargedThroughDate(final UUID subscriptionId, final LocalDate expectedLocalCTD) {
+        try {
+            Subscription subscription = entitlementApi.getSubscriptionFromId(subscriptionId);
+            if (expectedLocalCTD == null) {
+                assertNull(subscription.getChargedThroughDate());
+            } else {
+                final DateTime expectedCTD = expectedLocalCTD.toDateTime(new LocalTime(subscription.getStartDate().getMillis()), DateTimeZone.UTC);
+                final String msg = String.format("Checking CTD for subscription %s : expectedLocalCTD = %s => expectedCTD = %s, got %s",
+                        subscriptionId, expectedLocalCTD, expectedCTD, subscription.getChargedThroughDate());
+                log.info(msg);
+                assertNotNull(subscription.getChargedThroughDate());
+                assertTrue(subscription.getChargedThroughDate().compareTo(expectedCTD) == 0, msg);
+            }
+        } catch (EntitlementUserApiException e) {
+            fail("Failed to retrieve subscription for " + subscriptionId);
+        }
+    }
+
     public static class ExpectedItemCheck {
 
         private final LocalDate startDate;
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
index 8468183..f06224c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultChargeThruApi.java
@@ -19,6 +19,8 @@ package com.ning.billing.entitlement.api.billing;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
+import org.joda.time.LocalTime;
 
 import com.google.inject.Inject;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
@@ -44,11 +46,11 @@ public class DefaultChargeThruApi implements ChargeThruApi {
     }
 
     @Override
-    public void setChargedThroughDate(final UUID subscriptionId, final DateTime ctd, final CallContext context) {
+    public void setChargedThroughDate(final UUID subscriptionId, final LocalDate ctd, final CallContext context) {
         final SubscriptionData subscription = (SubscriptionData) entitlementDao.getSubscriptionFromId(subscriptionFactory, subscriptionId);
-
+        final DateTime chargedThroughDate = ctd.toDateTime(new LocalTime(subscription.getStartDate()));
         final SubscriptionBuilder builder = new SubscriptionBuilder(subscription)
-                .setChargedThroughDate(ctd)
+                .setChargedThroughDate(chargedThroughDate)
                 .setPaidThroughDate(subscription.getPaidThroughDate());
         entitlementDao.updateChargedThroughDate(new SubscriptionData(builder), context);
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
index 0d73825..0593c2a 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairBP.java
@@ -583,7 +583,7 @@ public class TestRepairBP extends TestApiBaseRepair {
 
         // SET CTD to BASE SUBSCRIPTION SP CANCEL OCCURS EOT
         final DateTime newChargedThroughDate = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
-        billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, context);
+        billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate.toLocalDate(), context);
         baseSubscription = entitlementApi.getSubscriptionFromId(baseSubscription.getId());
 
         final DateTime requestedChange = clock.getUTCNow();
@@ -696,7 +696,7 @@ public class TestRepairBP extends TestApiBaseRepair {
                 // Move clock at least a sec to make sure the last_sys_update from bundle is different-- and therefore generates a different viewId
                 clock.setDeltaFromReality(1000);
 
-                billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, context);
+                billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate.toLocalDate(), context);
                 entitlementApi.getSubscriptionFromId(baseSubscription.getId());
 
                 repairApi.repairBundle(bRepair, true, context);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
index 661f960..c1159c6 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/timeline/TestRepairWithAO.java
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright 2010-2011 Ning, Inc.
  *
  * Ning licenses this file to you under the Apache License, version 2.0
@@ -133,7 +133,7 @@ public class TestRepairWithAO extends TestApiBaseRepair {
             validateExistingEventForAssertion(e, aoRepair2.getExistingEvents().get(index++));
         }
 
-        // Check expected for BP        
+        // Check expected for BP
         final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionTimeline.ExistingEvent>();
         expectedBP.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, "Shotgun", PhaseType.TRIAL,
                                                        ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
@@ -267,7 +267,7 @@ public class TestRepairWithAO extends TestApiBaseRepair {
             validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
 
-        // Check expected for BP        
+        // Check expected for BP
         final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionTimeline.ExistingEvent>();
         expectedBP.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, "Shotgun", PhaseType.TRIAL,
                                                        ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
@@ -347,7 +347,7 @@ public class TestRepairWithAO extends TestApiBaseRepair {
 
         // SET CTD to BASE SUBSCRIPTION SP CANCEL OCCURS EOT
         final DateTime newChargedThroughDate = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
-        billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, context);
+        billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate.toLocalDate(), context);
         baseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
 
         BundleTimeline bundleRepair = repairApi.getBundleTimeline(bundle.getId());
@@ -388,7 +388,7 @@ public class TestRepairWithAO extends TestApiBaseRepair {
             validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));
         }
 
-        // Check expected for BP        
+        // Check expected for BP
         final List<ExistingEvent> expectedBP = new LinkedList<SubscriptionTimeline.ExistingEvent>();
         expectedBP.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, "Shotgun", PhaseType.TRIAL,
                                                        ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java
index 96aa1ec..6074c5e 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/transfer/TestTransfer.java
@@ -119,7 +119,7 @@ public class TestTransfer extends TestApiBase {
         final Subscription baseSubscription = createSubscription(baseProduct, baseTerm, basePriceList);
         final DateTime ctd = baseSubscription.getStartDate().plusDays(30);
 
-        billingApi.setChargedThroughDate(baseSubscription.getId(), ctd, context);
+        billingApi.setChargedThroughDate(baseSubscription.getId(), ctd.toLocalDate(), context);
 
         final DateTime evergreenPhaseDate = baseSubscription.getPendingTransition().getEffectiveTransitionTime();
 
@@ -222,7 +222,7 @@ public class TestTransfer extends TestApiBase {
 
         // SET CTD
         final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
-        billingApi.setChargedThroughDate(baseSubscription.getId(), ctd, context);
+        billingApi.setChargedThroughDate(baseSubscription.getId(), ctd.toLocalDate(), context);
 
 
         final DateTime transferRequestedDate = clock.getUTCNow();
@@ -267,7 +267,7 @@ public class TestTransfer extends TestApiBase {
         clock.addDays(2);
 
         DateTime newCtd = newBaseSubscription.getStartDate().plusYears(1);
-        billingApi.setChargedThroughDate(newBaseSubscription.getId(), newCtd, context);
+        billingApi.setChargedThroughDate(newBaseSubscription.getId(), newCtd.toLocalDate(), context);
         final Subscription newBaseSubscriptionWithCtd = entitlementApi.getSubscriptionFromId(newBaseSubscription.getId());
 
         final String newBaseProduct2 = "Pistol";
@@ -318,7 +318,7 @@ public class TestTransfer extends TestApiBase {
 
         // SET CTD TO TRIGGER CANCELLATION EOT
         final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
-        billingApi.setChargedThroughDate(baseSubscription.getId(), ctd, context);
+        billingApi.setChargedThroughDate(baseSubscription.getId(), ctd.toLocalDate(), context);
 
         final DateTime transferRequestedDate = clock.getUTCNow();
         testListener.pushExpectedEvent(NextEvent.TRANSFER);
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
index 2571b6f..2ec89a3 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiAddOn.java
@@ -115,7 +115,7 @@ public class TestUserApiAddOn extends TestApiBase {
             final Duration ctd = getDurationMonth(1);
             // Why not just use clock.getUTCNow().plusMonths(1) ?
             final DateTime newChargedThroughDate = DefaultClock.addDuration(now, ctd);
-            billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate.toLocalDate(), context);
             baseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
 
             // FUTURE CANCELLATION
@@ -175,7 +175,7 @@ public class TestUserApiAddOn extends TestApiBase {
             final DateTime now = clock.getUTCNow();
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(now, ctd);
-            billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate.toLocalDate(), context);
             baseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
 
             // CHANGE IMMEDIATELY WITH TO BP WITH NON INCLUDED ADDON
@@ -237,7 +237,7 @@ public class TestUserApiAddOn extends TestApiBase {
             final DateTime now = clock.getUTCNow();
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(now, ctd);
-            billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(baseSubscription.getId(), newChargedThroughDate.toLocalDate(), context);
             baseSubscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(baseSubscription.getId());
 
             // CHANGE IMMEDIATELY WITH TO BP WITH NON AVAILABLE ADDON
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
index 9eee156..8e70eee 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiCancel.java
@@ -110,7 +110,7 @@ public abstract class TestUserApiCancel extends TestApiBase {
             // SET CTD + RE READ SUBSCRIPTION + CHANGE PLAN
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(expectedPhaseTrialChange, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             assertEquals(subscription.getLastActiveProductName(), prod);
@@ -228,7 +228,7 @@ public abstract class TestUserApiCancel extends TestApiBase {
             // SET CTD + RE READ SUBSCRIPTION + CHANGE PLAN
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(expectedPhaseTrialChange, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             // CANCEL EOT
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
index 72573e3..577a776 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiChangePlan.java
@@ -118,7 +118,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
             // SET CTD
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(expectedPhaseTrialChange, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
 
             // RE READ SUBSCRIPTION + CHANGE PLAN
             testListener.setNonExpectedMode();
@@ -221,7 +221,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
             // SET CTD
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(expectedPhaseTrialChange, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
 
             // RE READ SUBSCRIPTION + CHECK CURRENT PHASE
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
@@ -302,7 +302,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
             final DateTime startDiscountPhase = DefaultClock.addDuration(subscription.getStartDate(), durationList);
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(startDiscountPhase, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             // CHANGE EOT
@@ -350,7 +350,7 @@ public abstract class TestUserApiChangePlan extends TestApiBase {
             final DateTime startDiscountPhase = DefaultClock.addDuration(subscription.getStartDate(), durationList);
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(startDiscountPhase, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             // CHANGE EOT
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
index d2d33c4..dffd3de 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiDemos.java
@@ -100,7 +100,7 @@ public class TestUserApiDemos extends TestApiBase {
 
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(startDiscountPhase, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             testListener.setNonExpectedMode();
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
index adcddbc..3beb9a9 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiError.java
@@ -195,7 +195,7 @@ public class TestUserApiError extends TestApiBase {
             final DateTime expectedPhaseTrialChange = DefaultClock.addDuration(subscription.getStartDate(), trialPhase.getDuration());
             final Duration ctd = getDurationMonth(1);
             final DateTime newChargedThroughDate = DefaultClock.addDuration(expectedPhaseTrialChange, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
 
             subscription = entitlementApi.getSubscriptionFromId(subscription.getId());
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
index f679b73..e53c706 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/user/TestUserApiScenarios.java
@@ -65,7 +65,7 @@ public class TestUserApiScenarios extends TestApiBase {
             final Duration ctd = getDurationMonth(1);
             final DateTime expectedPhaseTrialChange = DefaultClock.addDuration(subscription.getStartDate(), trialPhase.getDuration());
             final DateTime newChargedThroughDate = DefaultClock.addDuration(expectedPhaseTrialChange, ctd);
-            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate, context);
+            billingApi.setChargedThroughDate(subscription.getId(), newChargedThroughDate.toLocalDate(), context);
             subscription = (SubscriptionData) entitlementApi.getSubscriptionFromId(subscription.getId());
 
             // CANCEL EOT
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
index 81636fe..27ce936 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -84,12 +84,12 @@ public class InvoiceDispatcher {
 
     @Inject
     public InvoiceDispatcher(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
-                             final BillingApi billingApi,
-                             final InvoiceDao invoiceDao,
-                             final InvoiceNotifier invoiceNotifier,
-                             final GlobalLocker locker,
-                             final Bus eventBus,
-                             final Clock clock) {
+            final BillingApi billingApi,
+            final InvoiceDao invoiceDao,
+            final InvoiceNotifier invoiceNotifier,
+            final GlobalLocker locker,
+            final Bus eventBus,
+            final Clock clock) {
         this.generator = generator;
         this.billingApi = billingApi;
         this.accountUserApi = accountUserApi;
@@ -104,7 +104,7 @@ public class InvoiceDispatcher {
     }
 
     public void processSubscription(final EffectiveSubscriptionEvent transition,
-                                    final CallContext context) throws InvoiceApiException {
+            final CallContext context) throws InvoiceApiException {
         final UUID subscriptionId = transition.getSubscriptionId();
         final DateTime targetDate = transition.getEffectiveTransitionTime();
         log.info("Got subscription transition: type: " + transition.getTransitionType().toString() + "; id: " + subscriptionId.toString() + "; targetDate: " + targetDate.toString());
@@ -112,7 +112,7 @@ public class InvoiceDispatcher {
     }
 
     public void processSubscription(final UUID subscriptionId, final DateTime targetDate,
-                                    final CallContext context) throws InvoiceApiException {
+            final CallContext context) throws InvoiceApiException {
         try {
             if (subscriptionId == null) {
                 log.error("Failed handling entitlement change.", new InvoiceApiException(ErrorCode.INVOICE_INVALID_TRANSITION));
@@ -122,12 +122,12 @@ public class InvoiceDispatcher {
             processAccount(accountId, targetDate, false, context);
         } catch (EntitlementBillingApiException e) {
             log.error("Failed handling entitlement change.",
-                      new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
+                    new InvoiceApiException(ErrorCode.INVOICE_NO_ACCOUNT_ID_FOR_SUBSCRIPTION_ID, subscriptionId.toString()));
         }
     }
 
     public Invoice processAccount(final UUID accountId, final DateTime targetDate,
-                                  final boolean dryRun, final CallContext context) throws InvoiceApiException {
+            final boolean dryRun, final CallContext context) throws InvoiceApiException {
         GlobalLock lock = null;
         try {
             lock = locker.lockWithNumberOfTries(LockerType.ACCOUNT, accountId.toString(), NB_LOCK_TRY);
@@ -136,7 +136,7 @@ public class InvoiceDispatcher {
         } catch (LockFailedException e) {
             // Not good!
             log.error(String.format("Failed to process invoice for account %s, targetDate %s",
-                                    accountId.toString(), targetDate), e);
+                    accountId.toString(), targetDate), e);
         } finally {
             if (lock != null) {
                 lock.release();
@@ -146,7 +146,7 @@ public class InvoiceDispatcher {
     }
 
     private Invoice processAccountWithLock(final UUID accountId, final DateTime targetDateTime,
-                                           final boolean dryRun, final CallContext context) throws InvoiceApiException {
+            final boolean dryRun, final CallContext context) throws InvoiceApiException {
         try {
             // Make sure to first set the BCD if needed then get the account object (to have the BCD set)
             final BillingEventSet billingEvents = billingApi.getBillingEventsForAccountAndUpdateAccountBCD(accountId);
@@ -194,11 +194,11 @@ public class InvoiceDispatcher {
 
                     final List<InvoiceItem> fixedPriceInvoiceItems = invoice.getInvoiceItems(FixedPriceInvoiceItem.class);
                     final List<InvoiceItem> recurringInvoiceItems = invoice.getInvoiceItems(RecurringInvoiceItem.class);
-                    setChargedThroughDates(account.getBillCycleDay(), fixedPriceInvoiceItems, recurringInvoiceItems, context);
+                    setChargedThroughDates(account.getBillCycleDay(), account.getTimeZone(), fixedPriceInvoiceItems, recurringInvoiceItems, context);
 
                     final InvoiceCreationEvent event = new DefaultInvoiceCreationEvent(invoice.getId(), invoice.getAccountId(),
-                                                                                       invoice.getBalance(), invoice.getCurrency(),
-                                                                                       context.getUserToken());
+                            invoice.getBalance(), invoice.getCurrency(),
+                            context.getUserToken());
 
                     if (isRealInvoiceWithItems) {
                         postEvent(event, accountId);
@@ -218,17 +218,17 @@ public class InvoiceDispatcher {
     }
 
     private void setChargedThroughDates(final BillCycleDay billCycleDay,
-                                        final Collection<InvoiceItem> fixedPriceItems,
-                                        final Collection<InvoiceItem> recurringItems,
-                                        final CallContext context) {
-        // TODO - this should be handled by entitlement
-        final Map<UUID, DateTime> chargeThroughDates = new HashMap<UUID, DateTime>();
-        addInvoiceItemsToChargeThroughDates(billCycleDay, chargeThroughDates, fixedPriceItems);
-        addInvoiceItemsToChargeThroughDates(billCycleDay, chargeThroughDates, recurringItems);
+            final DateTimeZone accountTimeZone,
+            final Collection<InvoiceItem> fixedPriceItems,
+            final Collection<InvoiceItem> recurringItems,
+            final CallContext context) {
+        final Map<UUID, LocalDate> chargeThroughDates = new HashMap<UUID, LocalDate>();
+        addInvoiceItemsToChargeThroughDates(billCycleDay, accountTimeZone, chargeThroughDates, fixedPriceItems);
+        addInvoiceItemsToChargeThroughDates(billCycleDay, accountTimeZone, chargeThroughDates, recurringItems);
 
         for (final UUID subscriptionId : chargeThroughDates.keySet()) {
             if (subscriptionId != null) {
-                final DateTime chargeThroughDate = chargeThroughDates.get(subscriptionId);
+                final LocalDate chargeThroughDate = chargeThroughDates.get(subscriptionId);
                 log.info("Setting CTD for subscription {} to {}", subscriptionId.toString(), chargeThroughDate.toString());
                 billingApi.setChargedThroughDate(subscriptionId, chargeThroughDate, context);
             }
@@ -244,22 +244,18 @@ public class InvoiceDispatcher {
     }
 
     private void addInvoiceItemsToChargeThroughDates(final BillCycleDay billCycleDay,
-                                                     final Map<UUID, DateTime> chargeThroughDates,
-                                                     final Collection<InvoiceItem> items) {
+            final DateTimeZone accountTimeZone,
+            final Map<UUID, LocalDate> chargeThroughDates,
+            final Collection<InvoiceItem> items) {
+
         for (final InvoiceItem item : items) {
             final UUID subscriptionId = item.getSubscriptionId();
-            final DateTime endDate;
-            if (item.getEndDate() != null) {
-                endDate = new DateTime(item.getEndDate().toDateTime(clock.getUTCNow()) , DateTimeZone.UTC);
-            } else {
-                // item end date is null for fixed price items for instance
-                endDate = new DateTime(item.getStartDate().toDateTime(clock.getUTCNow()), DateTimeZone.UTC);
-            }
+            final LocalDate endDate = (item.getEndDate() != null) ? item.getEndDate() : item.getStartDate();
 
             if (chargeThroughDates.containsKey(subscriptionId)) {
                 if (chargeThroughDates.get(subscriptionId).isBefore(endDate)) {
                     // The CTD should always align with the BCD
-                    final DateTime ctd = InvoiceDateUtils.calculateBillingCycleDateOnOrAfter(endDate, billCycleDay.getDayOfMonthLocal());
+                    final LocalDate ctd = InvoiceDateUtils.calculateBillingCycleDateOnOrAfter(endDate, accountTimeZone, billCycleDay.getDayOfMonthLocal());
                     chargeThroughDates.put(subscriptionId, ctd);
                 }
             } else {
diff --git a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
index 19f0f28..9d30ca4 100644
--- a/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
+++ b/junction/src/main/java/com/ning/billing/junction/plumbing/billing/DefaultBillingApi.java
@@ -22,6 +22,7 @@ import java.util.SortedSet;
 import java.util.UUID;
 
 import org.joda.time.DateTime;
+import org.joda.time.LocalDate;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -178,7 +179,7 @@ public class DefaultBillingApi implements BillingApi {
     }
 
     @Override
-    public void setChargedThroughDate(final UUID subscriptionId, final DateTime ctd, final CallContext context) {
+    public void setChargedThroughDate(final UUID subscriptionId, final LocalDate ctd, final CallContext context) {
         chargeThruApi.setChargedThroughDate(subscriptionId, ctd, context);
     }
 }