killbill-memoizeit

Changes

Details

diff --git a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
index 1e00dba..623aa01 100644
--- a/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
+++ b/account/src/main/java/com/ning/billing/account/dao/DefaultAccountDao.java
@@ -16,6 +16,7 @@
 
 package com.ning.billing.account.dao;
 
+import java.sql.DataTruncation;
 import java.util.List;
 import java.util.UUID;
 
@@ -89,7 +90,6 @@ public class DefaultAccountDao implements AccountDao {
     public void create(final Account account) throws AccountApiException {
         final String key = account.getExternalKey();
         try {
-
             accountSqlDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
                 @Override
                 public Void inTransaction(final AccountSqlDao transactionalDao, final TransactionStatus status) throws AccountApiException, Bus.EventBusException {
@@ -109,6 +109,8 @@ public class DefaultAccountDao implements AccountDao {
         } catch (RuntimeException re) {
             if (re.getCause() instanceof AccountApiException) {
                 throw (AccountApiException) re.getCause();
+            } else if (re.getCause() instanceof DataTruncation) {
+                throw new AccountApiException(ErrorCode.DATA_TRUNCATION, re.getCause().getMessage());
             } else {
                 throw re;
             }
diff --git a/account/src/main/resources/com/ning/billing/account/ddl.sql b/account/src/main/resources/com/ning/billing/account/ddl.sql
index 58b47f0..fd2f6f8 100644
--- a/account/src/main/resources/com/ning/billing/account/ddl.sql
+++ b/account/src/main/resources/com/ning/billing/account/ddl.sql
@@ -17,7 +17,7 @@ CREATE TABLE accounts (
     state_or_province varchar(50) DEFAULT NULL,
     country varchar(50) DEFAULT NULL,
     postal_code varchar(11) DEFAULT NULL,
-    phone varchar(13) DEFAULT NULL,
+    phone varchar(25) DEFAULT NULL,
     created_dt datetime,
     updated_dt datetime,
     PRIMARY KEY(id)
@@ -25,3 +25,48 @@ CREATE TABLE accounts (
 CREATE UNIQUE INDEX accounts_external_key ON accounts(external_key);
 CREATE UNIQUE INDEX accounts_email ON accounts(email);
 
+DROP TABLE IF EXISTS account_history;
+CREATE TABLE account_history (
+    id char(36) NOT NULL,
+    external_key varchar(128) NULL,
+    email varchar(50) NOT NULL,
+    name varchar(100) NOT NULL,
+    first_name_length int NOT NULL,
+    currency char(3) DEFAULT NULL,
+    billing_cycle_day int DEFAULT NULL,
+    payment_provider_name varchar(20) DEFAULT NULL,
+    time_zone varchar(50) DEFAULT NULL,
+    locale varchar(5) DEFAULT NULL,
+    address1 varchar(100) DEFAULT NULL,
+    address2 varchar(100) DEFAULT NULL,
+    company_name varchar(50) DEFAULT NULL,
+    city varchar(50) DEFAULT NULL,
+    state_or_province varchar(50) DEFAULT NULL,
+    country varchar(50) DEFAULT NULL,
+    postal_code varchar(11) DEFAULT NULL,
+    phone varchar(25) DEFAULT NULL,
+    date datetime
+) ENGINE=innodb;
+CREATE INDEX account_id ON account_history(id);
+
+CREATE TRIGGER store_account_history_on_insert AFTER INSERT ON accounts
+    FOR EACH ROW
+        INSERT INTO account_history (id, external_key, email, name, first_name_length, currency,
+                                    billing_cycle_day, payment_provider_name, time_zone, locale, 
+                                    address1, address2, company_name, city, state_or_province, 
+                                    country, postal_code, phone, date)
+        VALUES (NEW.id, NEW.external_key, NEW.email, NEW.name, NEW.first_name_length, NEW.currency,
+                NEW.billing_cycle_day, NEW.payment_provider_name, NEW.time_zone, NEW.locale, 
+                NEW.address1, NEW.address2, NEW.company_name, NEW.city, NEW.state_or_province, 
+                NEW.country, NEW.postal_code, NEW.phone, NEW.created_dt);
+
+CREATE TRIGGER store_account_history_on_update AFTER UPDATE ON accounts
+    FOR EACH ROW
+        INSERT INTO account_history (id, external_key, email, name, first_name_length, currency,
+                                    billing_cycle_day, payment_provider_name, time_zone, locale, 
+                                    address1, address2, company_name, city, state_or_province, 
+                                    country, postal_code, phone, date)
+        VALUES (NEW.id, NEW.external_key, NEW.email, NEW.name, NEW.first_name_length, NEW.currency,
+                NEW.billing_cycle_day, NEW.payment_provider_name, NEW.time_zone, NEW.locale, 
+                NEW.address1, NEW.address2, NEW.company_name, NEW.city, NEW.state_or_province, 
+                NEW.country, NEW.postal_code, NEW.phone, NEW.updated_dt);
diff --git a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
index f4f530e..964eb6a 100644
--- a/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
+++ b/account/src/test/java/com/ning/billing/account/dao/AccountDaoTestBase.java
@@ -21,7 +21,10 @@ import static org.testng.Assert.fail;
 import java.io.IOException;
 
 import org.apache.commons.io.IOUtils;
+import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 
@@ -31,6 +34,7 @@ import com.google.inject.Stage;
 import com.ning.billing.account.glue.AccountModuleWithEmbeddedDb;
 import com.ning.billing.util.bus.DefaultBusService;
 import com.ning.billing.util.bus.BusService;
+import org.testng.annotations.BeforeMethod;
 
 public abstract class AccountDaoTestBase {
     protected AccountModuleWithEmbeddedDb module;
@@ -68,4 +72,29 @@ public abstract class AccountDaoTestBase {
     {
         module.stopDb();
     }
+
+    @BeforeMethod(alwaysRun = true)
+    public void cleanupData() {
+        dbi.inTransaction(new TransactionCallback<Void>() {
+            @Override
+            public Void inTransaction(Handle h, TransactionStatus status) throws Exception {
+                h.execute("truncate table accounts");
+                h.execute("truncate table entitlement_events");
+                h.execute("truncate table subscriptions");
+                h.execute("truncate table bundles");
+                h.execute("truncate table notifications");
+                h.execute("truncate table claimed_notifications");
+                h.execute("truncate table invoices");
+                h.execute("truncate table fixed_invoice_items");
+                h.execute("truncate table recurring_invoice_items");
+                h.execute("truncate table tag_definitions");
+                h.execute("truncate table tags");
+                h.execute("truncate table custom_fields");
+                h.execute("truncate table invoice_payments");
+                h.execute("truncate table payment_attempts");
+                h.execute("truncate table payments");
+                return null;
+            }
+        });
+    }
 }
diff --git a/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
index 1c118a9..3c726aa 100644
--- a/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
+++ b/account/src/test/java/com/ning/billing/account/dao/TestSimpleAccountDao.java
@@ -42,7 +42,7 @@ import com.ning.billing.util.tag.dao.TagDefinitionSqlDao;
 
 @Test(groups = {"account-dao"})
 public class TestSimpleAccountDao extends AccountDaoTestBase {
-    private DefaultAccount createTestAccount() {
+    private AccountBuilder createTestAccountBuilder() {
         String thisKey = "test" + UUID.randomUUID().toString();
         String lastName = UUID.randomUUID().toString();
         String thisEmail = "me@me.com" + " " + UUID.randomUUID();
@@ -65,13 +65,12 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
                                    .locale(locale)
                                    .timeZone(timeZone)
                                    .createdDate(createdDate)
-                                   .updatedDate(updatedDate)
-                                   .build();
+                                   .updatedDate(updatedDate);
     }
 
+    @Test
     public void testBasic() throws AccountApiException {
-
-        Account a = createTestAccount();
+        Account a = createTestAccountBuilder().build();
         accountDao.create(a);
         String key = a.getExternalKey();
 
@@ -88,9 +87,26 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
         assertTrue(all.size() >= 1);
     }
 
+    // simple test to ensure long phone numbers can be stored
+    @Test
+    public void testLongPhoneNumber() throws AccountApiException {
+        Account account = createTestAccountBuilder().phone("123456789012345678901234").build();
+        accountDao.create(account);
+
+        Account saved = accountDao.getAccountByKey(account.getExternalKey());
+        assertNotNull(saved);
+    }
+
+    // simple test to ensure excessively long phone numbers cannot be stored
+    @Test(expectedExceptions = {AccountApiException.class})
+    public void testOverlyLongPhoneNumber() throws AccountApiException {
+        Account account = createTestAccountBuilder().phone("12345678901234567890123456").build();
+        accountDao.create(account);
+    }
+
     @Test
     public void testGetById() throws AccountApiException {
-        Account account = createTestAccount();
+        Account account = createTestAccountBuilder().build();
         UUID id = account.getId();
         String key = account.getExternalKey();
         String name = account.getName();
@@ -109,7 +125,7 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
 
     @Test
     public void testCustomFields() throws AccountApiException {
-        Account account = createTestAccount();
+        Account account = createTestAccountBuilder().build();
         String fieldName = "testField1";
         String fieldValue = "testField1_value";
         account.setFieldValue(fieldName, fieldValue);
@@ -124,8 +140,8 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
 
     @Test
     public void testTags() throws AccountApiException {
-        Account account = createTestAccount();
-        TagDefinition definition = new DefaultTagDefinition("Test Tag", "For testing only", "Test System", new DateTime());
+        Account account = createTestAccountBuilder().build();
+        TagDefinition definition = new DefaultTagDefinition("Test Tag", "For testing only", "Test System");
         TagDefinitionSqlDao tagDescriptionDao = dbi.onDemand(TagDefinitionSqlDao.class);
         tagDescriptionDao.create(definition);
 
@@ -146,7 +162,7 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
 
     @Test
     public void testGetIdFromKey() throws AccountApiException {
-        Account account = createTestAccount();
+        Account account = createTestAccountBuilder().build();
         accountDao.create(account);
 
         try {
@@ -159,12 +175,13 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
 
     @Test(expectedExceptions = AccountApiException.class)
     public void testGetIdFromKeyForNullKey() throws AccountApiException {
-        accountDao.getIdFromKey(null);
+        String key = null;
+        accountDao.getIdFromKey(key);
     }
 
     @Test
     public void testUpdate() throws Exception {
-        final Account account = createTestAccount();
+        final Account account = createTestAccountBuilder().build();
         accountDao.create(account);
 
         AccountData accountData = new AccountData() {
@@ -365,7 +382,7 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
     @Test(groups={"slow"},enabled=true)
     public void testDelete() throws AccountApiException {
 
-        Account a = createTestAccount();
+        Account a = createTestAccountBuilder().build();
         accountDao.create(a);
         String key = a.getExternalKey();
 
diff --git a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
index d869e88..c413f0d 100644
--- a/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
+++ b/analytics/src/test/java/com/ning/billing/analytics/api/TestAnalyticsService.java
@@ -75,8 +75,8 @@ public class TestAnalyticsService
     private static final UUID ID = UUID.randomUUID();
     private static final String KEY = "12345";
     private static final String ACCOUNT_KEY = "pierre-12345";
-    private static final DefaultTagDefinition TAG_ONE = new DefaultTagDefinition("batch20", "something", "pierre", new DateTime(DateTimeZone.UTC));
-    private static final DefaultTagDefinition TAG_TWO = new DefaultTagDefinition("awesome", "something", "pierre", new DateTime(DateTimeZone.UTC));
+    private static final DefaultTagDefinition TAG_ONE = new DefaultTagDefinition("batch20", "something", "pierre");
+    private static final DefaultTagDefinition TAG_TWO = new DefaultTagDefinition("awesome", "something", "pierre");
 
     @Inject
     private AccountUserApi accountApi;
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index f7825e9..a90c6aa 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -22,7 +22,7 @@ public enum ErrorCode {
      * Range 0 : COMMON EXCEPTIONS
      */
     NOT_IMPLEMENTED(1, "Api not implemented yet"),
-
+    DATA_TRUNCATION(2, "Data truncation error. (%s)"),
     /*
      *
      * Range 1000 : ENTITLEMENTS
diff --git a/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java b/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
index d5cc5c1..1e17866 100644
--- a/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
+++ b/api/src/main/java/com/ning/billing/util/tag/TagDefinition.java
@@ -24,7 +24,5 @@ public interface TagDefinition extends Entity {
 
     String getCreatedBy();
 
-    DateTime getCreationDate();
-
     String getDescription();
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java
index d04d768..cdd7464 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBasic.java
@@ -22,8 +22,6 @@ import static org.testng.Assert.assertTrue;
 
 import java.io.IOException;
 import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.Iterator;
 import java.util.List;
 import java.util.UUID;
 
@@ -31,13 +29,11 @@ import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 
-import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.RandomStringUtils;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
-import org.joda.time.Days;
 import org.joda.time.Interval;
 import org.skife.jdbi.v2.Handle;
 import org.skife.jdbi.v2.IDBI;
@@ -79,6 +75,13 @@ import com.ning.billing.util.bus.BusService;
 
 @Guice(modules = {MockModule.class})
 public class TestBasic {
+    private static final int NUMBER_OF_DECIMALS = 4;
+    private static final int ROUNDING_METHOD = BigDecimal.ROUND_HALF_EVEN;
+
+    private static final BigDecimal ONE = new BigDecimal("1.0000").setScale(NUMBER_OF_DECIMALS);
+    private static final BigDecimal TWENTY_NINE = new BigDecimal("29.0000").setScale(NUMBER_OF_DECIMALS);
+    private static final BigDecimal THIRTY = new BigDecimal("30.0000").setScale(NUMBER_OF_DECIMALS);
+    private static final BigDecimal THIRTY_ONE = new BigDecimal("31.0000").setScale(NUMBER_OF_DECIMALS);
 
     private static final Logger log = LoggerFactory.getLogger(TestBasic.class);
     private static long AT_LEAST_ONE_MONTH_MS =  31L * 24L * 3600L * 1000L;
@@ -114,8 +117,6 @@ public class TestBasic {
 
     private TestBusHandler busHandler;
 
-
-
     private void setupMySQL() throws IOException
     {
 
@@ -208,17 +209,18 @@ public class TestBasic {
 
     private void verifyTestResult(UUID accountId, UUID subscriptionId,
                                   DateTime startDate, DateTime endDate,
-                                  BigDecimal amount, DateTime chargeThroughDate) {
+                                  BigDecimal amount, DateTime chargeThroughDate,
+                                  int totalInvoiceItemCount) {
         SubscriptionData subscription = (SubscriptionData) entitlementUserApi.getSubscriptionFromId(subscriptionId);
 
         List<InvoiceItem> invoiceItems = invoiceUserApi.getInvoiceItemsByAccount(accountId);
+        assertEquals(invoiceItems.size(), totalInvoiceItemCount);
+
         boolean wasFound = false;
 
-        Iterator<InvoiceItem> invoiceItemIterator = invoiceItems.iterator();
-        while (invoiceItemIterator.hasNext()) {
-            InvoiceItem item = invoiceItemIterator.next();
-            if (item.getStartDate().compareTo(removeMillis(startDate)) == 0) {
-                if (item.getEndDate().compareTo(removeMillis(endDate)) == 0) {
+        for (InvoiceItem item : invoiceItems) {
+            if (item.getStartDate().compareTo(startDate) == 0) {
+                if (item.getEndDate().compareTo(endDate) == 0) {
                     if (item.getAmount().compareTo(amount) == 0) {
                         wasFound = true;
                         break;
@@ -233,32 +235,28 @@ public class TestBasic {
         assertNotNull(ctd);
         log.info("Checking CTD: " + ctd.toString() + "; clock is " + clock.getUTCNow().toString());
         assertTrue(clock.getUTCNow().isBefore(ctd));
-        assertTrue(ctd.compareTo(removeMillis(chargeThroughDate)) == 0);
+        assertTrue(ctd.compareTo(chargeThroughDate) == 0);
     }
 
-    private DateTime removeMillis(DateTime input) {
-        return input.toMutableDateTime().millisOfSecond().set(0).toDateTime();
-    }
-
-    @Test(groups = "fast", enabled = false)
+    @Test(groups = "fast", enabled = true)
     public void testBasePlanCompleteWithBillingDayInPast() throws Exception {
         DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
         testBasePlanComplete(startDate, 31, false);
     }
 
-    @Test(groups = "fast", enabled = false)
+    @Test(groups = "fast", enabled = true)
     public void testBasePlanCompleteWithBillingDayPresent() throws Exception {
         DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
         testBasePlanComplete(startDate, 1, false);
     }
 
-    @Test(groups = "fast", enabled = false)
+    @Test(groups = "fast", enabled = true)
     public void testBasePlanCompleteWithBillingDayAlignedWithTrial() throws Exception {
         DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
         testBasePlanComplete(startDate, 2, false);
     }
 
-    @Test(groups = "fast", enabled = false)
+    @Test(groups = "fast", enabled = true)
     public void testBasePlanCompleteWithBillingDayInFuture() throws Exception {
         DateTime startDate = new DateTime(2012, 2, 1, 0, 3, 42, 0);
         testBasePlanComplete(startDate, 3, true);
@@ -271,8 +269,7 @@ public class TestBasic {
     @Test(groups = "stress", enabled = false)
     public void stressTest() throws Exception {
         final int maxIterations = 7;
-        int curIteration = maxIterations;
-        for (curIteration = 0; curIteration < maxIterations; curIteration++) {
+        for (int curIteration = 0; curIteration < maxIterations; curIteration++) {
             log.info("################################  ITERATION " + curIteration + "  #########################");
             Thread.sleep(1000);
             setupTest();
@@ -291,14 +288,15 @@ public class TestBasic {
 
     private void testBasePlanComplete(DateTime initialCreationDate, int billingDay,
                                       boolean proRationExpected) throws Exception {
-        long DELAY = 5000 * 10;
+        long DELAY = 5000;
 
+        log.info("Beginning test with BCD of " + billingDay);
         Account account = accountUserApi.createAccount(getAccountData(billingDay), null, null);
         UUID accountId = account.getId();
         assertNotNull(account);
 
         // set clock to the initial start date
-        clock.setDeltaFromReality(initialCreationDate.getMillis() - DateTime.now().getMillis());
+        clock.setDeltaFromReality(initialCreationDate.getMillis() - clock.getUTCNow().getMillis());
         SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever");
 
         String productName = "Shotgun";
@@ -315,15 +313,15 @@ public class TestBasic {
         assertNotNull(subscription);
 
         assertTrue(busHandler.isCompleted(DELAY));
-        log.info("testSimple passed first busHandler checkpoint.");
 
         //
         // VERIFY CTD HAS BEEN SET
         //
         DateTime startDate = subscription.getCurrentPhaseStart();
         DateTime endDate = startDate.plusDays(30);
-        BigDecimal price = subscription.getCurrentPhase().getFixedPrice().getPrice(Currency.USD);
-        verifyTestResult(accountId, subscription.getId(), startDate, endDate, price, endDate);
+        BigDecimal rate = subscription.getCurrentPhase().getFixedPrice().getPrice(Currency.USD);
+        int invoiceItemCount = 1;
+        verifyTestResult(accountId, subscription.getId(), startDate, endDate, rate, endDate, invoiceItemCount);
 
         //
         // CHANGE PLAN IMMEDIATELY AND EXPECT BOTH EVENTS: NextEvent.CHANGE NextEvent.INVOICE
@@ -337,15 +335,14 @@ public class TestBasic {
         subscription.changePlan(newProductName, newTerm, newPlanSetName, clock.getUTCNow());
 
         assertTrue(busHandler.isCompleted(DELAY));
-        log.info("testSimple passed second busHandler checkpoint.");
 
         //
         // VERIFY AGAIN CTD HAS BEEN SET
         //
         startDate = subscription.getCurrentPhaseStart();
-        endDate = startDate.plusMonths(1);
-        price = subscription.getCurrentPhase().getFixedPrice().getPrice(Currency.USD);
-        verifyTestResult(accountId, subscription.getId(), startDate, endDate, price, endDate);
+        endDate = startDate.plusDays(30);
+        invoiceItemCount = 2;
+        verifyTestResult(accountId, subscription.getId(), startDate, endDate, rate, endDate, invoiceItemCount);
 
         //
         // MOVE TIME TO AFTER TRIAL AND EXPECT BOTH EVENTS :  NextEvent.PHASE NextEvent.INVOICE
@@ -363,6 +360,46 @@ public class TestBasic {
 
         assertTrue(busHandler.isCompleted(DELAY));
 
+        startDate = subscription.getCurrentPhaseStart();
+        rate = subscription.getCurrentPhase().getRecurringPrice().getPrice(Currency.USD);
+        BigDecimal price;
+        DateTime chargeThroughDate;
+
+        switch (billingDay) {
+            case 1:
+                // 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:
+                // this will result in a 1-day leading pro-ration and a full-period invoice item
+                price = ONE.divide(TWENTY_NINE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD).multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+                DateTime firstEndDate = startDate.plusDays(1);
+                chargeThroughDate = firstEndDate.plusMonths(1);
+                invoiceItemCount += 2;
+                verifyTestResult(accountId, subscription.getId(), startDate, firstEndDate, price, chargeThroughDate, invoiceItemCount);
+                verifyTestResult(accountId, subscription.getId(), firstEndDate, chargeThroughDate, rate, chargeThroughDate, invoiceItemCount);
+                break;
+            case 31:
+                // this will result in a 29-day pro-ration
+                chargeThroughDate = startDate.toMutableDateTime().dayOfMonth().set(31).toDateTime();
+                price = TWENTY_NINE.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD).multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+                invoiceItemCount += 1;
+                verifyTestResult(accountId, subscription.getId(), startDate, chargeThroughDate, price, chargeThroughDate, invoiceItemCount);
+                break;
+            default:
+                throw new UnsupportedOperationException();
+        }
+
         //
         // CHANGE PLAN EOT AND EXPECT NOTHING
         //
@@ -371,7 +408,6 @@ public class TestBasic {
         newProductName = "Pistol";
         subscription = (SubscriptionData) entitlementUserApi.getSubscriptionFromId(subscription.getId());
         subscription.changePlan(newProductName, newTerm, newPlanSetName, clock.getUTCNow());
-        log.info("testSimple has passed third busHandler checkpoint (no events)");
 
         //
         // MOVE TIME AFTER CTD AND EXPECT BOTH EVENTS : NextEvent.CHANGE NextEvent.INVOICE
@@ -385,20 +421,34 @@ public class TestBasic {
         //waitForDebug();
 
         assertTrue(busHandler.isCompleted(DELAY));
-        log.info("testSimple passed fourth busHandler checkpoint.");
+
+        startDate = chargeThroughDate;
+        endDate = chargeThroughDate.plusMonths(1);
+        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
         //
         int maxCycles = 3;
-        startDate = endDate;
-        endDate = startDate.plusMonths(1);
         do {
             busHandler.pushExpectedEvent(NextEvent.INVOICE);
             busHandler.pushExpectedEvent(NextEvent.PAYMENT);
             clock.addDeltaFromReality(AT_LEAST_ONE_MONTH_MS + 1000);
             assertTrue(busHandler.isCompleted(DELAY));
-            verifyTestResult(accountId, subscription.getId(), startDate, endDate, price, endDate);
+
+            startDate = endDate;
+            endDate = startDate.plusMonths(1);
+            if (endDate.dayOfMonth().get() != billingDay) {
+                // adjust for end of month issues
+                int maximumDay = endDate.dayOfMonth().getMaximumValue();
+                int newDay = (maximumDay < billingDay) ? maximumDay : billingDay;
+                endDate = endDate.toMutableDateTime().dayOfMonth().set(newDay).toDateTime();
+            }
+
+            invoiceItemCount += 1;
+            verifyTestResult(accountId, subscription.getId(), startDate, endDate, price, endDate, invoiceItemCount);
         } while (maxCycles-- > 0);
 
         //
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
index f4bb22b..9a0ef55 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/user/SubscriptionData.java
@@ -202,11 +202,12 @@ public class SubscriptionData implements Subscription {
     }
 
     public SubscriptionTransition getPreviousTransition() {
-
         if (transitions == null) {
             return null;
         }
-        SubscriptionTransition latestSubscription = null;
+
+        // ensure that the latestSubscription is always set; prevents NPEs
+        SubscriptionTransition latestSubscription = transitions.get(0);
         for (SubscriptionTransition cur : transitions) {
             if (cur.getEffectiveTransitionTime().isAfter(clock.getUTCNow())) {
                 break;
@@ -330,10 +331,12 @@ public class SubscriptionData implements Subscription {
                 // Skip future events
                 continue;
             }
-            if (cur.getEventType() == EventType.PHASE) {
+            if (cur.getEventType() == EventType.PHASE
+                    || (cur.getEventType() == EventType.API_USER && cur.getApiEventType() == ApiEventType.CHANGE)) {
                 return cur.getEffectiveTransitionTime();
             }
         }
+
         // CREATE event
         return transitions.get(0).getEffectiveTransitionTime();
     }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index a2e6839..011f193 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -68,7 +68,7 @@ public class Engine implements EventListener, EntitlementService {
     private final EntitlementConfig config;
     private final NotificationQueueService notificationQueueService;
 
-    private NotificationQueue subscritionEventQueue;
+    private NotificationQueue subscriptionEventQueue;
 
     @Inject
     public Engine(Clock clock, EntitlementDao dao, PlanAligner planAligner,
@@ -97,7 +97,7 @@ public class Engine implements EventListener, EntitlementService {
     public void initialize() {
 
         try {
-            subscritionEventQueue = notificationQueueService.createNotificationQueue(ENTITLEMENT_SERVICE_NAME,
+            subscriptionEventQueue = notificationQueueService.createNotificationQueue(ENTITLEMENT_SERVICE_NAME,
                     NOTIFICATION_QUEUE_NAME,
                     new NotificationQueueHandler() {
                 @Override
@@ -135,13 +135,13 @@ public class Engine implements EventListener, EntitlementService {
 
     @LifecycleHandlerType(LifecycleLevel.START_SERVICE)
     public void start() {
-        subscritionEventQueue.startQueue();
+        subscriptionEventQueue.startQueue();
     }
 
     @LifecycleHandlerType(LifecycleLevel.STOP_SERVICE)
     public void stop() {
-        if (subscritionEventQueue != null) {
-            subscritionEventQueue.stopQueue();
+        if (subscriptionEventQueue != null) {
+            subscriptionEventQueue.stopQueue();
          }
     }
 
diff --git a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
index dfdc746..c3fd808 100644
--- a/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
+++ b/entitlement/src/main/resources/com/ning/billing/entitlement/ddl.sql
@@ -1,3 +1,4 @@
+DROP TABLE IF EXISTS events;
 DROP TABLE IF EXISTS entitlement_events;
 CREATE TABLE entitlement_events (
     id int(11) unsigned NOT NULL AUTO_INCREMENT,
diff --git a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
index 1dfac5b..7c6e5cc 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/glue/InvoiceModule.java
@@ -52,10 +52,6 @@ public class InvoiceModule extends AbstractModule {
         bind(InvoicePaymentApi.class).to(DefaultInvoicePaymentApi.class).asEagerSingleton();
     }
 
-    protected void installClock() {
-    	install(new ClockModule());
-    }
-
     protected void installConfig() {
         final InvoiceConfig config = new ConfigurationObjectFactory(System.getProperties()).build(InvoiceConfig.class);
         bind(InvoiceConfig.class).toInstance(config);
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
index 6d419de..b11bfe2 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoice.java
@@ -184,7 +184,7 @@ public class DefaultInvoice implements Invoice {
             return true;
         }
 
-        return lastPaymentAttempt.plusDays(numberOfDays).isBefore(targetDate);
+        return !lastPaymentAttempt.plusDays(numberOfDays).isAfter(targetDate);
     }
 
     @Override
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
index 039f305..a8a1ecc 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceGenerator.java
@@ -233,34 +233,4 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             return fixedPriceInvoiceItem;
         }
     }
-
-//    // assumption: startDate is in the user's time zone
-//    private DateTime calculateSegmentEndDate(final DateTime startDate, final DateTime nextEndDate,
-//                                             final int billCycleDay, final BillingPeriod billingPeriod) {
-//        int dayOfMonth = startDate.getDayOfMonth();
-//        int maxDayOfMonth = startDate.dayOfMonth().getMaximumValue();
-//
-//        DateTime nextBillingDate;
-//
-//        // if the start date is not on the bill cycle day, move it to the nearest following date that works
-//        if ((billCycleDay > maxDayOfMonth) || (dayOfMonth == billCycleDay)) {
-//            nextBillingDate = startDate.plusMonths(billingPeriod.getNumberOfMonths());
-//        } else {
-//            MutableDateTime proposedDate = startDate.toMutableDateTime();
-//
-//            if (dayOfMonth < billCycleDay) {
-//                // move the end date forward to the bill cycle date (same month)
-//                int effectiveBillCycleDay = (billCycleDay > maxDayOfMonth) ? maxDayOfMonth : billCycleDay;
-//                nextBillingDate = proposedDate.dayOfMonth().set(effectiveBillCycleDay).toDateTime();
-//            } else {
-//                // go to the next month
-//                proposedDate = proposedDate.monthOfYear().add(1);
-//                maxDayOfMonth = proposedDate.dayOfMonth().getMaximumValue();
-//                int effectiveBillCycleDay = (billCycleDay > maxDayOfMonth) ? maxDayOfMonth : billCycleDay;
-//                nextBillingDate = proposedDate.dayOfMonth().set(effectiveBillCycleDay).toDateTime();
-//            }
-//        }
-//
-//        return nextBillingDate.isAfter(nextEndDate) ? nextEndDate : nextBillingDate;
-//    }
 }
\ No newline at end of file
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java b/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
index 4d3dff9..916d514 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InAdvanceBillingMode.java
@@ -149,7 +149,7 @@ public class InAdvanceBillingMode implements BillingMode {
         BigDecimal daysInPeriod = new BigDecimal(daysBetween);
         BigDecimal days = new BigDecimal(Days.daysBetween(startDate, nextBillingCycleDate).getDays());
 
-        return days.divide(daysInPeriod, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        return days.divide(daysInPeriod, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
     }
 
     private int calculateNumberOfWholeBillingPeriods(final DateTime startDate, final DateTime endDate, final BillingPeriod billingPeriod) {
@@ -232,6 +232,6 @@ public class InAdvanceBillingMode implements BillingMode {
 
         BigDecimal days = new BigDecimal(Days.daysBetween(previousBillThroughDate, endDate).getDays());
 
-        return days.divide(daysInPeriod, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        return days.divide(daysInPeriod, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
     }
 }
\ No newline at end of file
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
index 90310d5..79fd3db 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/FixedPriceInvoiceItemSqlDao.sql.stg
@@ -9,7 +9,8 @@ fields(prefix) ::= <<
   <prefix>start_date,
   <prefix>end_date,
   <prefix>amount,
-  <prefix>currency
+  <prefix>currency,
+  <prefix>created_date
 >>
 
 getById() ::= <<
@@ -40,13 +41,13 @@ getInvoiceItemsBySubscription() ::= <<
 create() ::= <<
   INSERT INTO fixed_invoice_items(<fields()>)
   VALUES(:id, :invoiceId, :subscriptionId, :planName, :phaseName,
-         :startDate, :endDate, :amount, :currency);
+         :startDate, :endDate, :amount, :currency, NOW());
 >>
 
 batchCreateFromTransaction() ::= <<
   INSERT INTO fixed_invoice_items(<fields()>)
   VALUES(:id, :invoiceId, :subscriptionId, :planName, :phaseName,
-         :startDate, :endDate, :amount, :currency);
+         :startDate, :endDate, :amount, :currency, NOW());
 >>
 
 update() ::= <<
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
index d50a1c5..a5291e8 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/RecurringInvoiceItemSqlDao.sql.stg
@@ -11,7 +11,8 @@ fields(prefix) ::= <<
   <prefix>amount,
   <prefix>rate,
   <prefix>currency,
-  <prefix>reversed_item_id
+  <prefix>reversed_item_id,
+  <prefix>created_date
 >>
 
 getById() ::= <<
@@ -42,13 +43,13 @@ getInvoiceItemsBySubscription() ::= <<
 create() ::= <<
   INSERT INTO recurring_invoice_items(<fields()>)
   VALUES(:id, :invoiceId, :subscriptionId, :planName, :phaseName, :startDate, :endDate,
-         :amount, :rate, :currency, :reversedItemId);
+         :amount, :rate, :currency, :reversedItemId, NOW());
 >>
 
 batchCreateFromTransaction() ::= <<
   INSERT INTO recurring_invoice_items(<fields()>)
   VALUES(:id, :invoiceId, :subscriptionId, :planName, :phaseName, :startDate, :endDate,
-         :amount, :rate, :currency, :reversedItemId);
+         :amount, :rate, :currency, :reversedItemId, NOW());
 >>
 
 update() ::= <<
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
index c7712a8..e210044 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -12,6 +12,7 @@ CREATE TABLE recurring_invoice_items (
   rate numeric(10,4) NULL,
   currency char(3) NOT NULL,
   reversed_item_id char(36),
+  created_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
 CREATE INDEX recurring_invoice_items_subscription_id ON recurring_invoice_items(subscription_id ASC);
@@ -28,16 +29,13 @@ CREATE TABLE fixed_invoice_items (
   end_date datetime NOT NULL,
   amount numeric(10,4) NULL,
   currency char(3) NOT NULL,
+  created_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
 CREATE INDEX fixed_invoice_items_subscription_id ON fixed_invoice_items(subscription_id ASC);
 CREATE INDEX fixed_invoice_items_invoice_id ON fixed_invoice_items(invoice_id ASC);
 
 DROP TABLE IF EXISTS invoice_locking;
-CREATE TABLE invoice_locking (
-  account_id char(36) NOT NULL,
-  PRIMARY KEY(account_id)
-) ENGINE = innodb;
 
 DROP TABLE IF EXISTS invoices;
 CREATE TABLE invoices (
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
index 6957ba0..9d7805a 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTestBase.java
@@ -21,8 +21,13 @@ import static org.testng.Assert.fail;
 
 import java.io.IOException;
 
+import com.google.inject.Inject;
 import com.ning.billing.invoice.tests.InvoicingTestBase;
 import org.apache.commons.io.IOUtils;
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
 import org.testng.annotations.AfterClass;
 import org.testng.annotations.BeforeClass;
 
@@ -32,6 +37,7 @@ import com.google.inject.Stage;
 import com.ning.billing.invoice.glue.InvoiceModuleWithEmbeddedDb;
 import com.ning.billing.util.bus.BusService;
 import com.ning.billing.util.bus.DefaultBusService;
+import org.testng.annotations.BeforeMethod;
 
 public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
     protected InvoiceDao invoiceDao;
@@ -70,6 +76,32 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
         }
     }
 
+    @BeforeMethod(alwaysRun = true)
+    public void cleanupData() {
+        module.getDbi().inTransaction(new TransactionCallback<Void>() {
+            @Override
+            public Void inTransaction(Handle h, TransactionStatus status)
+                    throws Exception {
+                h.execute("truncate table accounts");
+                h.execute("truncate table entitlement_events");
+                h.execute("truncate table subscriptions");
+                h.execute("truncate table bundles");
+                h.execute("truncate table notifications");
+                h.execute("truncate table claimed_notifications");
+                h.execute("truncate table invoices");
+                h.execute("truncate table fixed_invoice_items");
+                h.execute("truncate table recurring_invoice_items");
+                h.execute("truncate table tag_definitions");
+                h.execute("truncate table tags");
+                h.execute("truncate table custom_fields");
+                h.execute("truncate table invoice_payments");
+                h.execute("truncate table payment_attempts");
+                h.execute("truncate table payments");
+                return null;
+            }
+        });
+    }
+
     @AfterClass(alwaysRun = true)
     protected void tearDown() {
         module.stopDb();
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 4e07a39..711665a 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
@@ -169,7 +169,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
     @Test
     public void testGetInvoicesForPayment() {
         List<UUID> invoices;
-        DateTime notionalDate = new DateTime();
+        DateTime notionalDate = clock.getUTCNow();
 
         // create a new invoice with one item
         UUID accountId = UUID.randomUUID();
diff --git a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
index 4ab3495..bb9094e 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/glue/InvoiceModuleWithEmbeddedDb.java
@@ -23,6 +23,7 @@ import com.ning.billing.invoice.api.test.DefaultInvoiceTestApi;
 import com.ning.billing.invoice.dao.InvoicePaymentSqlDao;
 import com.ning.billing.invoice.dao.RecurringInvoiceItemSqlDao;
 import com.ning.billing.util.glue.GlobalLockerModule;
+import com.ning.billing.util.notificationq.NotificationConfig;
 import org.skife.jdbi.v2.IDBI;
 import com.ning.billing.account.glue.AccountModule;
 import com.ning.billing.catalog.glue.CatalogModule;
@@ -50,6 +51,10 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
         helper.stopMysql();
     }
 
+    public IDBI getDbi() {
+        return dbi;
+    }
+
     public RecurringInvoiceItemSqlDao getInvoiceItemSqlDao() {
         return dbi.onDemand(RecurringInvoiceItemSqlDao.class);
     }
@@ -80,4 +85,23 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
 
         install(new BusModule());
     }
+
+    private class TestNotificationConfig implements NotificationConfig {
+        @Override
+        public boolean isNotificationProcessingOff() {
+            return false;
+        }
+        @Override
+        public long getNotificationSleepTimeMs() {
+            return 10;
+        }
+        @Override
+        public int getDaoMaxReadyEvents() {
+            return 1;
+        }
+        @Override
+        public long getDaoClaimTimeMs() {
+            return 60000;
+        }
+    }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
index f0de1ce..136eeb5 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/DefaultInvoiceGeneratorTests.java
@@ -59,8 +59,6 @@ import static org.testng.Assert.assertNull;
 
 @Test(groups = {"fast", "invoicing", "invoiceGenerator"})
 public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
-
-
     private final InvoiceGenerator generator = new DefaultInvoiceGenerator(new DefaultClock());
 
     @Test
@@ -131,8 +129,8 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         assertEquals(invoice.getNumberOfItems(), 2);
 
         BigDecimal expectedNumberOfBillingCycles;
-        expectedNumberOfBillingCycles = ONE.add(FOURTEEN.divide(THIRTY_ONE, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
-        BigDecimal expectedAmount = expectedNumberOfBillingCycles.multiply(rate).setScale(NUMBER_OF_DECIMALS);
+        expectedNumberOfBillingCycles = ONE.add(FOURTEEN.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        BigDecimal expectedAmount = expectedNumberOfBillingCycles.multiply(rate).setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         assertEquals(invoice.getTotalAmount(), expectedAmount);
     }
 
@@ -192,14 +190,14 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         assertEquals(invoice.getNumberOfItems(), 4);
 
         BigDecimal numberOfCyclesEvent1;
-        numberOfCyclesEvent1 = ONE.add(FOURTEEN.divide(THIRTY_ONE, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        numberOfCyclesEvent1 = ONE.add(FOURTEEN.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
 
         BigDecimal numberOfCyclesEvent2 = TWO;
 
         BigDecimal expectedValue;
         expectedValue = numberOfCyclesEvent1.multiply(rate1);
         expectedValue = expectedValue.add(numberOfCyclesEvent2.multiply(rate2));
-        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS);
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         assertEquals(invoice.getTotalAmount(), expectedValue);
     }
@@ -373,7 +371,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
 
         // on 6/21/2011, create add-on (subscription 5)
         events.add(createBillingEvent(subscriptionId5, plan5StartDate, plan5, plan5Phase1, 10));
-        expectedAmount = TWENTY.multiply(NINETEEN.divide(THIRTY, NUMBER_OF_DECIMALS, ROUNDING_METHOD)).setScale(NUMBER_OF_DECIMALS);
+        expectedAmount = TWENTY.multiply(NINETEEN).divide(THIRTY, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         testInvoiceGeneration(events, invoiceItems, plan5StartDate, 1, expectedAmount);
 
         // on 7/7/2011, invoice subscription 4 (plan 1)
@@ -391,8 +389,8 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         // on 7/31/2011, convert subscription 3 to annual
         events.add(createBillingEvent(subscriptionId3, plan3UpgradeToAnnualDate, plan3, plan3Phase2, 31));
         expectedAmount = ONE_HUNDRED.subtract(TEN);
-        expectedAmount = expectedAmount.add(TEN.multiply(ELEVEN.divide(THIRTY_ONE, NUMBER_OF_DECIMALS, ROUNDING_METHOD)));
-        expectedAmount = expectedAmount.setScale(NUMBER_OF_DECIMALS);
+        expectedAmount = expectedAmount.add(TEN.multiply(ELEVEN.divide(THIRTY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD)));
+        expectedAmount = expectedAmount.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         testInvoiceGeneration(events, invoiceItems, plan3UpgradeToAnnualDate, 3, expectedAmount);
 
         // on 8/7/2011, invoice subscription 4 (plan 2)
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/annual/DoubleProRationTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/annual/DoubleProRationTests.java
index 64fa95c..fd37599 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/annual/DoubleProRationTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/annual/DoubleProRationTests.java
@@ -81,9 +81,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2012, 1, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -95,9 +96,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2012, 1, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -109,9 +111,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2012, 1, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -123,9 +126,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2012, 1, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(THREE_HUNDRED_AND_SIXTY_FIVE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(THREE_HUNDRED_AND_SIXTY_SIX, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/quarterly/DoubleProRationTests.java b/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/quarterly/DoubleProRationTests.java
index c1d6085..184f5d5 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/quarterly/DoubleProRationTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/inAdvance/quarterly/DoubleProRationTests.java
@@ -37,7 +37,8 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime targetDate = buildDateTime(2011, 1, 1);
         DateTime endDate = buildDateTime(2011, 4, 27);
 
-        BigDecimal expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        BigDecimal expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
 
@@ -47,7 +48,8 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime targetDate = buildDateTime(2011, 1, 7);
         DateTime endDate = buildDateTime(2011, 4, 27);
 
-        BigDecimal expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        BigDecimal expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
 
@@ -57,7 +59,8 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime targetDate = buildDateTime(2011, 1, 15);
         DateTime endDate = buildDateTime(2011, 4, 27);
 
-        BigDecimal expectedValue = ONE.add(FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        BigDecimal expectedValue = ONE.add(FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
 
@@ -68,8 +71,9 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2011, 4, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -81,9 +85,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2011, 4, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -95,9 +100,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2011, 4, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -109,9 +115,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2011, 4, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -123,9 +130,10 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2011, 4, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(ONE);
-        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.add(TWELVE.divide(NINETY_ONE, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD));
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
@@ -137,8 +145,9 @@ public class DoubleProRationTests extends ProRationInAdvanceTestBase {
         DateTime endDate = buildDateTime(2011, 8, 27);
 
         BigDecimal expectedValue;
-        expectedValue = FOURTEEN.divide(NINETY_TWO, NUMBER_OF_DECIMALS, ROUNDING_METHOD);
+        expectedValue = FOURTEEN.divide(NINETY_TWO, 2 * NUMBER_OF_DECIMALS, ROUNDING_METHOD);
         expectedValue = expectedValue.add(TWO);
+        expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         testCalculateNumberOfBillingCycles(startDate, endDate, targetDate, 15, expectedValue);
     }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/tests/ProRationTestBase.java b/invoice/src/test/java/com/ning/billing/invoice/tests/ProRationTestBase.java
index a24b0c0..122b13b 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/tests/ProRationTestBase.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/tests/ProRationTestBase.java
@@ -66,7 +66,7 @@ public abstract class ProRationTestBase extends InvoicingTestBase {
             numberOfBillingCycles = numberOfBillingCycles.add(item.getNumberOfCycles());
         }
 
-        return numberOfBillingCycles;
+        return numberOfBillingCycles.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
     }
 
     protected BigDecimal calculateNumberOfBillingCycles(DateTime startDate, DateTime targetDate, int billingCycleDay) throws InvalidDateSequenceException {
@@ -77,6 +77,6 @@ public abstract class ProRationTestBase extends InvoicingTestBase {
             numberOfBillingCycles = numberOfBillingCycles.add(item.getNumberOfCycles());
         }
 
-        return numberOfBillingCycles;
+        return numberOfBillingCycles.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
     }
 }
\ No newline at end of file
diff --git a/payment/src/test/java/com/ning/billing/payment/TestHelper.java b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
index ac05da4..4430eb2 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestHelper.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
@@ -53,7 +53,7 @@ public class TestHelper {
                                                                      .firstNameLength(name.length())
                                                                      .externalKey(externalKey)
                                                                      .phone("123-456-7890")
-                                                                     .email("ccuser@example.com")
+                                                                     .email("ccuser" + RandomStringUtils.randomAlphanumeric(8) + "@example.com")
                                                                      .currency(Currency.USD)
                                                                      .billingCycleDay(1)
                                                                      .build();
diff --git a/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java b/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
index 8768117..c1e62d8 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestPaymentInvoiceIntegration.java
@@ -90,7 +90,7 @@ public class TestPaymentInvoiceIntegration {
 
     @AfterClass(alwaysRun = true)
     public void stopMysql() {
-        helper.stopMysql();
+        if (helper != null) helper.stopMysql();
     }
 
     @BeforeMethod(alwaysRun = true)
@@ -116,9 +116,11 @@ public class TestPaymentInvoiceIntegration {
 
     @AfterMethod(alwaysRun = true)
     public void tearDown() throws EventBusException {
-        eventBus.unregister(invoiceProcessor);
-        eventBus.unregister(paymentInfoReceiver);
-        eventBus.stop();
+        if (eventBus != null) {
+            eventBus.unregister(invoiceProcessor);
+            eventBus.unregister(paymentInfoReceiver);
+            eventBus.stop();
+        }
     }
 
     @Test
diff --git a/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java b/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java
index 14c123a..a766982 100644
--- a/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java
+++ b/util/src/main/java/com/ning/billing/util/customfield/dao/FieldStoreDao.java
@@ -48,8 +48,8 @@ public interface FieldStoreDao extends EntityCollectionDao<CustomField>, Transac
     @Override
     @SqlBatch(transactional=false)
     public void batchSaveFromTransaction(@Bind("objectId") final String objectId,
-                     @Bind("objectType") final String objectType,
-                     @CustomFieldBinder final List<CustomField> entities);
+                                         @Bind("objectType") final String objectType,
+                                         @CustomFieldBinder final List<CustomField> entities);
 
 
     public class CustomFieldMapper implements ResultSetMapper<CustomField> {
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
index 57ca679..baaf9cd 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/DefaultTagDefinitionDao.java
@@ -46,7 +46,7 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
 
         // add control tag definitions
         for (ControlTagType controlTag : ControlTagType.values()) {
-            definitionList.add(new DefaultTagDefinition(controlTag.toString(), controlTag.getDescription(), null, null));
+            definitionList.add(new DefaultTagDefinition(controlTag.toString(), controlTag.getDescription(), null));
         }
 
         return definitionList;
@@ -69,7 +69,7 @@ public class DefaultTagDefinitionDao implements TagDefinitionDao {
             throw new TagDefinitionApiException(ErrorCode.TAG_DEFINITION_ALREADY_EXISTS, definitionName);
         }
 
-        TagDefinition definition = new DefaultTagDefinition(definitionName, description, createdBy, clock.getUTCNow());
+        TagDefinition definition = new DefaultTagDefinition(definitionName, description, createdBy);
         dao.create(definition);
         return definition;
     }
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
index f13daff..b2e7dab 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.java
@@ -70,8 +70,7 @@ public interface TagDefinitionSqlDao extends EntityDao<TagDefinition> {
             String name = result.getString("name");
             String description = result.getString("description");
             String createdBy = result.getString("created_by");
-            DateTime creationDate = new DateTime(result.getTimestamp("creation_date"));
-            return new DefaultTagDefinition(id, name, description, createdBy, creationDate);
+            return new DefaultTagDefinition(id, name, description, createdBy);
         }
     }
 
@@ -86,7 +85,6 @@ public interface TagDefinitionSqlDao extends EntityDao<TagDefinition> {
                         q.bind("id", tagDefinition.getId().toString());
                         q.bind("name", tagDefinition.getName());
                         q.bind("createdBy", tagDefinition.getCreatedBy());
-                        q.bind("creationDate", tagDefinition.getCreationDate().toDate());
                         q.bind("description", tagDefinition.getDescription());
                     }
                 };
diff --git a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
index 1296083..fadf98c 100644
--- a/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
+++ b/util/src/main/java/com/ning/billing/util/tag/dao/TagMapper.java
@@ -45,10 +45,9 @@ public class TagMapper implements ResultSetMapper<Tag> {
         } catch (Throwable t) {
             String description = result.getString("tag_description");
             String createdBy = result.getString("created_by");
-            DateTime creationDate = new DateTime(result.getDate("creation_date"));
 
             UUID tagDefinitionId = UUID.fromString(result.getString("tag_definition_id"));
-            TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, name, description, createdBy, creationDate);
+            TagDefinition tagDefinition = new DefaultTagDefinition(tagDefinitionId, name, description, createdBy);
             tag = new DescriptiveTag(id, tagDefinition, addedBy, addedDate);
         }
 
diff --git a/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java b/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
index bfce619..482e56d 100644
--- a/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
+++ b/util/src/main/java/com/ning/billing/util/tag/DefaultTagDefinition.java
@@ -17,27 +17,24 @@
 package com.ning.billing.util.tag;
 
 import java.util.UUID;
-import org.joda.time.DateTime;
 import com.ning.billing.util.entity.EntityBase;
 
 public class DefaultTagDefinition extends EntityBase implements TagDefinition {
     private String name;
     private String description;
     private String createdBy;
-    private DateTime creationDate;
 
     public DefaultTagDefinition(String name, String description,
-                                String createdBy, DateTime creationDate) {
-        this(UUID.randomUUID(), name, description, createdBy, creationDate);
+                                String createdBy) {
+        this(UUID.randomUUID(), name, description, createdBy);
     }
 
     public DefaultTagDefinition(UUID id, String name, String description,
-                                String createdBy, DateTime creationDate) {
+                                String createdBy) {
         super(id);
         this.name = name;
         this.description = description;
         this.createdBy = createdBy;
-        this.creationDate = creationDate;
     }
     
     @Override
@@ -51,11 +48,6 @@ public class DefaultTagDefinition extends EntityBase implements TagDefinition {
     }
 
     @Override
-    public DateTime getCreationDate() {
-        return creationDate;
-    }
-
-    @Override
     public String getDescription() {
         return description;
     }
diff --git a/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg b/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg
index 9d3e96e..c9ee046 100644
--- a/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/customfield/dao/FieldStoreDao.sql.stg
@@ -1,8 +1,8 @@
 group FieldStoreDao;
 
 batchSaveFromTransaction() ::= <<
-  INSERT INTO custom_fields(id, object_id, object_type, field_name, field_value)
-  VALUES (:id, :objectId, :objectType, :fieldName, :fieldValue)
+  INSERT INTO custom_fields(id, object_id, object_type, field_name, field_value, created_date, updated_date)
+  VALUES (:id, :objectId, :objectType, :fieldName, :fieldValue, NOW(), NOW())
   ON DUPLICATE KEY UPDATE
     field_value = :fieldValue;
 >>
diff --git a/util/src/main/resources/com/ning/billing/util/ddl.sql b/util/src/main/resources/com/ning/billing/util/ddl.sql
index a0ef302..389efa7 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -5,19 +5,44 @@ CREATE TABLE custom_fields (
   object_type varchar(30) NOT NULL,
   field_name varchar(30) NOT NULL,
   field_value varchar(255) NOT NULL,
+  created_date datetime NOT NULL,
+  updated_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
 CREATE INDEX custom_fields_object_id_object_type ON custom_fields(object_id, object_type);
 CREATE UNIQUE INDEX custom_fields_unique ON custom_fields(object_id, object_type, field_name);
 
+DROP TABLE IF EXISTS custom_field_history;
+CREATE TABLE custom_field_history (
+  id char(36) NOT NULL,
+  object_id char(36) NOT NULL,
+  object_type varchar(30) NOT NULL,
+  field_name varchar(30) NOT NULL,
+  field_value varchar(255) NOT NULL,
+  change_type char(6) NOT NULL,
+  date datetime NOT NULL
+) ENGINE=innodb;
+CREATE INDEX custom_field_history_object_id_object_type ON custom_fields(object_id, object_type);
+
+CREATE TRIGGER store_custom_field_history_on_insert AFTER INSERT ON custom_fields
+    FOR EACH ROW
+        INSERT INTO custom_field_history (id, object_id, object_type, field_name, field_value, change_type, date)
+        VALUES (NEW.id, NEW.object_id, NEW.object_type, NEW.field_name, NEW.field_value, 'CREATE', NEW.created_date);
+
+CREATE TRIGGER store_custom_field_history_on_update AFTER UPDATE ON custom_fields
+    FOR EACH ROW
+        INSERT INTO custom_field_history (id, object_id, object_type, field_name, field_value, change_type, date)
+        VALUES (NEW.id, NEW.object_id, NEW.object_type, NEW.field_name, NEW.field_value, 'UPDATE', NEW.updated_date);
+
 DROP TABLE IF EXISTS tag_descriptions;
 DROP TABLE IF EXISTS tag_definitions;
 CREATE TABLE tag_definitions (
   id char(36) NOT NULL,
   name varchar(20) NOT NULL,
   created_by varchar(50) NOT NULL,
-  creation_date datetime NOT NULL,
   description varchar(200) NOT NULL,
+  created_date datetime NOT NULL,
+  updated_date datetime NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
 CREATE UNIQUE INDEX tag_definitions_name ON tag_definitions(name);
diff --git a/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
index 72268d0..333da26 100644
--- a/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/tag/dao/TagDefinitionSqlDao.sql.stg
@@ -1,24 +1,32 @@
 group TagDefinitionDao;
 
+fields(prefix) ::= <<
+    <prefix>id,
+    <prefix>name,
+    <prefix>created_by,
+    <prefix>description,
+    <prefix>created_date,
+    <prefix>updated_date
+>>
+
 get() ::= <<
-  SELECT id, name, created_by, creation_date, description
+  SELECT <fields()>
   FROM tag_definitions;
 >>
 
 create() ::= <<
-  INSERT INTO tag_definitions(id, name, created_by, creation_date, description)
-  VALUES(:id, :name, :createdBy, :creationDate, :description);
+  INSERT INTO tag_definitions(<fields()>)
+  VALUES(:id, :name, :createdBy, :description, NOW(), NOW());
 >>
 
 update() ::= <<
   UPDATE tag_definitions
-  SET name = :name, created_by = :createdBy, creation_date = :creationDate,
-      description = :description)
+  SET name = :name, created_by = :createdBy, description = :description, updated_date = NOW())
   WHERE id = :id;
 >>
 
 load() ::= <<
-  SELECT id, name, created_by, creation_date, description
+  SELECT <fields()>
   FROM tag_definitions
   WHERE id = :id;
 >>
@@ -40,7 +48,7 @@ tagDefinitionUsageCount() ::= <<
 >>
 
 getByName() ::= <<
-  SELECT id, name, created_by, creation_date, description
+  SELECT <fields()>
   FROM tag_definitions
   WHERE name = :name;
 >>
diff --git a/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg b/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg
index 9d7ce5c..4cad04c 100644
--- a/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg
+++ b/util/src/main/resources/com/ning/billing/util/tag/dao/TagStoreSqlDao.sql.stg
@@ -13,7 +13,7 @@ load() ::= <<
            td.id AS tag_definition_id,
            t.tag_definition_name AS tag_definition_name,
            td.description AS tag_description,
-           td.created_by, td.creation_date
+           td.created_by
     FROM tags t
     LEFT JOIN tag_definitions td ON t.tag_definition_name = td.name
     WHERE t.object_id = :objectId AND t.object_type = :objectType;
diff --git a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
index 5ee7e88..93814f3 100644
--- a/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
+++ b/util/src/test/java/com/ning/billing/dbi/MysqlTestingHelper.java
@@ -46,7 +46,7 @@ public class MysqlTestingHelper
 
     private static final String DB_NAME = "test_killbill";
     private static final String USERNAME = "root";
-    private static final String PASSWORD = "";
+    private static final String PASSWORD = "root";
 
     private File dbDir;
     private MysqldResource mysqldResource;
@@ -77,7 +77,6 @@ public class MysqlTestingHelper
 
     public void startMysql() throws IOException
     {
-
         if (isUsingLocalInstance()) {
             return;
         }
@@ -90,6 +89,7 @@ public class MysqlTestingHelper
         final Map<String, String> dbOpts = new HashMap<String, String>();
         dbOpts.put(MysqldResourceI.PORT, Integer.toString(port));
         dbOpts.put(MysqldResourceI.INITIALIZE_USER, "true");
+        dbOpts.put(MysqldResourceI.INITIALIZE_PASSWORD, PASSWORD);
         dbOpts.put(MysqldResourceI.INITIALIZE_USER_NAME, USERNAME);
         dbOpts.put("default-time-zone", "+00:00");
 
diff --git a/util/src/test/java/com/ning/billing/util/clock/ClockMock.java b/util/src/test/java/com/ning/billing/util/clock/ClockMock.java
index ad3e5d3..8787cd1 100644
--- a/util/src/test/java/com/ning/billing/util/clock/ClockMock.java
+++ b/util/src/test/java/com/ning/billing/util/clock/ClockMock.java
@@ -150,7 +150,7 @@ public class ClockMock extends DefaultClock {
     }
 
     private DateTime adjustFromAbsolute(DateTime input) {
-        return input.plus(deltaFromRealityMs);
+        return truncateMs(input.plus(deltaFromRealityMs));
     }
 
 }