killbill-uncached

- add invoice number (auto_increment field that is only set

3/9/2012 1:34:29 AM

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 b9585fe..429e0fb 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
@@ -138,16 +138,16 @@ public class DefaultAccountDao implements AccountDao {
         try {
             accountSqlDao.inTransaction(new Transaction<Void, AccountSqlDao>() {
                 @Override
-                public Void inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws AccountApiException, Bus.EventBusException {
+                public Void inTransaction(final AccountSqlDao accountSqlDao, final TransactionStatus status) throws EntityPersistenceException, Bus.EventBusException {
                     String accountId = account.getId().toString();
                     Account currentAccount = accountSqlDao.getById(accountId);
                     if (currentAccount == null) {
-                        throw new AccountApiException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
+                        throw new EntityPersistenceException(ErrorCode.ACCOUNT_DOES_NOT_EXIST_FOR_ID, accountId);
                     }
 
                     String currentKey = currentAccount.getExternalKey();
                     if (!currentKey.equals(account.getExternalKey())) {
-                        throw new AccountApiException(ErrorCode.ACCOUNT_CANNOT_CHANGE_EXTERNAL_KEY, currentKey);
+                        throw new EntityPersistenceException(ErrorCode.ACCOUNT_CANNOT_CHANGE_EXTERNAL_KEY, currentKey);
                     }
 
                     accountSqlDao.update(account);
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 e3b3a1e..8c0e3c2 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
@@ -99,7 +99,7 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
     }
 
     // simple test to ensure excessively long phone numbers cannot be stored
-    @Test(expectedExceptions = {AccountApiException.class})
+    @Test(expectedExceptions = {EntityPersistenceException.class})
     public void testOverlyLongPhoneNumber() throws EntityPersistenceException {
         Account account = createTestAccountBuilder().phone("12345678901234567890123456").build();
         accountDao.create(account);
@@ -364,7 +364,7 @@ public class TestSimpleAccountDao extends AccountDaoTestBase {
         assertEquals(savedAccount.getPhone(), null);
     }
 
-    @Test(expectedExceptions = AccountApiException.class)
+    @Test(expectedExceptions = EntityPersistenceException.class)
     public void testExternalKeyCannotBeUpdated() throws Exception {
         UUID accountId = UUID.randomUUID();
         String originalExternalKey = "extKey1337";
diff --git a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
index 4a61849..bb93d8b 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/Invoice.java
@@ -45,6 +45,8 @@ public interface Invoice extends Entity {
 
     UUID getAccountId();
 
+    Integer getInvoiceNumber();
+
     DateTime getInvoiceDate();
 
     DateTime getTargetDate();
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
index 043a8fd..1186580 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultBillingEvent.java
@@ -52,9 +52,11 @@ public class DefaultBillingEvent implements BillingEvent {
         plan = (transition.getTransitionType() != SubscriptionTransitionType.CANCEL) ?
                 transition.getNextPlan() : transition.getPreviousPlan();
         fixedPrice = (transition.getNextPhase() == null) ? null :
-        		transition.getNextPhase().getFixedPrice().getPrice(currency);
+        		(transition.getNextPhase().getFixedPrice() == null) ? null :
+                        transition.getNextPhase().getFixedPrice().getPrice(currency);
         recurringPrice = (transition.getNextPhase() == null) ? null :
-        	transition.getNextPhase().getRecurringPrice().getPrice(currency);
+                (transition.getNextPhase().getRecurringPrice() == null) ? null :
+                        transition.getNextPhase().getRecurringPrice().getPrice(currency);
         this.currency = currency;
         description = transition.getTransitionType().toString();
         billingModeType = BillingModeType.IN_ADVANCE;
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
index 28e5f3f..998e684 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/billing/TestDefaultEntitlementBillingApi.java
@@ -17,6 +17,7 @@
 package com.ning.billing.entitlement.api.billing;
 
 
+import static org.testng.Assert.assertNull;
 import static org.testng.Assert.assertTrue;
 
 import java.util.ArrayList;
@@ -128,10 +129,10 @@ public class TestDefaultEntitlementBillingApi {
         ((ZombieControl) dao).addResult("getSubscriptionBundleForAccount", new ArrayList<SubscriptionBundle>());
 
         UUID accountId = UUID.randomUUID();
-        Account account = new BrainDeadAccount();
-        ((ZombieControl) account).addResult("getId", accountId);
+        Account account = BrainDeadProxyFactory.createBrainDeadProxyFor(Account.class);
+        ((ZombieControl) account).addResult("getId", accountId).addResult("getCurrency", Currency.USD);
 
-		AccountUserApi accountApi = new BrainDeadAccountUserApi() ;
+		AccountUserApi accountApi = BrainDeadProxyFactory.createBrainDeadProxyFor(AccountUserApi.class);
         ((ZombieControl) accountApi).addResult("getAccountById", account);
 
 		DefaultEntitlementBillingApi api = new DefaultEntitlementBillingApi(dao, accountApi, catalogService);
@@ -255,11 +256,17 @@ public class TestDefaultEntitlementBillingApi {
 			int BCD, UUID id, DateTime time, PlanPhase nextPhase, String desc) throws CatalogApiException {
 		Assert.assertEquals(events.size(), 1);
 		BillingEvent event = events.first();
-		if(nextPhase.getFixedPrice() != null) {
+
+        if(nextPhase.getFixedPrice() != null) {
 			Assert.assertEquals(nextPhase.getFixedPrice().getPrice(Currency.USD), event.getFixedPrice());
+        } else {
+            assertNull(event.getFixedPrice());
 		}
+
 		if(nextPhase.getRecurringPrice() != null) {
 			Assert.assertEquals(nextPhase.getRecurringPrice().getPrice(Currency.USD), event.getRecurringPrice());
+        } else {
+            assertNull(event.getRecurringPrice());
 		}
 
 		Assert.assertEquals(BCD, event.getBillCycleDay());
@@ -270,8 +277,6 @@ public class TestDefaultEntitlementBillingApi {
 		Assert.assertEquals(nextPhase.getBillingPeriod(), event.getBillingPeriod());
 		Assert.assertEquals(BillingModeType.IN_ADVANCE, event.getBillingMode());
 		Assert.assertEquals(desc, event.getDescription());
-		Assert.assertEquals(nextPhase.getFixedPrice(), event.getFixedPrice());
-		Assert.assertEquals(nextPhase.getRecurringPrice(), event.getRecurringPrice());
 	}
 
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
index 101af71..36a2ee3 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceSqlDao.java
@@ -82,6 +82,7 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
     @SqlQuery
     List<Invoice> getUnpaidInvoicesByAccountId(@Bind("accountId") final String accountId,
                                                @Bind("upToDate") final Date upToDate);
+
     @BindingAnnotation(InvoiceBinder.InvoiceBinderFactory.class)
     @Retention(RetentionPolicy.RUNTIME)
     @Target({ElementType.PARAMETER})
@@ -96,10 +97,6 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
                         q.bind("accountId", invoice.getAccountId().toString());
                         q.bind("invoiceDate", invoice.getInvoiceDate().toDate());
                         q.bind("targetDate", invoice.getTargetDate().toDate());
-                        q.bind("amountPaid", invoice.getAmountPaid());
-                        q.bind("amountOutstanding", invoice.getBalance());
-                        DateTime last_payment_date = invoice.getLastPaymentAttempt();
-                        q.bind("lastPaymentAttempt", last_payment_date == null ? null : last_payment_date.toDate());
                         q.bind("currency", invoice.getCurrency().toString());
                     }
                 };
@@ -112,11 +109,12 @@ public interface InvoiceSqlDao extends EntityDao<Invoice>, Transactional<Invoice
         public Invoice map(int index, ResultSet result, StatementContext context) throws SQLException {
             UUID id = UUID.fromString(result.getString("id"));
             UUID accountId = UUID.fromString(result.getString("account_id"));
+            int invoiceNumber = result.getInt("invoice_number");
             DateTime invoiceDate = new DateTime(result.getTimestamp("invoice_date"));
             DateTime targetDate = new DateTime(result.getTimestamp("target_date"));
             Currency currency = Currency.valueOf(result.getString("currency"));
 
-            return new DefaultInvoice(id, accountId, invoiceDate, targetDate, currency);
+            return new DefaultInvoice(id, accountId, invoiceNumber, invoiceDate, targetDate, currency);
         }
     }
 
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 2b2d606..c4a3b6a 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceDispatcher.java
@@ -54,7 +54,7 @@ public class InvoiceDispatcher {
     private final InvoiceDao invoiceDao;
     private final GlobalLocker locker;
 
-    private final static boolean VERBOSE_OUTPUT = false;
+    private final boolean VERBOSE_OUTPUT;
 
     @Inject
     public InvoiceDispatcher(final InvoiceGenerator generator, final AccountUserApi accountUserApi,
@@ -66,6 +66,9 @@ public class InvoiceDispatcher {
         this.accountUserApi = accountUserApi;
         this.invoiceDao = invoiceDao;
         this.locker = locker;
+
+        String verboseOutputValue = System.getProperty("VERBOSE_OUTPUT");
+        VERBOSE_OUTPUT = (verboseOutputValue == null) ? false : Boolean.parseBoolean(verboseOutputValue);
     }
 
     public void processSubscription(final SubscriptionTransition transition) throws InvoiceApiException {
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 b11bfe2..72921c3 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
@@ -21,38 +21,33 @@ import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.util.clock.Clock;
-import com.ning.billing.util.clock.DefaultClock;
 import org.joda.time.DateTime;
 
+import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
-import org.joda.time.DateTime;
-
-import com.ning.billing.catalog.api.Currency;
-import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.api.InvoiceItem;
-import com.ning.billing.util.clock.DefaultClock;
-
 public class DefaultInvoice implements Invoice {
     private final InvoiceItemList invoiceItems = new InvoiceItemList();
     private final List<InvoicePayment> payments = new ArrayList<InvoicePayment>();
     private final UUID id;
     private final UUID accountId;
+    private final Integer invoiceNumber;
     private final DateTime invoiceDate;
     private final DateTime targetDate;
     private final Currency currency;
 
     public DefaultInvoice(UUID accountId, DateTime targetDate, Currency currency, Clock clock) {
-        this(UUID.randomUUID(), accountId, clock.getUTCNow(), targetDate, currency);
+        this(UUID.randomUUID(), accountId, null, clock.getUTCNow(), targetDate, currency);
     }
 
-    public DefaultInvoice(UUID invoiceId, UUID accountId, DateTime invoiceDate, DateTime targetDate,
+    public DefaultInvoice(UUID invoiceId, UUID accountId, @Nullable Integer invoiceNumber, DateTime invoiceDate, DateTime targetDate,
                           Currency currency) {
         this.id = invoiceId;
         this.accountId = accountId;
+        this.invoiceNumber = invoiceNumber;
         this.invoiceDate = invoiceDate;
         this.targetDate = targetDate;
         this.currency = currency;
@@ -119,6 +114,15 @@ public class DefaultInvoice implements Invoice {
         return accountId;
     }
 
+    /**
+     * null until retrieved from the database
+     * @return the invoice number
+     */
+    @Override
+    public Integer getInvoiceNumber() {
+        return invoiceNumber;
+    }
+
     @Override
     public DateTime getInvoiceDate() {
         return invoiceDate;
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 e4af118..66c71bd 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
@@ -41,7 +41,7 @@ import javax.annotation.Nullable;
 public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private static final int ROUNDING_MODE = InvoicingConfiguration.getRoundingMode();
     private static final int NUMBER_OF_DECIMALS = InvoicingConfiguration.getNumberOfDecimals();
-    public static final String NUMBER_OF_MONTHS = "com.ning.billing.invoice.maxNumberOfMonthsInFuture";
+    public static final String NUMBER_OF_MONTHS = "killbill.invoice.maxNumberOfMonthsInFuture";
 
     private final Clock clock;
 
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
index 35c45bf..203be9e 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceSqlDao.sql.stg
@@ -1,6 +1,15 @@
 group InvoiceDao;
 
-invoiceFields(prefix) ::= <<
+invoiceFetchFields(prefix) ::= <<
+    <prefix>invoice_number,
+    <prefix>id,
+    <prefix>account_id,
+    <prefix>invoice_date,
+    <prefix>target_date,
+    <prefix>currency
+>>
+
+invoiceSetFields(prefix) ::= <<
     <prefix>id,
     <prefix>account_id,
     <prefix>invoice_date,
@@ -9,31 +18,31 @@ invoiceFields(prefix) ::= <<
 >>
 
 get() ::= <<
-  SELECT <invoiceFields()>
+  SELECT <invoiceFetchFields()>
   FROM invoices
   ORDER BY target_date ASC;
 >>
 
 getInvoicesByAccount() ::= <<
-  SELECT <invoiceFields()>
+  SELECT <invoiceFetchFields()>
   FROM invoices
   WHERE account_id = :accountId
   ORDER BY target_date ASC;
 >>
 
 getInvoicesByAccountAfterDate() ::= <<
-  SELECT <invoiceFields()>
+  SELECT <invoiceFetchFields()>
   FROM invoices
   WHERE account_id = :accountId AND target_date >= :fromDate
   ORDER BY target_date ASC;
 >>
 
 getInvoicesBySubscription() ::= <<
-  SELECT <invoiceFields("i.")>
+  SELECT <invoiceFetchFields("i.")>
   FROM invoices i
   LEFT JOIN recurring_invoice_items rii ON i.id = rii.invoice_id
   WHERE rii.subscription_id = :subscriptionId
-  GROUP BY <invoiceFields("i.")>;
+  GROUP BY <invoiceFetchFields("i.")>;
 >>
 
 getInvoicesForPayment() ::= <<
@@ -44,11 +53,11 @@ getInvoicesForPayment() ::= <<
   WHERE ((ips.last_payment_date IS NULL) OR (DATEDIFF(:targetDate, ips.last_payment_date) >= :numberOfDays))
         AND ((ips.total_paid IS NULL) OR (iis.amount_invoiced >= ips.total_paid))
         AND ((iis.amount_invoiced IS NOT NULL) AND (iis.amount_invoiced > 0))
-  GROUP BY <invoiceFields("i.")>;
+  GROUP BY <invoiceFetchFields("i.")>;
 >>
 
 getById() ::= <<
-  SELECT <invoiceFields()>
+  SELECT <invoiceFetchFields()>
   FROM invoices
   WHERE id = :id;
 >>
@@ -64,7 +73,7 @@ getAccountBalance() ::= <<
 >>
 
 create() ::= <<
-  INSERT INTO invoices(<invoiceFields()>)
+  INSERT INTO invoices(<invoiceSetFields()>)
   VALUES (:id, :accountId, :invoiceDate, :targetDate, :currency);
 >>
 
@@ -75,14 +84,8 @@ getInvoiceIdByPaymentAttemptId() ::= <<
      AND ip.payment_attempt_id = :paymentAttemptId
 >>
 
-update() ::= <<
-  UPDATE invoices
-  SET account_id = :accountId, invoice_date = :invoiceDate, target_date = :targetDate, currency = :currency
-  WHERE id = :id;
->>
-
 getUnpaidInvoicesByAccountId() ::= <<
-  SELECT i.id, i.account_id, i.invoice_date, i.target_date, i.currency
+  SELECT <invoiceFetchFields("i.")>
   FROM invoices i
   LEFT JOIN invoice_payment_summary ips ON i.id = ips.invoice_id
   LEFT JOIN invoice_item_summary iis ON i.id = iis.invoice_id
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 c3be18d..503ec7f 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -39,13 +39,16 @@ DROP TABLE IF EXISTS invoice_locking;
 
 DROP TABLE IF EXISTS invoices;
 CREATE TABLE invoices (
+  invoice_number int NOT NULL AUTO_INCREMENT,
   id char(36) NOT NULL,
   account_id char(36) NOT NULL,
   invoice_date datetime NOT NULL,
   target_date datetime NOT NULL,
   currency char(3) NOT NULL,
-  PRIMARY KEY(id)
+  PRIMARY KEY(invoice_number)
 ) ENGINE=innodb;
+CREATE INDEX invoices_invoice_number ON invoices(invoice_number ASC);
+CREATE INDEX invoices_id ON invoices(id ASC);
 CREATE INDEX invoices_account_id ON invoices(account_id ASC);
 
 DROP TABLE IF EXISTS invoice_payments;
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 ebdc2f5..eabcc26 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
@@ -48,10 +48,12 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
         // Health check test to make sure MySQL is setup properly
         try {
             module = new InvoiceModuleWithEmbeddedDb();
+            final String accountDdl = IOUtils.toString(DefaultInvoiceDao.class.getResourceAsStream("/com/ning/billing/account/ddl.sql"));
             final String invoiceDdl = IOUtils.toString(DefaultInvoiceDao.class.getResourceAsStream("/com/ning/billing/invoice/ddl.sql"));
             final String entitlementDdl = IOUtils.toString(DefaultInvoiceDao.class.getResourceAsStream("/com/ning/billing/entitlement/ddl.sql"));
 
             module.startDb();
+            module.initDb(accountDdl);
             module.initDb(invoiceDdl);
             module.initDb(entitlementDdl);
 
@@ -81,20 +83,21 @@ public abstract class InvoiceDaoTestBase extends InvoicingTestBase {
             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 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");
+                //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/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceDaoTests.java
index 07dd93b..b4058e2 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
@@ -16,7 +16,6 @@
 
 package com.ning.billing.invoice.dao;
 
-import com.google.inject.Inject;
 import com.ning.billing.catalog.DefaultPrice;
 import com.ning.billing.catalog.MockInternationalPrice;
 import com.ning.billing.catalog.MockPlan;
@@ -25,6 +24,8 @@ import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.CatalogApiException;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.entitlement.api.billing.BillingEvent;
 import com.ning.billing.entitlement.api.billing.BillingModeType;
 import com.ning.billing.entitlement.api.billing.DefaultBillingEvent;
@@ -36,6 +37,7 @@ import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
 import com.ning.billing.invoice.model.BillingEventSet;
 import com.ning.billing.invoice.model.DefaultInvoice;
+import com.ning.billing.invoice.model.DefaultInvoiceGenerator;
 import com.ning.billing.invoice.model.DefaultInvoicePayment;
 import com.ning.billing.invoice.model.InvoiceGenerator;
 import com.ning.billing.invoice.model.RecurringInvoiceItem;
@@ -61,13 +63,7 @@ import static org.testng.Assert.assertTrue;
 public class InvoiceDaoTests extends InvoiceDaoTestBase {
     private final int NUMBER_OF_DAY_BETWEEN_RETRIES = 8;
     private final Clock clock = new DefaultClock();
-    private final InvoiceGenerator generator;
-
-    @Inject
-    public InvoiceDaoTests(InvoiceGenerator generator) {
-        super();
-        this.generator = generator;
-    }
+    private final InvoiceGenerator generator = new DefaultInvoiceGenerator(clock);
 
     @Test
     public void testCreationAndRetrievalByAccount() {
@@ -687,4 +683,48 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         assertEquals(savedInvoice.getNumberOfItems(), 2);
         assertEquals(savedInvoice.getTotalAmount().compareTo(cheapAmount), 0);
     }
+
+    @Test
+    public void testInvoiceNumber() throws InvoiceApiException {
+        Currency currency = Currency.USD;
+        DateTime targetDate1 = DateTime.now().plusMonths(1);
+        DateTime targetDate2 = DateTime.now().plusMonths(2);
+
+        Subscription subscription = BrainDeadProxyFactory.createBrainDeadProxyFor(Subscription.class);
+        ((ZombieControl) subscription).addResult("getId", UUID.randomUUID());
+
+        Plan plan = BrainDeadProxyFactory.createBrainDeadProxyFor(Plan.class);
+        ((ZombieControl) plan).addResult("getName", "plan");
+
+        PlanPhase phase1 = BrainDeadProxyFactory.createBrainDeadProxyFor(PlanPhase.class);
+        ((ZombieControl) phase1).addResult("getName", "plan-phase1");
+
+        PlanPhase phase2 = BrainDeadProxyFactory.createBrainDeadProxyFor(PlanPhase.class);
+        ((ZombieControl) phase2).addResult("getName", "plan-phase2");
+
+        BillingEventSet events = new BillingEventSet();
+        List<Invoice> invoices = new ArrayList<Invoice>();
+
+        BillingEvent event1 = new DefaultBillingEvent(subscription, targetDate1, plan, phase1, null,
+                                                      TEN, currency,
+                                                      BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                                                      "testEvent1", SubscriptionTransitionType.CHANGE);
+        events.add(event1);
+
+        Invoice invoice1 = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate1, Currency.USD);
+        invoices.add(invoice1);
+        invoiceDao.create(invoice1);
+        invoice1 = invoiceDao.getById(invoice1.getId());
+        assertNotNull(invoice1.getInvoiceNumber());
+
+        BillingEvent event2 = new DefaultBillingEvent(subscription, targetDate1, plan, phase2, null,
+                                                      TWENTY, currency,
+                                                      BillingPeriod.MONTHLY, 31, BillingModeType.IN_ADVANCE,
+                                                      "testEvent2", SubscriptionTransitionType.CHANGE);
+        events.add(event2);
+        Invoice invoice2 = generator.generateInvoice(UUID.randomUUID(), events, invoices, targetDate2, Currency.USD);
+        invoiceDao.create(invoice2);
+        invoice2 = invoiceDao.getById(invoice2.getId());
+        assertNotNull(invoice2.getInvoiceNumber());
+    }
 }
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
index 9bcef4b..63ad021 100644
--- a/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/InvoiceItemDaoTests.java
@@ -32,9 +32,8 @@ import java.util.UUID;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertNotNull;
 
-
+@Test(groups = {"invoicing", "invoicing-invoiceDao"})
 public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
-
     private final Clock clock = new DefaultClock();
 
     @Test(groups = "slow")
@@ -60,7 +59,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
         assertEquals(thisItem.getAmount().compareTo(item.getRate()), 0);
         assertEquals(thisItem.getRate().compareTo(item.getRate()), 0);
         assertEquals(thisItem.getCurrency(), item.getCurrency());
-        assertEquals(thisItem.getCreatedDate(), item.getCreatedDate());
+        assertEquals(thisItem.getCreatedDate().compareTo(item.getCreatedDate()), 0);
     }
 
     @Test(groups = "slow")
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 f09fe31..77b90ec 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
@@ -17,14 +17,13 @@
 package com.ning.billing.invoice.glue;
 
 import java.io.IOException;
+import java.net.URL;
 
-import com.ning.billing.invoice.api.InvoiceUserApi;
 import com.ning.billing.invoice.api.test.InvoiceTestApi;
 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;
@@ -36,6 +35,8 @@ import com.ning.billing.util.glue.BusModule;
 import com.ning.billing.util.notificationq.MockNotificationQueueService;
 import com.ning.billing.util.notificationq.NotificationQueueService;
 
+import static org.testng.Assert.assertNotNull;
+
 public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
     private final MysqlTestingHelper helper = new MysqlTestingHelper();
     private IDBI dbi;
@@ -70,6 +71,8 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
 
     @Override
     public void configure() {
+        loadSystemPropertiesFromClasspath("/resource.properties");
+
         dbi = helper.getDBI();
         bind(IDBI.class).toInstance(dbi);
 
@@ -87,22 +90,13 @@ 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;
+    private static void loadSystemPropertiesFromClasspath(final String resource) {
+        final URL url = InvoiceModuleWithEmbeddedDb.class.getResource(resource);
+        assertNotNull(url);
+        try {
+            System.getProperties().load( url.openStream() );
+        } catch (IOException e) {
+            throw new RuntimeException(e);
         }
     }
 }
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 84c0197..d868c9b 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestHelper.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
@@ -80,7 +80,7 @@ public class TestHelper {
                                      DateTime targetDate,
                                      Currency currency,
                                      InvoiceItem... items) {
-        Invoice invoice = new DefaultInvoice(UUID.randomUUID(), account.getId(), new DateTime(), targetDate, currency);
+        Invoice invoice = new DefaultInvoice(UUID.randomUUID(), account.getId(), 1, new DateTime(), targetDate, currency);
 
         for (InvoiceItem item : items) {
             if (item instanceof RecurringInvoiceItem) {
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 4ae95d7..f76795a 100644
--- a/util/src/main/resources/com/ning/billing/util/ddl.sql
+++ b/util/src/main/resources/com/ning/billing/util/ddl.sql
@@ -4,7 +4,7 @@ CREATE TABLE custom_fields (
   object_id char(36) NOT NULL,
   object_type varchar(30) NOT NULL,
   field_name varchar(30) NOT NULL,
-  field_value varchar(255) NOT NULL,
+  field_value varchar(255),
   created_date datetime NOT NULL,
   updated_date datetime NOT NULL,
   PRIMARY KEY(id)
diff --git a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
index 4512a5d..f7c16e4 100644
--- a/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
+++ b/util/src/test/java/com/ning/billing/util/customfield/TestFieldStore.java
@@ -17,6 +17,7 @@
 package com.ning.billing.util.customfield;
 
 import java.io.IOException;
+import java.util.ArrayList;
 import java.util.UUID;
 import org.apache.commons.io.IOUtils;
 import org.skife.jdbi.v2.IDBI;