killbill-aplcache

updates to fix invoice issues

1/28/2012 11:12:33 PM

Changes

account/pom.xml 2(+1 -1)

api/pom.xml 2(+1 -1)

beatrix/pom.xml 2(+1 -1)

catalog/pom.xml 2(+1 -1)

invoice/pom.xml 2(+1 -1)

payment/pom.xml 2(+1 -1)

pom.xml 2(+1 -1)

util/pom.xml 2(+1 -1)

Details

account/pom.xml 2(+1 -1)

diff --git a/account/pom.xml b/account/pom.xml
index 153f0bd..141e6cb 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>
diff --git a/analytics/pom.xml b/analytics/pom.xml
index 7368654..18bd687 100644
--- a/analytics/pom.xml
+++ b/analytics/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-analytics</artifactId>

api/pom.xml 2(+1 -1)

diff --git a/api/pom.xml b/api/pom.xml
index 7c0dcd7..afbca6a 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-api</artifactId>
diff --git a/api/src/main/java/com/ning/billing/ErrorCode.java b/api/src/main/java/com/ning/billing/ErrorCode.java
index d7bd49e..4e1ffaa 100644
--- a/api/src/main/java/com/ning/billing/ErrorCode.java
+++ b/api/src/main/java/com/ning/billing/ErrorCode.java
@@ -69,7 +69,7 @@ public enum ErrorCode {
     CAT_NO_PRICE_FOR_CURRENCY(2010, "This price does not have a value for the currency '%s'."),
 
     /* Price value explicitly set to NULL meaning there is no price available in that currency */
-    CAT_PRICE_VALUE_NULL_FOR_CURRENCY(2011, "The value for the currency '%s' is NULL. This plan cannot be bought in this currnency."),
+    CAT_PRICE_VALUE_NULL_FOR_CURRENCY(2011, "The value for the currency '%s' is NULL. This plan cannot be bought in this currency."),
     CAT_NULL_PRICE_LIST_NAME(2012,"Price list name was null"),
     CAT_PRICE_LIST_NOT_FOUND(2013, "Could not find a pricelist with name '%s'"),
     /*
diff --git a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
index 44c46a7..a9070fd 100644
--- a/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
+++ b/api/src/main/java/com/ning/billing/invoice/api/InvoiceItem.java
@@ -34,9 +34,11 @@ public interface InvoiceItem extends Entity, Comparable<InvoiceItem> {
 
     String getDescription();
 
-    BigDecimal getAmount();
+    BigDecimal getRecurringAmount();
 
-    BigDecimal getRate();
+    BigDecimal getRecurringRate();
+
+    BigDecimal getFixedAmount();
 
     Currency getCurrency();
 
diff --git a/api/src/main/java/com/ning/billing/invoice/api/test/InvoiceTestApi.java b/api/src/main/java/com/ning/billing/invoice/api/test/InvoiceTestApi.java
new file mode 100644
index 0000000..9edcd8c
--- /dev/null
+++ b/api/src/main/java/com/ning/billing/invoice/api/test/InvoiceTestApi.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.invoice.api.test;
+
+import com.ning.billing.invoice.api.Invoice;
+
+public interface InvoiceTestApi {
+    public void create(Invoice invoice);
+}

beatrix/pom.xml 2(+1 -1)

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index 792a09e..ded6f0f 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>
diff --git a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java
index a4a4ce2..83115de 100644
--- a/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java
+++ b/beatrix/src/main/java/com/ning/billing/beatrix/lifecycle/ServiceFinder.java
@@ -16,7 +16,6 @@
 
 package com.ning.billing.beatrix.lifecycle;
 
-
 import com.ning.billing.lifecycle.KillbillService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -25,7 +24,13 @@ import java.io.File;
 import java.io.IOException;
 import java.net.MalformedURLException;
 import java.net.URL;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 import java.util.jar.JarFile;
 
 public class ServiceFinder {
@@ -81,8 +86,6 @@ public class ServiceFinder {
 	    }
 
 	    for (int h = 0; h < classPaths.length; h++) {
-
-
 	        Enumeration<?> files = null;
 	        JarFile module = null;
 	        File classPath = new File( (URL.class).isInstance(classPaths[h]) ?
@@ -93,7 +96,7 @@ public class ServiceFinder {
 
 	            List<String> dirListing = new ArrayList<String>();
 	            recursivelyListDir(dirListing, classPath, new StringBuffer() );
-	            files = Collections.enumeration( dirListing );
+	            files = Collections.enumeration(dirListing);
 	        } else if (classPath.getName().endsWith(".jar")) {
 
 	            log.debug("JAR : " + classPath);

catalog/pom.xml 2(+1 -1)

diff --git a/catalog/pom.xml b/catalog/pom.xml
index 09e0e48..635fac3 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockInternationalPrice.java b/catalog/src/test/java/com/ning/billing/catalog/MockInternationalPrice.java
index c290979..cc3a679 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockInternationalPrice.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockInternationalPrice.java
@@ -19,7 +19,6 @@ package com.ning.billing.catalog;
 import com.ning.billing.catalog.api.Currency;
 
 import java.math.BigDecimal;
-import java.util.Date;
 
 public class MockInternationalPrice extends DefaultInternationalPrice {
 
diff --git a/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java b/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java
index b9e9afe..53c73fe 100644
--- a/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java
+++ b/catalog/src/test/java/com/ning/billing/catalog/MockPlan.java
@@ -34,6 +34,14 @@ public class MockPlan extends DefaultPlan {
 		setPlansAllowedInBundle(1);
 	}
 
+    public MockPlan(String planName) {
+		setName(planName);
+		setProduct(new MockProduct());
+		setFinalPhase(new MockPlanPhase(this));
+		setInitialPhases(null);
+		setPlansAllowedInBundle(1);
+	}
+
 	public MockPlan(MockPlanPhase mockPlanPhase) {
 		setName("test-plan");
 		setProduct(new MockProduct());
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index b75837c..805436d 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
index c212b75..4c5e0af 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/billing/DefaultEntitlementBillingApi.java
@@ -64,10 +64,13 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
         for (final Subscription subscription: subscriptions) {
         	for (final SubscriptionTransition transition : subscription.getAllTransitions()) {
         		try {
-        			result.add(new DefaultBillingEvent(transition, subscription, calculateBCD(transition, accountId)));
+                    BillingEvent event = new DefaultBillingEvent(transition, subscription, calculateBCD(transition, accountId));
+        			result.add(event);
         		} catch (CatalogApiException e) {
         			log.error("Failing to identify catalog components while creating BillingEvent from transition: " + 
         					transition.getId().toString(), e);
+                } catch (Exception e) {
+                    log.warn("Failed while getting BillingEvent", e);
         		}
         	}
         }

invoice/pom.xml 2(+1 -1)

diff --git a/invoice/pom.xml b/invoice/pom.xml
index 6b7cb14..e685de0 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>
diff --git a/invoice/src/main/java/com/ning/billing/invoice/api/test/DefaultInvoiceTestApi.java b/invoice/src/main/java/com/ning/billing/invoice/api/test/DefaultInvoiceTestApi.java
new file mode 100644
index 0000000..bbec57f
--- /dev/null
+++ b/invoice/src/main/java/com/ning/billing/invoice/api/test/DefaultInvoiceTestApi.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.invoice.api.test;
+
+import com.google.inject.Inject;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.dao.InvoiceDao;
+
+public class DefaultInvoiceTestApi implements InvoiceTestApi {
+    private final InvoiceDao invoiceDao;
+
+    @Inject
+    public DefaultInvoiceTestApi(InvoiceDao invoiceDao) {
+        this.invoiceDao = invoiceDao;
+    }
+
+    @Override
+    public void create(Invoice invoice) {
+        invoiceDao.create(invoice);
+    }
+}
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
index aa2cb63..4d963bb 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/DefaultInvoiceDao.java
@@ -239,13 +239,17 @@ public class DefaultInvoiceDao implements InvoiceDao {
 
     private void notifyOfFutureBillingEvents(final InvoiceSqlDao dao, final List<InvoiceItem> invoiceItems) {
         for (final InvoiceItem item : invoiceItems) {
-            notifier.insertNextBillingNotification(dao, item.getSubscriptionId(), item.getEndDate());
+            if (item.getEndDate() != null) {
+                notifier.insertNextBillingNotification(dao, item.getSubscriptionId(), item.getEndDate());
+            }
         }
     }
 
     private void setChargedThroughDates(final InvoiceSqlDao dao, final Collection<InvoiceItem> invoiceItems) {
         for (InvoiceItem invoiceItem : invoiceItems) {
-            entitlementBillingApi.setChargedThroughDateFromTransaction(dao, invoiceItem.getSubscriptionId(), invoiceItem.getEndDate());
+            if (invoiceItem.getEndDate() != null) {
+                entitlementBillingApi.setChargedThroughDateFromTransaction(dao, invoiceItem.getSubscriptionId(), invoiceItem.getEndDate());
+            }
         }
     }
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java
index 6f4e47b..76e0dbf 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/dao/InvoiceItemSqlDao.java
@@ -19,17 +19,26 @@ package com.ning.billing.invoice.dao;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.model.DefaultInvoiceItem;
-import com.ning.billing.util.entity.EntityCollectionDao;
 import com.ning.billing.util.entity.EntityDao;
 import org.joda.time.DateTime;
 import org.skife.jdbi.v2.SQLStatement;
 import org.skife.jdbi.v2.StatementContext;
-import org.skife.jdbi.v2.sqlobject.*;
+import org.skife.jdbi.v2.sqlobject.Bind;
+import org.skife.jdbi.v2.sqlobject.Binder;
+import org.skife.jdbi.v2.sqlobject.BinderFactory;
+import org.skife.jdbi.v2.sqlobject.BindingAnnotation;
+import org.skife.jdbi.v2.sqlobject.SqlBatch;
+import org.skife.jdbi.v2.sqlobject.SqlQuery;
+import org.skife.jdbi.v2.sqlobject.SqlUpdate;
 import org.skife.jdbi.v2.sqlobject.customizers.RegisterMapper;
 import org.skife.jdbi.v2.sqlobject.stringtemplate.ExternalizedSqlViaStringTemplate3;
 import org.skife.jdbi.v2.tweak.ResultSetMapper;
 
-import java.lang.annotation.*;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
 import java.math.BigDecimal;
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -71,10 +80,11 @@ public interface InvoiceItemSqlDao extends EntityDao<InvoiceItem> {
                         q.bind("invoiceId", item.getInvoiceId().toString());
                         q.bind("subscriptionId", item.getSubscriptionId().toString());
                         q.bind("startDate", item.getStartDate().toDate());
-                        q.bind("endDate", item.getEndDate().toDate());
+                        q.bind("endDate", item.getEndDate() == null ? null : item.getEndDate().toDate());
                         q.bind("description", item.getDescription());
-                        q.bind("amount", item.getAmount());
-                        q.bind("rate", item.getRate());
+                        q.bind("recurringAmount", item.getRecurringAmount() == null ? BigDecimal.ZERO : item.getRecurringAmount());
+                        q.bind("recurringRate", item.getRecurringRate() == null ? BigDecimal.ZERO : item.getRecurringRate());
+                        q.bind("fixedAmount", item.getFixedAmount() == null ? BigDecimal.ZERO : item.getFixedAmount());
                         q.bind("currency", item.getCurrency().toString());
                     }
                 };
@@ -91,11 +101,13 @@ public interface InvoiceItemSqlDao extends EntityDao<InvoiceItem> {
             DateTime startDate = new DateTime(result.getTimestamp("start_date"));
             DateTime endDate = new DateTime(result.getTimestamp("end_date"));
             String description = result.getString("description");
-            BigDecimal amount = result.getBigDecimal("amount");
-            BigDecimal rate = result.getBigDecimal("rate");
+            BigDecimal recurringAmount = result.getBigDecimal("recurring_amount");
+            BigDecimal recurringRate = result.getBigDecimal("recurring_rate");
+            BigDecimal fixedAmount = result.getBigDecimal("fixed_amount");
             Currency currency = Currency.valueOf(result.getString("currency"));
 
-            return new DefaultInvoiceItem(id, invoiceId, subscriptionId, startDate, endDate, description, amount, rate , currency);
+            return new DefaultInvoiceItem(id, invoiceId, subscriptionId, startDate, endDate,
+                                          description, recurringAmount, recurringRate, fixedAmount, currency);
         }
     }
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
index 54efe1b..ec42757 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -108,9 +108,9 @@ public class InvoiceListener {
         Invoice invoice = generator.generateInvoice(accountId, billingEvents, invoiceItemList, targetDate, targetCurrency);
 
         if (invoice != null) {
-            //if (invoice.getNumberOfItems() > 0) {
+            if (invoice.getNumberOfItems() > 0) {
                 invoiceDao.create(invoice);
-            //}
+            }
         }
     }
 }
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 899b4a5..47f5d67 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
@@ -35,12 +35,14 @@ import com.ning.billing.entitlement.api.billing.BillingModeType;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 
+import javax.annotation.Nullable;
+
 public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private static final Logger log = LoggerFactory.getLogger(DefaultInvoiceGenerator.class);
 
     @Override
     public Invoice generateInvoice(final UUID accountId, final BillingEventSet events,
-                                   final InvoiceItemList existingItems, final DateTime targetDate,
+                                   @Nullable final InvoiceItemList existingItems, final DateTime targetDate,
                                    final Currency targetCurrency) {
         if (events == null) {return null;}
         if (events.size() == 0) {return null;}
@@ -94,6 +96,8 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
             currentItems.add(existingItem.asCredit(existingItem.getInvoiceId()));
         }
 
+        currentItems.cleanupDuplicatedItems();
+
         return currentItems;
     }
 
@@ -128,18 +132,21 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private void processEvent(final UUID invoiceId, final BillingEvent event, final List<InvoiceItem> items,
                               final DateTime targetDate, final Currency targetCurrency) {
     	try {
-    		//TODO: Jeff getPrice() -> getRecurringPrice()
-            InternationalPrice recurringPrice = event.getRecurringPrice();
-    		BigDecimal rate = (recurringPrice == null) ? BigDecimal.ZERO : recurringPrice.getPrice(targetCurrency);
+            BigDecimal recurringRate = event.getRecurringPrice() == null ? null : event.getRecurringPrice().getPrice(targetCurrency);
+            BigDecimal fixedPrice = event.getFixedPrice() == null ? null : event.getFixedPrice().getPrice(targetCurrency);
 
-    		BigDecimal numberOfBillingPeriods = calculateNumberOfBillingPeriods(event, targetDate);
-            if (numberOfBillingPeriods.compareTo(BigDecimal.ZERO) != 0) {
-                BigDecimal invoiceItemAmount = numberOfBillingPeriods.multiply(rate);
-                BillingMode billingMode = getBillingMode(event.getBillingMode());
-                DateTime billThroughDate = billingMode.calculateEffectiveEndDate(event.getEffectiveDate(), targetDate, event.getBillCycleDay(), event.getBillingPeriod());
+    		BigDecimal numberOfBillingPeriods;
+            BigDecimal recurringAmount =null;
 
-                addInvoiceItem(invoiceId, items, event, billThroughDate, invoiceItemAmount, rate, targetCurrency);
+            if (recurringRate != null) {
+                numberOfBillingPeriods = calculateNumberOfBillingPeriods(event, targetDate);
+                recurringAmount = numberOfBillingPeriods.multiply(recurringRate);
             }
+
+            BillingMode billingMode = getBillingMode(event.getBillingMode());
+            DateTime billThroughDate = billingMode.calculateEffectiveEndDate(event.getEffectiveDate(), targetDate, event.getBillCycleDay(), event.getBillingPeriod());
+
+            addInvoiceItem(invoiceId, items, event, billThroughDate, recurringAmount, recurringRate, fixedPrice, targetCurrency);
     	} catch (CatalogApiException e) {
             log.error(String.format("Encountered a catalog error processing invoice %s for billing event on date %s", 
                     invoiceId.toString(), 
@@ -150,18 +157,21 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
     private void processEvents(final UUID invoiceId, final BillingEvent firstEvent, final BillingEvent secondEvent,
                                final List<InvoiceItem> items, final DateTime targetDate, final Currency targetCurrency) {
     	try {
-            InternationalPrice recurringPrice = firstEvent.getRecurringPrice();
-            if (recurringPrice != null) {
-                BigDecimal rate = recurringPrice.getPrice(targetCurrency);
-                BigDecimal numberOfBillingPeriods = calculateNumberOfBillingPeriods(firstEvent, secondEvent, targetDate);
-                if (numberOfBillingPeriods.compareTo(BigDecimal.ZERO) != 0) {
-                    BigDecimal invoiceItemAmount = numberOfBillingPeriods.multiply(rate);
-                    BillingMode billingMode = getBillingMode(firstEvent.getBillingMode());
-                    DateTime billThroughDate = billingMode.calculateEffectiveEndDate(firstEvent.getEffectiveDate(), secondEvent.getEffectiveDate(), targetDate, firstEvent.getBillCycleDay(), firstEvent.getBillingPeriod());
-
-                    addInvoiceItem(invoiceId, items, firstEvent, billThroughDate, invoiceItemAmount, rate, targetCurrency);
-                }
+            BigDecimal recurringRate = firstEvent.getRecurringPrice() == null ? null : firstEvent.getRecurringPrice().getPrice(targetCurrency);
+            BigDecimal fixedPrice = firstEvent.getFixedPrice() == null ? null : firstEvent.getFixedPrice().getPrice(targetCurrency);
+
+            BigDecimal numberOfBillingPeriods;
+            BigDecimal recurringAmount =null;
+
+            if (recurringRate != null) {
+                numberOfBillingPeriods = calculateNumberOfBillingPeriods(firstEvent, secondEvent, targetDate);
+                recurringAmount = numberOfBillingPeriods.multiply(recurringRate);
             }
+
+            BillingMode billingMode = getBillingMode(firstEvent.getBillingMode());
+            DateTime billThroughDate = billingMode.calculateEffectiveEndDate(firstEvent.getEffectiveDate(), secondEvent.getEffectiveDate(), targetDate, firstEvent.getBillCycleDay(), firstEvent.getBillingPeriod());
+
+            addInvoiceItem(invoiceId, items, firstEvent, billThroughDate, recurringAmount, recurringRate, fixedPrice, targetCurrency);
     	} catch (CatalogApiException e) {
     		log.error(String.format("Encountered a catalog error processing invoice %s for billing event on date %s",
                     invoiceId.toString(),
@@ -171,8 +181,9 @@ public class DefaultInvoiceGenerator implements InvoiceGenerator {
 
     private void addInvoiceItem(final UUID invoiceId, final List<InvoiceItem> items, final BillingEvent event,
                                 final DateTime billThroughDate, final BigDecimal amount, final BigDecimal rate,
-                                final Currency currency) {
-        DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, event.getSubscription().getId(), event.getEffectiveDate(), billThroughDate, event.getDescription(), amount, rate, currency);
+                                final BigDecimal fixedAmount, final Currency currency) {
+        DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, event.getSubscription().getId(), event.getEffectiveDate(),
+                                  billThroughDate, event.getDescription(), amount, rate, fixedAmount, currency);
         items.add(item);
     }
 
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java
index eb54aeb..136967c 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/DefaultInvoiceItem.java
@@ -20,6 +20,7 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.InvoiceItem;
 import org.joda.time.DateTime;
 
+import javax.annotation.Nullable;
 import java.math.BigDecimal;
 import java.util.UUID;
 
@@ -30,23 +31,30 @@ public class DefaultInvoiceItem implements InvoiceItem {
     private DateTime startDate;
     private DateTime endDate;
     private final String description;
-    private BigDecimal amount;
-    private final BigDecimal rate;
+    private BigDecimal recurringAmount;
+    private final BigDecimal recurringRate;
+    private BigDecimal fixedAmount;
     private final Currency currency;
 
-    public DefaultInvoiceItem(UUID invoiceId, UUID subscriptionId, DateTime startDate, DateTime endDate, String description, BigDecimal amount, BigDecimal rate, Currency currency) {
-        this(UUID.randomUUID(), invoiceId, subscriptionId, startDate, endDate, description, amount, rate, currency);
+    public DefaultInvoiceItem(UUID invoiceId, UUID subscriptionId, DateTime startDate, DateTime endDate,
+                              String description, BigDecimal recurringAmount, BigDecimal recurringRate,
+                              BigDecimal fixedAmount, Currency currency) {
+        this(UUID.randomUUID(), invoiceId, subscriptionId, startDate, endDate, description,
+             recurringAmount, recurringRate, fixedAmount, currency);
     }
 
-    public DefaultInvoiceItem(UUID id, UUID invoiceId, UUID subscriptionId, DateTime startDate, DateTime endDate, String description, BigDecimal amount, BigDecimal rate, Currency currency) {
+    public DefaultInvoiceItem(UUID id, UUID invoiceId, UUID subscriptionId, DateTime startDate, DateTime endDate,
+                              String description, BigDecimal recurringAmount, BigDecimal recurringRate,
+                              BigDecimal fixedAmount, Currency currency) {
         this.id = id;
         this.invoiceId = invoiceId;
         this.subscriptionId = subscriptionId;
         this.startDate = startDate;
         this.endDate = endDate;
         this.description = description;
-        this.amount = amount;
-        this.rate = rate;
+        this.recurringAmount = recurringAmount;
+        this.recurringRate = recurringRate;
+        this.fixedAmount = fixedAmount;
         this.currency = currency;
     }
 
@@ -57,14 +65,18 @@ public class DefaultInvoiceItem implements InvoiceItem {
         this.startDate = that.getStartDate();
         this.endDate = that.getEndDate();
         this.description = that.getDescription();
-        this.amount = that.getAmount();
-        this.rate = that.getRate();
+        this.recurringAmount = that.getRecurringAmount();
+        this.recurringRate = that.getRecurringRate();
+        this.fixedAmount = that.getFixedAmount();
         this.currency = that.getCurrency();
     }
 
     @Override
     public InvoiceItem asCredit(UUID invoiceId) {
-        return new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, endDate, description, amount.negate(), rate, currency);
+        BigDecimal recurringAmountNegated = recurringAmount == null ? null : recurringAmount.negate();
+        BigDecimal fixedAmountNegated = fixedAmount == null ? null : fixedAmount.negate();
+        return new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, endDate, description,
+                                      recurringAmountNegated, recurringRate, fixedAmountNegated, currency);
     }
 
     @Override
@@ -98,13 +110,18 @@ public class DefaultInvoiceItem implements InvoiceItem {
     }
 
     @Override
-    public BigDecimal getAmount() {
-        return amount;
+    public BigDecimal getRecurringAmount() {
+        return recurringAmount;
     }
 
     @Override
-    public BigDecimal getRate() {
-        return rate;
+    public BigDecimal getRecurringRate() {
+        return recurringRate;
+    }
+
+    @Override
+    public BigDecimal getFixedAmount() {
+        return fixedAmount;
     }
 
     @Override
@@ -113,11 +130,20 @@ public class DefaultInvoiceItem implements InvoiceItem {
     }
 
     @Override
-    public int compareTo(InvoiceItem invoiceItem) {
-        int compareSubscriptions = getSubscriptionId().compareTo(invoiceItem.getSubscriptionId());
+    public int compareTo(InvoiceItem that) {
+        int compareSubscriptions = getSubscriptionId().compareTo(that.getSubscriptionId());
 
         if (compareSubscriptions == 0) {
-            return getStartDate().compareTo(invoiceItem.getStartDate());
+            // move null end dates to the end of the set
+            if ((this.endDate != null) && (that.getEndDate() == null)) {
+                return -1;
+            }
+
+            if ((this.endDate == null) && (that.getEndDate() != null)) {
+                return 1;
+            }
+
+            return getStartDate().compareTo(that.getStartDate());
         } else {
             return compareSubscriptions;
         }
@@ -128,44 +154,89 @@ public class DefaultInvoiceItem implements InvoiceItem {
     public void subtract(InvoiceItem that) {
         if (this.startDate.equals(that.getStartDate()) && this.endDate.equals(that.getEndDate())) {
             this.startDate = this.endDate;
-            this.amount = this.amount.subtract(that.getAmount());
+                this.recurringAmount = safeSubtract(this.recurringAmount, that.getRecurringAmount());
+                this.fixedAmount = safeSubtract(this.fixedAmount, that.getFixedAmount());
         } else {
             if (this.startDate.equals(that.getStartDate())) {
                 this.startDate = that.getEndDate();
-                this.amount = this.amount.subtract(that.getAmount());
+                this.recurringAmount = safeSubtract(this.recurringAmount, that.getRecurringAmount());
+                this.fixedAmount = safeSubtract(this.fixedAmount, that.getFixedAmount());
             }
 
             if (this.endDate.equals(that.getEndDate())) {
                 this.endDate = that.getStartDate();
-                this.amount = this.amount.subtract(that.getAmount());
+                this.recurringAmount = safeSubtract(this.recurringAmount, that.getRecurringAmount());
+                this.fixedAmount = safeSubtract(this.fixedAmount, that.getFixedAmount());
             }
         }
     }
 
+    private BigDecimal safeSubtract(BigDecimal minuend, BigDecimal subtrahend) {
+        // minuend - subtrahend == difference
+        if (minuend == null) {
+            if (subtrahend == null) {
+                return BigDecimal.ZERO;
+            } else {
+                return subtrahend.negate();
+            }
+        } else {
+            if (subtrahend == null) {
+                return minuend;
+            } else {
+                return minuend.subtract(subtrahend);
+            }
+        }
+
+    }
+
     @Override
     public boolean duplicates(InvoiceItem that) {
         if(!this.getSubscriptionId().equals(that.getSubscriptionId())) {return false;}
-        if(!this.getRate().equals(that.getRate())) {return false;}
+        
+        //if (!compareNullableBigDecimal(this.getRecurringAmount(), that.getRecurringAmount())) {return false;}
+        if (!compareNullableBigDecimal(this.getRecurringRate(), that.getRecurringRate())) {return false;}
+        if (!compareNullableBigDecimal(this.getFixedAmount(), that.getFixedAmount())) {return false;}
+
         if(!this.getCurrency().equals(that.getCurrency())) {return false;}
 
         DateRange thisDateRange = new DateRange(this.getStartDate(), this.getEndDate());
         return thisDateRange.contains(that.getStartDate()) && thisDateRange.contains(that.getEndDate());
     }
 
+    private boolean compareNullableBigDecimal(@Nullable BigDecimal value1, @Nullable BigDecimal value2) {
+        if ((value1 == null) && (value2 != null)) {return false;}
+        if ((value1 != null) && (value2 == null)) {return false;}
+
+        if ((value1 != null) && (value2 != null)) {
+            if (!value1.equals(value2)) {return false;}
+        }
+
+        return true;
+    }
+
     /**
      * indicates whether the supplied item is a cancelling item for this item
-     * @param that
-     * @return
+     * @param that  the InvoiceItem to be examined
+     * @return true if the two invoice items cancel each other out (same subscription, same date range, sum of amounts = 0)
      */
     @Override
     public boolean cancels(InvoiceItem that) {
         if(!this.getSubscriptionId().equals(that.getSubscriptionId())) {return false;}
         if(!this.getEndDate().equals(that.getEndDate())) {return false;}
         if(!this.getStartDate().equals(that.getStartDate())) {return false;}
-        if(!this.getAmount().equals(that.getAmount().negate())) {return false;}
-        if(!this.getRate().equals(that.getRate())) {return false;}
+
+        if (!safeCheckForZeroSum(this.getRecurringAmount(), that.getRecurringAmount())) {return false;}
+        if(!this.getRecurringRate().equals(that.getRecurringRate())) {return false;}
+
+        if (!safeCheckForZeroSum(this.getFixedAmount(), that.getFixedAmount())) {return false;}
         if(!this.getCurrency().equals(that.getCurrency())) {return false;}
 
         return true;
     }
+
+    private boolean safeCheckForZeroSum(final BigDecimal value1, final BigDecimal value2) {
+        if ((value1 == null) && (value2 == null)) {return true;}
+        if ((value1 == null) ^ (value2 == null)) {return false;}
+        return (value1.add(value2).compareTo(BigDecimal.ZERO) == 0);
+    }
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java
index b4d81a7..626993e 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceGenerator.java
@@ -20,8 +20,9 @@ import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.invoice.api.Invoice;
 import org.joda.time.DateTime;
 
+import javax.annotation.Nullable;
 import java.util.UUID;
 
 public interface InvoiceGenerator {
-    public Invoice generateInvoice(UUID accountId, BillingEventSet events, InvoiceItemList items, DateTime targetDate, Currency targetCurrency);
+    public Invoice generateInvoice(UUID accountId, BillingEventSet events, @Nullable InvoiceItemList items, DateTime targetDate, Currency targetCurrency);
 }
diff --git a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java
index 8cae782..5a10928 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/model/InvoiceItemList.java
@@ -18,12 +18,14 @@ package com.ning.billing.invoice.model;
 
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 import com.ning.billing.invoice.api.InvoiceItem;
 
 public class InvoiceItemList extends ArrayList<InvoiceItem> {
     private static final int NUMBER_OF_DECIMALS = InvoicingConfiguration.getNumberOfDecimals();
     private static final int ROUNDING_METHOD = InvoicingConfiguration.getRoundingMethod();
+
     public InvoiceItemList() {
         super();
     }
@@ -34,11 +36,17 @@ public class InvoiceItemList extends ArrayList<InvoiceItem> {
     }
 
     public BigDecimal getTotalAmount() {
-        // TODO: Jeff -- naive implementation, assumes all invoice items share the same currency
-        BigDecimal total = new BigDecimal("0");
+        // naive implementation, assumes all invoice items share the same currency
+        BigDecimal total = BigDecimal.ZERO.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
 
         for (final InvoiceItem item : this) {
-            total = total.add(item.getAmount());
+            if (item.getRecurringAmount() != null) {
+                total = total.add(item.getRecurringAmount());
+            }
+
+            if (item.getFixedAmount() != null) {
+                total = total.add(item.getFixedAmount());
+            }
         }
 
         return total.setScale(NUMBER_OF_DECIMALS, ROUNDING_METHOD);
@@ -60,4 +68,21 @@ public class InvoiceItemList extends ArrayList<InvoiceItem> {
 
         this.removeAll(itemsToRemove);
     }
+
+   /*
+    * removes items from the list that have a recurring amount of zero, but a recurring rate that is not zero
+    */
+    public void cleanupDuplicatedItems() {
+        Iterator<InvoiceItem> iterator = this.iterator();
+        while (iterator.hasNext()) {
+            InvoiceItem item = iterator.next();
+            Boolean hasZeroRecurringAmount = item.getRecurringAmount() == null || (item.getRecurringAmount().compareTo(BigDecimal.ZERO) == 0);
+            Boolean hasRecurringRate = item.getRecurringRate() == null || (item.getRecurringRate().compareTo(BigDecimal.ZERO) != 0);
+            Boolean hasZeroFixedAmount = item.getFixedAmount() == null || (item.getFixedAmount().compareTo(BigDecimal.ZERO) == 0);
+
+            if (hasZeroRecurringAmount && hasRecurringRate & hasZeroFixedAmount) {
+                iterator.remove();
+            }
+        }
+    }
 }
diff --git a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceItemSqlDao.sql.stg b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
index 4dc783f..39fcd24 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
+++ b/invoice/src/main/resources/com/ning/billing/invoice/dao/InvoiceItemSqlDao.sql.stg
@@ -1,39 +1,54 @@
 group InvoiceItemDao;
 
+invoiceItemFields(prefix) ::= <<
+  <prefix>id,
+  <prefix>invoice_id,
+  <prefix>subscription_id,
+  <prefix>start_date,
+  <prefix>end_date,
+  <prefix>description,
+  <prefix>recurring_amount,
+  <prefix>recurring_rate,
+  <prefix>fixed_amount,
+  <prefix>currency
+>>
+
 getById() ::= <<
-  SELECT id, invoice_id, subscription_id, start_date, end_date, description, amount, rate, currency
+  SELECT <invoiceItemFields()>
   FROM invoice_items
   WHERE id = :id;
 >>
 
 getInvoiceItemsByInvoice() ::= <<
-  SELECT id, invoice_id, subscription_id, start_date, end_date, description, amount, rate, currency
+  SELECT <invoiceItemFields()>
   FROM invoice_items
   WHERE invoice_id = :invoiceId;
 >>
 
 getInvoiceItemsByAccount() ::= <<
-  SELECT ii.id, ii.invoice_id, ii.subscription_id, ii.start_date, ii.end_date, ii.description, ii.amount, ii.rate, ii.currency
+  SELECT <invoiceItemFields("ii.")>
   FROM invoice_items ii
   INNER JOIN invoices i ON i.id = ii.invoice_id
   WHERE i.account_id = :accountId;
 >>
 
 getInvoiceItemsBySubscription() ::= <<
-  SELECT id, invoice_id, subscription_id, start_date, end_date, description, amount, rate, currency
+  SELECT <invoiceItemFields()>
   FROM invoice_items
   WHERE subscription_id = :subscriptionId;
 >>
 
 create() ::= <<
-  INSERT INTO invoice_items(id, invoice_id, subscription_id, start_date, end_date, description, amount, rate, currency)
-  VALUES(:id, :invoiceId, :subscriptionId, :startDate, :endDate, :description, :amount, :rate, :currency);
+  INSERT INTO invoice_items(<invoiceItemFields()>)
+  VALUES(:id, :invoiceId, :subscriptionId, :startDate, :endDate, :description,
+         :recurringAmount, :recurringRate, :fixedAmount, :currency);
 >>
 
 update() ::= <<
   UPDATE invoice_items
   SET invoice_id = :invoiceId, subscription_id = :subscriptionId, start_date = :startDate, end_date = :endDate,
-      description = :description, amount = :amount, rate = :rate, currency = :currency
+      description = :description, recurring_amount = :recurringAmount, recurring_rate = :recurringRate,
+      fixed_amount = :fixedAmount, currency = :currency
   WHERE id = :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 da13062..348f423 100644
--- a/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
+++ b/invoice/src/main/resources/com/ning/billing/invoice/ddl.sql
@@ -4,10 +4,11 @@ CREATE TABLE invoice_items (
   invoice_id char(36) NOT NULL,
   subscription_id char(36) NOT NULL,
   start_date datetime NOT NULL,
-  end_date datetime NOT NULL,
+  end_date datetime NULL,
   description varchar(100) NOT NULL,
-  amount numeric(10,4) NOT NULL,
-  rate numeric(10,4) NOT NULL,
+  recurring_amount numeric(10,4) NOT NULL,
+  recurring_rate numeric(10,4) NOT NULL,
+  fixed_amount numeric(10,4) NOT NULL,
   currency char(3) NOT NULL,
   PRIMARY KEY(id)
 ) ENGINE=innodb;
@@ -45,6 +46,6 @@ GROUP BY invoice_id;
 
 DROP VIEW IF EXISTS invoice_item_summary;
 CREATE VIEW invoice_item_summary AS
-select invoice_id, sum(amount) AS total_amount
+select invoice_id, sum(recurring_amount) + SUM(fixed_amount) AS total_amount
 from invoice_items
 group by invoice_id;
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 66ad993..b63c230 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
@@ -23,14 +23,10 @@ import com.ning.billing.catalog.MockPlanPhase;
 import com.ning.billing.catalog.api.BillingPeriod;
 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;
-import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 import com.ning.billing.entitlement.api.user.Subscription;
-import com.ning.billing.entitlement.api.user.SubscriptionTransition;
 import com.ning.billing.invoice.api.Invoice;
 import com.ning.billing.invoice.api.InvoiceItem;
 import com.ning.billing.invoice.api.InvoicePayment;
@@ -87,7 +83,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         UUID subscriptionId = UUID.randomUUID();
         DateTime startDate = new DateTime(2010, 1, 1, 0, 0, 0, 0);
         DateTime endDate = new DateTime(2010, 4, 1, 0, 0, 0, 0);
-        InvoiceItem invoiceItem = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, endDate, "test", new BigDecimal("21.00"), new BigDecimal("7.00"), Currency.USD);
+        InvoiceItem invoiceItem = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, endDate, "test", new BigDecimal("21.00"), new BigDecimal("7.00"), null, Currency.USD);
         invoice.addInvoiceItem(invoiceItem);
         invoiceDao.create(invoice);
 
@@ -184,7 +180,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate = new BigDecimal("9.0");
         BigDecimal amount = rate.multiply(new BigDecimal("3.0"));
 
-        DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, targetDate, endDate, "test", amount, rate, Currency.USD);
+        DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, targetDate, endDate, "test", amount, rate, null, Currency.USD);
         invoice.addInvoiceItem(item);
         invoiceDao.create(invoice);
 
@@ -279,16 +275,16 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         DateTime startDate = new DateTime(2011, 3, 1, 0, 0, 0, 0);
         DateTime endDate = startDate.plusMonths(1);
 
-        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoiceId1, subscriptionId1, startDate, endDate, "test A", rate1, rate1, Currency.USD);
+        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoiceId1, subscriptionId1, startDate, endDate, "test A", rate1, rate1, null, Currency.USD);
         invoiceItemDao.create(item1);
 
-        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoiceId1, subscriptionId2, startDate, endDate, "test B", rate2, rate2, Currency.USD);
+        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoiceId1, subscriptionId2, startDate, endDate, "test B", rate2, rate2, null, Currency.USD);
         invoiceItemDao.create(item2);
 
-        DefaultInvoiceItem item3 = new DefaultInvoiceItem(invoiceId1, subscriptionId3, startDate, endDate, "test C", rate3, rate3, Currency.USD);
+        DefaultInvoiceItem item3 = new DefaultInvoiceItem(invoiceId1, subscriptionId3, startDate, endDate, "test C", rate3, rate3, null, Currency.USD);
         invoiceItemDao.create(item3);
 
-        DefaultInvoiceItem item4 = new DefaultInvoiceItem(invoiceId1, subscriptionId4, startDate, endDate, "test D", rate4, rate4, Currency.USD);
+        DefaultInvoiceItem item4 = new DefaultInvoiceItem(invoiceId1, subscriptionId4, startDate, endDate, "test D", rate4, rate4, null, Currency.USD);
         invoiceItemDao.create(item4);
 
         // create invoice 2 (subscriptions 1-3)
@@ -300,13 +296,13 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         startDate = endDate;
         endDate = startDate.plusMonths(1);
 
-        DefaultInvoiceItem item5 = new DefaultInvoiceItem(invoiceId2, subscriptionId1, startDate, endDate, "test A", rate1, rate1, Currency.USD);
+        DefaultInvoiceItem item5 = new DefaultInvoiceItem(invoiceId2, subscriptionId1, startDate, endDate, "test A", rate1, rate1, null, Currency.USD);
         invoiceItemDao.create(item5);
 
-        DefaultInvoiceItem item6 = new DefaultInvoiceItem(invoiceId2, subscriptionId2, startDate, endDate, "test B", rate2, rate2, Currency.USD);
+        DefaultInvoiceItem item6 = new DefaultInvoiceItem(invoiceId2, subscriptionId2, startDate, endDate, "test B", rate2, rate2, null, Currency.USD);
         invoiceItemDao.create(item6);
 
-        DefaultInvoiceItem item7 = new DefaultInvoiceItem(invoiceId2, subscriptionId3, startDate, endDate, "test C", rate3, rate3, Currency.USD);
+        DefaultInvoiceItem item7 = new DefaultInvoiceItem(invoiceId2, subscriptionId3, startDate, endDate, "test C", rate3, rate3, null, Currency.USD);
         invoiceItemDao.create(item7);
 
         // check that each subscription returns the correct number of invoices
@@ -365,10 +361,10 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate1 = new BigDecimal("17.0");
         BigDecimal rate2 = new BigDecimal("42.0");
 
-        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test A", rate1, rate1, Currency.USD);
+        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test A", rate1, rate1, null, Currency.USD);
         invoiceItemDao.create(item1);
 
-        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test B", rate2, rate2, Currency.USD);
+        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test B", rate2, rate2, null, Currency.USD);
         invoiceItemDao.create(item2);
 
         BigDecimal payment1 = new BigDecimal("48.0");
@@ -392,10 +388,10 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate1 = new BigDecimal("17.0");
         BigDecimal rate2 = new BigDecimal("42.0");
 
-        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test A", rate1, rate1, Currency.USD);
+        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test A", rate1, rate1, null, Currency.USD);
         invoiceItemDao.create(item1);
 
-        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test B", rate2, rate2, Currency.USD);
+        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test B", rate2, rate2, null, Currency.USD);
         invoiceItemDao.create(item2);
 
         BigDecimal balance = invoiceDao.getAccountBalance(accountId);
@@ -430,10 +426,10 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate1 = new BigDecimal("17.0");
         BigDecimal rate2 = new BigDecimal("42.0");
 
-        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test A", rate1, rate1, Currency.USD);
+        DefaultInvoiceItem item1 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test A", rate1, rate1, null, Currency.USD);
         invoiceItemDao.create(item1);
 
-        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test B", rate2, rate2, Currency.USD);
+        DefaultInvoiceItem item2 = new DefaultInvoiceItem(invoice1.getId(), UUID.randomUUID(), startDate, endDate, "test B", rate2, rate2, null, Currency.USD);
         invoiceItemDao.create(item2);
 
         DateTime upToDate;
@@ -456,7 +452,7 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
 
         BigDecimal rate3 = new BigDecimal("21.0");
 
-        DefaultInvoiceItem item3 = new DefaultInvoiceItem(invoice2.getId(), UUID.randomUUID(), startDate2, endDate2, "test C", rate3, rate3, Currency.USD);
+        DefaultInvoiceItem item3 = new DefaultInvoiceItem(invoice2.getId(), UUID.randomUUID(), startDate2, endDate2, "test C", rate3, rate3, null, Currency.USD);
         invoiceItemDao.create(item3);
 
         upToDate = new DateTime(2011, 1, 1, 0, 0, 0, 0);
@@ -558,98 +554,4 @@ public class InvoiceDaoTests extends InvoiceDaoTestBase {
         Invoice invoice = generator.generateInvoice(UUID.randomUUID(), events, null, new DateTime(), Currency.USD);
         assertNull(invoice);
     }
-
-    private class MockSubscription implements Subscription {
-        private UUID subscriptionId = UUID.randomUUID();
-
-        @Override
-        public void cancel(DateTime requestedDate, boolean eot) throws EntitlementUserApiException {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void uncancel() throws EntitlementUserApiException {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate) throws EntitlementUserApiException {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void pause() throws EntitlementUserApiException {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void resume() throws EntitlementUserApiException {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public UUID getId() {
-            return subscriptionId;
-        }
-
-        @Override
-        public UUID getBundleId() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public SubscriptionState getState() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public DateTime getStartDate() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public DateTime getEndDate() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public Plan getCurrentPlan() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public String getCurrentPriceList() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public PlanPhase getCurrentPhase() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public DateTime getChargedThroughDate() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public DateTime getPaidThroughDate() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public List<SubscriptionTransition> getActiveTransitions() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public List<SubscriptionTransition> getAllTransitions() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public SubscriptionTransition getPendingTransition() {
-            throw new UnsupportedOperationException();
-        }
-    }
 }
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 dc2afd8..92a90b3 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
@@ -45,7 +45,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
         DateTime endDate = new DateTime(2011, 11, 1, 0, 0, 0, 0);
         BigDecimal rate = new BigDecimal("20.00");
 
-        InvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, endDate, "test", rate, rate, Currency.USD);
+        InvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, endDate, "test", rate, rate, rate, Currency.USD);
         invoiceItemDao.create(item);
 
         InvoiceItem thisItem = invoiceItemDao.getById(item.getId().toString());
@@ -56,8 +56,9 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
         assertEquals(thisItem.getStartDate(), item.getStartDate());
         assertEquals(thisItem.getEndDate(), item.getEndDate());
         assertEquals(thisItem.getDescription(), item.getDescription());
-        assertEquals(thisItem.getAmount().compareTo(item.getAmount()), 0);
-        assertEquals(thisItem.getRate().compareTo(item.getRate()), 0);
+        assertEquals(thisItem.getRecurringAmount().compareTo(item.getRecurringAmount()), 0);
+        assertEquals(thisItem.getRecurringRate().compareTo(item.getRecurringRate()), 0);
+        assertEquals(thisItem.getFixedAmount().compareTo(item.getFixedAmount()), 0);
         assertEquals(thisItem.getCurrency(), item.getCurrency());
     }
 
@@ -69,7 +70,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
 
         for (int i = 0; i < 3; i++) {
             UUID invoiceId = UUID.randomUUID();
-            DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate.plusMonths(i), startDate.plusMonths(i + 1), "test", rate, rate, Currency.USD);
+            DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate.plusMonths(i), startDate.plusMonths(i + 1), "test", rate, rate, null, Currency.USD);
             invoiceItemDao.create(item);
         }
 
@@ -86,7 +87,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
         for (int i = 0; i < 5; i++) {
             UUID subscriptionId = UUID.randomUUID();
             BigDecimal amount = rate.multiply(new BigDecimal(i + 1));
-            DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, startDate.plusMonths(1), "test", amount, amount, Currency.USD);
+            DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, startDate.plusMonths(1), "test", amount, amount, amount, Currency.USD);
             invoiceItemDao.create(item);
         }
 
@@ -107,7 +108,7 @@ public class InvoiceItemDaoTests extends InvoiceDaoTestBase {
         BigDecimal rate = new BigDecimal("20.00");
 
         UUID subscriptionId = UUID.randomUUID();
-        DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, startDate.plusMonths(1), "test", rate, rate, Currency.USD);
+        DefaultInvoiceItem item = new DefaultInvoiceItem(invoiceId, subscriptionId, startDate, startDate.plusMonths(1), "test", rate, rate, rate, Currency.USD);
         invoiceItemDao.create(item);
 
         List<InvoiceItem> items = invoiceItemDao.getInvoiceItemsByAccount(accountId.toString());
diff --git a/invoice/src/test/java/com/ning/billing/invoice/dao/MockSubscription.java b/invoice/src/test/java/com/ning/billing/invoice/dao/MockSubscription.java
new file mode 100644
index 0000000..005a605
--- /dev/null
+++ b/invoice/src/test/java/com/ning/billing/invoice/dao/MockSubscription.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2010-2011 Ning, Inc.
+ *
+ * Ning licenses this file to you under the Apache License, version 2.0
+ * (the "License"); you may not use this file except in compliance with the
+ * License.  You may obtain a copy of the License at:
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.ning.billing.invoice.dao;
+
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.Plan;
+import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
+import com.ning.billing.entitlement.api.user.Subscription;
+import com.ning.billing.entitlement.api.user.SubscriptionTransition;
+import org.joda.time.DateTime;
+
+import java.util.List;
+import java.util.UUID;
+
+public class MockSubscription implements Subscription {
+    private UUID subscriptionId = UUID.randomUUID();
+
+    @Override
+    public void cancel(DateTime requestedDate, boolean eot) throws EntitlementUserApiException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void uncancel() throws EntitlementUserApiException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void changePlan(String productName, BillingPeriod term, String planSet, DateTime requestedDate) throws EntitlementUserApiException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void pause() throws EntitlementUserApiException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void resume() throws EntitlementUserApiException {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public UUID getId() {
+        return subscriptionId;
+    }
+
+    @Override
+    public UUID getBundleId() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SubscriptionState getState() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DateTime getStartDate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DateTime getEndDate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public Plan getCurrentPlan() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public String getCurrentPriceList() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public PlanPhase getCurrentPhase() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DateTime getChargedThroughDate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DateTime getPaidThroughDate() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<SubscriptionTransition> getActiveTransitions() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public List<SubscriptionTransition> getAllTransitions() {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public SubscriptionTransition getPendingTransition() {
+        throw new UnsupportedOperationException();
+    }
+}
\ No newline at end of file
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 fb29cc6..1d0c358 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
@@ -18,6 +18,8 @@ package com.ning.billing.invoice.glue;
 
 import java.io.IOException;
 
+import com.ning.billing.invoice.api.test.InvoiceTestApi;
+import com.ning.billing.invoice.api.test.DefaultInvoiceTestApi;
 import com.ning.billing.invoice.dao.InvoicePaymentSqlDao;
 import org.skife.jdbi.v2.IDBI;
 import com.ning.billing.account.glue.AccountModule;
@@ -72,6 +74,8 @@ public class InvoiceModuleWithEmbeddedDb extends InvoiceModule {
 
         super.configure();
 
+        bind(InvoiceTestApi.class).to(DefaultInvoiceTestApi.class).asEagerSingleton();
+
         install(new BusModule());
     }
 }
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 11c3b1d..702801b 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
@@ -16,9 +16,13 @@
 
 package com.ning.billing.invoice.tests;
 
-import com.ning.billing.catalog.MockCatalog;
+import com.ning.billing.catalog.DefaultPrice;
+import com.ning.billing.catalog.MockInternationalPrice;
+import com.ning.billing.catalog.MockPlan;
+import com.ning.billing.catalog.MockPlanPhase;
 import com.ning.billing.catalog.api.BillingPeriod;
 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;
@@ -37,7 +41,9 @@ import com.ning.billing.invoice.model.InvoiceItemList;
 import org.joda.time.DateTime;
 import org.testng.annotations.Test;
 
+import javax.annotation.Nullable;
 import java.math.BigDecimal;
+import java.util.List;
 import java.util.UUID;
 
 import static org.testng.Assert.assertEquals;
@@ -47,7 +53,6 @@ import static org.testng.Assert.assertNull;
 @Test(groups = {"fast", "invoicing", "invoiceGenerator"})
 public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
     private final InvoiceGenerator generator = new DefaultInvoiceGenerator();
-    private final MockCatalog catalog = new MockCatalog();
 
     @Test
     public void testWithNullEventSetAndNullInvoiceSet() {
@@ -74,14 +79,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
 
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(UUID.randomUUID()));
         DateTime startDate = buildDateTime(2011, 9, 1);
-        MockCatalog catalog = new MockCatalog();
-        Plan plan = catalog.getCurrentPlans()[0];
-        PlanPhase phase = plan.getAllPhases()[0];
+
+        Plan plan = new MockPlan();
+        BigDecimal rate1 = TEN;
+        PlanPhase phase = createMockMonthlyPlanPhase(rate1);
         
-        BillingEvent event = new DefaultBillingEvent(sub, startDate, plan, phase,
-                                                     new InternationalPriceMock(ZERO),
-                                                     new InternationalPriceMock(TEN), BillingPeriod.MONTHLY,
-                                                     1, BillingModeType.IN_ADVANCE, "Test");
+        BillingEvent event = createBillingEvent(sub.getId(), startDate, plan, phase, 1);
         events.add(event);
 
         InvoiceItemList existingInvoiceItems = new InvoiceItemList();
@@ -102,14 +105,11 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
 
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(UUID.randomUUID()));
         DateTime startDate = buildDateTime(2011, 9, 1);
-        MockCatalog catalog = new MockCatalog();
-        Plan plan = catalog.getCurrentPlans()[0];
-        PlanPhase phase = plan.getAllPhases()[0];
+
+        Plan plan = new MockPlan();
         BigDecimal rate = TEN;
-        BillingEvent event = new DefaultBillingEvent(sub, startDate, plan, phase,
-                                                     new InternationalPriceMock(ZERO),
-                                                     new InternationalPriceMock(rate), BillingPeriod.MONTHLY,
-                                                     15, BillingModeType.IN_ADVANCE,"Test");
+        PlanPhase phase = createMockMonthlyPlanPhase(rate);
+        BillingEvent event = createBillingEvent(sub.getId(), startDate, plan, phase, 15);
         events.add(event);
 
         InvoiceItemList existingInvoiceItems = new InvoiceItemList();
@@ -131,23 +131,20 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
     public void testTwoMonthlySubscriptionsWithAlignedBillingDates() {
         BillingEventSet events = new BillingEventSet();
 
-        Plan plan1 = catalog.getCurrentPlans()[0];
-        PlanPhase phase1 = plan1.getAllPhases()[0];
-        Plan plan2 = catalog.getCurrentPlans()[1];
-        PlanPhase phase2 = plan2.getAllPhases()[0];
+        Plan plan1 = new MockPlan();
+        BigDecimal rate1 = FIVE;
+        PlanPhase phase1 = createMockMonthlyPlanPhase(rate1);
+
+        Plan plan2 = new MockPlan();
+        BigDecimal rate2 = TEN;
+        PlanPhase phase2 = createMockMonthlyPlanPhase(rate2);
         
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(UUID.randomUUID()));
 
-        BillingEvent event1 = new DefaultBillingEvent(sub, buildDateTime(2011, 9, 1), plan1, phase1,
-                                                      new InternationalPriceMock(ZERO),
-                                                      new InternationalPriceMock(FIVE), BillingPeriod.MONTHLY,
-                                                      1, BillingModeType.IN_ADVANCE, "Test");
+        BillingEvent event1 = createBillingEvent(sub.getId(), buildDateTime(2011, 9, 1), plan1, phase1, 1);
         events.add(event1);
 
-        BillingEvent event2 = new DefaultBillingEvent(sub, buildDateTime(2011, 10, 1), plan2, phase2,
-                                                      new InternationalPriceMock(ZERO),
-                                                      new InternationalPriceMock(TEN), BillingPeriod.MONTHLY,
-                                                      1, BillingModeType.IN_ADVANCE, "Test");
+        BillingEvent event2 = createBillingEvent(sub.getId(), buildDateTime(2011, 10, 1), plan2, phase2, 1);
         events.add(event2);
 
         InvoiceItemList existingInvoiceItems = new InvoiceItemList();
@@ -157,29 +154,25 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 2);
-        assertEquals(invoice.getTotalAmount(), FIVE.add(TEN).setScale(NUMBER_OF_DECIMALS));
+        assertEquals(invoice.getTotalAmount(), rate1.add(rate2).setScale(NUMBER_OF_DECIMALS));
     }
 
     @Test
     public void testOnePlan_TwoMonthlyPhases_ChangeImmediate() {
         BillingEventSet events = new BillingEventSet();
 
-        MockCatalog catalog = new MockCatalog();
-        Plan plan1 = catalog.getCurrentPlans()[0];
-        PlanPhase phase1 = plan1.getAllPhases()[0];
+        Plan plan1 = new MockPlan();
+        BigDecimal rate1 = FIVE;
+        PlanPhase phase1 = createMockMonthlyPlanPhase(rate1);
 
         
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(UUID.randomUUID()));
-        BillingEvent event1 = new DefaultBillingEvent(sub, buildDateTime(2011, 9, 1),
-                                               plan1,phase1,
-                                               new InternationalPriceMock(ZERO),new InternationalPriceMock(FIVE), BillingPeriod.MONTHLY,
-                                               1, BillingModeType.IN_ADVANCE,"Test");
+        BillingEvent event1 = createBillingEvent(sub.getId(), buildDateTime(2011, 9, 1), plan1,phase1, 1);
         events.add(event1);
 
-        BillingEvent event2 = new DefaultBillingEvent(sub, buildDateTime(2011, 10, 15),
-                                               plan1,phase1, //technically should be a different phase but it doesn't impact the test
-                                               new InternationalPriceMock(ZERO),new InternationalPriceMock(TEN), BillingPeriod.MONTHLY,
-                                               15, BillingModeType.IN_ADVANCE,"Test");
+        BigDecimal rate2 = TEN;
+        PlanPhase phase2 = createMockMonthlyPlanPhase(rate2);
+        BillingEvent event2 = createBillingEvent(sub.getId(), buildDateTime(2011, 10, 15), plan1, phase2, 15);
         events.add(event2);
 
         InvoiceItemList existingInvoiceItems = new InvoiceItemList();
@@ -196,8 +189,8 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         BigDecimal numberOfCyclesEvent2 = TWO;
 
         BigDecimal expectedValue;
-        expectedValue = numberOfCyclesEvent1.multiply(FIVE);
-        expectedValue = expectedValue.add(numberOfCyclesEvent2.multiply(TEN));
+        expectedValue = numberOfCyclesEvent1.multiply(rate1);
+        expectedValue = expectedValue.add(numberOfCyclesEvent2.multiply(rate2));
         expectedValue = expectedValue.setScale(NUMBER_OF_DECIMALS);
 
         assertEquals(invoice.getTotalAmount(), expectedValue);
@@ -207,28 +200,22 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
     public void testOnePlan_ThreeMonthlyPhases_ChangeEOT() {
         BillingEventSet events = new BillingEventSet();
 
-        MockCatalog catalog = new MockCatalog();
-        Plan plan1 = catalog.getCurrentPlans()[0];
-        PlanPhase phase1 = plan1.getAllPhases()[0];
-
+        Plan plan1 = new MockPlan();
+        BigDecimal rate1 = FIVE;
+        PlanPhase phase1 = createMockMonthlyPlanPhase(rate1);
 
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(UUID.randomUUID()));
-        BillingEvent event1 = new DefaultBillingEvent(sub, buildDateTime(2011, 9, 1),
-        										plan1,phase1,
-                                               new InternationalPriceMock(ZERO),new InternationalPriceMock(FIVE), BillingPeriod.MONTHLY,
-                                               1, BillingModeType.IN_ADVANCE,"Test");
+        BillingEvent event1 = createBillingEvent(sub.getId(), buildDateTime(2011, 9, 1), plan1, phase1, 1);
         events.add(event1);
 
-        BillingEvent event2 = new DefaultBillingEvent(sub, buildDateTime(2011, 10, 1),
-												plan1,phase1, //technically should be a different phase but it doesn't impact the test
-                                               new InternationalPriceMock(ZERO),new InternationalPriceMock(TEN), BillingPeriod.MONTHLY,
-                                               1, BillingModeType.IN_ADVANCE,"Test");
+        BigDecimal rate2 = TEN;
+        PlanPhase phase2 = createMockMonthlyPlanPhase(rate2);
+        BillingEvent event2 = createBillingEvent(sub.getId(), buildDateTime(2011, 10, 1), plan1, phase2, 1);
         events.add(event2);
 
-        BillingEvent event3 = new DefaultBillingEvent(sub, buildDateTime(2011, 11, 1),
-												plan1,phase1, //technically should be a different phase but it doesn't impact the test
-                                               new InternationalPriceMock(ZERO),new InternationalPriceMock(THIRTY), BillingPeriod.MONTHLY,
-                                               1, BillingModeType.IN_ADVANCE,"Test");
+        BigDecimal rate3 = THIRTY;
+        PlanPhase phase3 = createMockMonthlyPlanPhase(rate3);
+        BillingEvent event3 = createBillingEvent(sub.getId(), buildDateTime(2011, 11, 1), plan1, phase3, 1);
         events.add(event3);
 
         InvoiceItemList existingInvoiceItems = new InvoiceItemList();
@@ -238,7 +225,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
 
         assertNotNull(invoice);
         assertEquals(invoice.getNumberOfItems(), 3);
-        assertEquals(invoice.getTotalAmount(), FIVE.add(TEN).add(TWO.multiply(THIRTY)).setScale(NUMBER_OF_DECIMALS));
+        assertEquals(invoice.getTotalAmount(), rate1.add(rate2).add(TWO.multiply(rate3)).setScale(NUMBER_OF_DECIMALS));
     }
 
     @Test
@@ -247,30 +234,24 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
 
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(UUID.randomUUID()));
         DateTime startDate = buildDateTime(2011, 9, 1);
-        
-        MockCatalog catalog = new MockCatalog();
-        Plan plan1 = catalog.getCurrentPlans()[0];
-        PlanPhase phase1 = plan1.getAllPhases()[0];
-        
+
+        Plan plan1 = new MockPlan();
         BigDecimal rate = FIVE;
-        BillingEvent event1 = new DefaultBillingEvent(sub, startDate,
-        										plan1,phase1,
-                                               new InternationalPriceMock(ZERO),new InternationalPriceMock(rate), BillingPeriod.MONTHLY,
-                                               1, BillingModeType.IN_ADVANCE,"Test");
+        PlanPhase phase1 = createMockMonthlyPlanPhase(rate);
+        
+        BillingEvent event1 = createBillingEvent(sub.getId(), startDate, plan1, phase1, 1);
         events.add(event1);
 
+        DateTime targetDate = buildDateTime(2011, 12, 1);
+        UUID accountId = UUID.randomUUID();
+        Invoice invoice1 = generator.generateInvoice(accountId, events, null, targetDate, Currency.USD);
         InvoiceItemList existingInvoiceItems = new InvoiceItemList();
-        InvoiceItem invoiceItem = new DefaultInvoiceItem(UUID.randomUUID(), sub.getId(), startDate, buildDateTime(2012, 1, 1), "",
-                                                 rate.multiply(FOUR), rate, Currency.USD);
-        existingInvoiceItems.add(invoiceItem);
+        existingInvoiceItems.addAll(invoice1.getInvoiceItems());
 
-        DateTime targetDate = buildDateTime(2011, 12, 3);
-        UUID accountId = UUID.randomUUID();
-        Invoice invoice = generator.generateInvoice(accountId, events, existingInvoiceItems, targetDate, Currency.USD);
+        targetDate = buildDateTime(2011, 12, 3);
+        Invoice invoice2 = generator.generateInvoice(accountId, events, existingInvoiceItems, targetDate, Currency.USD);
 
-        assertNotNull(invoice);
-        assertEquals(invoice.getNumberOfItems(), 0);
-        assertEquals(invoice.getTotalAmount(), ZERO);
+        assertNull(invoice2);
     }
 
     @Test
@@ -282,37 +263,44 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         // plan 5: addon to plan 2, with bill cycle alignment to plan; immediate cancellation
 
         UUID subscriptionId1 = UUID.randomUUID();
-        Plan plan1 = catalog.getCurrentPlans()[0];
-        PlanPhase plan1Phase1 = plan1.getAllPhases()[0]; PlanPhase plan1Phase2 = plan1.getAllPhases()[0]; PlanPhase plan1Phase3 = plan1.getAllPhases()[0];
+        UUID subscriptionId2 = UUID.randomUUID();
+        UUID subscriptionId3 = UUID.randomUUID();
+        UUID subscriptionId4 = UUID.randomUUID();
+        UUID subscriptionId5 = UUID.randomUUID();
+
+        Plan plan1 = new MockPlan("Change from trial to discount with immediate cancellation");
+        PlanPhase plan1Phase1 = createMockMonthlyPlanPhase(EIGHT, PhaseType.TRIAL);
+        PlanPhase plan1Phase2 = createMockMonthlyPlanPhase(TWELVE, PhaseType.DISCOUNT);
+        PlanPhase plan1Phase3 = createMockMonthlyPlanPhase();
         DateTime plan1StartDate = buildDateTime(2011, 1, 5);
         DateTime plan1PhaseChangeDate = buildDateTime(2011, 4, 5);
         DateTime plan1CancelDate = buildDateTime(2011, 4, 29);
 
-        UUID subscriptionId2 = UUID.randomUUID();
-        Plan plan2 = catalog.getCurrentPlans()[1];
-        PlanPhase plan2Phase1 = plan2.getAllPhases()[0]; PlanPhase plan2Phase2 = plan2.getAllPhases()[0]; PlanPhase plan2Phase3 = plan2.getAllPhases()[0];
+        Plan plan2 = new MockPlan("Change phase from trial to discount to evergreen");
+        PlanPhase plan2Phase1 = createMockMonthlyPlanPhase(TWENTY, PhaseType.TRIAL);
+        PlanPhase plan2Phase2 = createMockMonthlyPlanPhase(THIRTY, PhaseType.DISCOUNT);
+        PlanPhase plan2Phase3 = createMockMonthlyPlanPhase(FORTY, PhaseType.EVERGREEN);
         DateTime plan2StartDate = buildDateTime(2011, 3, 10);
         DateTime plan2PhaseChangeToDiscountDate = buildDateTime(2011, 6, 10);
         DateTime plan2PhaseChangeToEvergreenDate = buildDateTime(2011, 9, 10);
 
-        UUID subscriptionId3 = UUID.randomUUID();
-        Plan plan3 = catalog.getCurrentPlans()[2];
-        PlanPhase plan3Phase1 = plan3.getAllPhases()[0]; PlanPhase plan3Phase2 = plan3.getAllPhases()[0];
+        Plan plan3 = new MockPlan("Upgrade with immediate change, BCD = 31");
+        PlanPhase plan3Phase1 = createMockMonthlyPlanPhase(TEN, PhaseType.EVERGREEN);
+        PlanPhase plan3Phase2 = createMockAnnualPlanPhase(ONE_HUNDRED, PhaseType.EVERGREEN);
         DateTime plan3StartDate = buildDateTime(2011, 5, 20);
         DateTime plan3UpgradeToAnnualDate = buildDateTime(2011, 7, 31);
 
-        UUID subscriptionId4 = UUID.randomUUID();
-        Plan plan4a = catalog.getCurrentPlans()[0];
-        Plan plan4b = catalog.getCurrentPlans()[1];
-        PlanPhase plan4aPhase1 = plan4a.getAllPhases()[0];
-        PlanPhase plan4bPhase1 = plan4b.getAllPhases()[0];
+        Plan plan4a = new MockPlan("Plan change effective EOT; plan 1");
+        Plan plan4b = new MockPlan("Plan change effective EOT; plan 2");
+        PlanPhase plan4aPhase1 = createMockMonthlyPlanPhase(FIFTEEN);
+        PlanPhase plan4bPhase1 = createMockMonthlyPlanPhase(TWENTY_FOUR);
 
         DateTime plan4StartDate = buildDateTime(2011, 6, 7);
         DateTime plan4ChangeOfPlanDate = buildDateTime(2011, 8, 7);
 
-        UUID subscriptionId5 = UUID.randomUUID();
-        Plan plan5 = catalog.getCurrentPlans()[2];
-        PlanPhase plan5Phase1 = plan5.getAllPhases()[0]; PlanPhase plan5Phase2 = plan5.getAllPhases()[0];
+        Plan plan5 = new MockPlan("Add-on");
+        PlanPhase plan5Phase1 = createMockMonthlyPlanPhase(TWENTY);
+        PlanPhase plan5Phase2 = createMockMonthlyPlanPhase();
         DateTime plan5StartDate = buildDateTime(2011, 6, 21);
         DateTime plan5CancelDate = buildDateTime(2011, 10, 7);
 
@@ -321,7 +309,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         BillingEventSet events = new BillingEventSet();
 
         // on 1/5/2011, create subscription 1 (trial)
-        events.add(createBillingEvent(subscriptionId1, plan1StartDate, plan1, plan1Phase1, EIGHT, 5));
+        events.add(createBillingEvent(subscriptionId1, plan1StartDate, plan1, plan1Phase1, 5));
         expectedAmount = EIGHT;
         testInvoiceGeneration(events, invoiceItems, plan1StartDate, 1, expectedAmount);
 
@@ -334,12 +322,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 3, 5), 1, expectedAmount);
 
         // on 3/10/2011, create subscription 2 (trial)
-        events.add(createBillingEvent(subscriptionId2, plan2StartDate, plan2, plan2Phase1, TWENTY, 10));
+        events.add(createBillingEvent(subscriptionId2, plan2StartDate, plan2, plan2Phase1, 10));
         expectedAmount = TWENTY;
         testInvoiceGeneration(events, invoiceItems, plan2StartDate, 1, expectedAmount);
 
         // on 4/5/2011, invoice subscription 1 (discount)
-        events.add(createBillingEvent(subscriptionId1, plan1PhaseChangeDate, plan1, plan1Phase2, TWELVE, 5));
+        events.add(createBillingEvent(subscriptionId1, plan1PhaseChangeDate, plan1, plan1Phase2, 5));
         expectedAmount = TWELVE;
         testInvoiceGeneration(events, invoiceItems, plan1PhaseChangeDate, 1, expectedAmount);
 
@@ -348,7 +336,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 4, 10), 1, expectedAmount);
 
         // on 4/29/2011, cancel subscription 1
-        events.add(createBillingEvent(subscriptionId1, plan1CancelDate, plan1, plan1Phase3, ZERO, 5));
+        events.add(createBillingEvent(subscriptionId1, plan1CancelDate, plan1, plan1Phase3, 5));
         expectedAmount = TWELVE.multiply(SIX.divide(THIRTY, NUMBER_OF_DECIMALS, ROUNDING_METHOD)).negate().setScale(NUMBER_OF_DECIMALS);
         testInvoiceGeneration(events, invoiceItems, plan1CancelDate, 2, expectedAmount);
 
@@ -357,17 +345,17 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 5, 10), 1, expectedAmount);
 
         // on 5/20/2011, create subscription 3 (monthly)
-        events.add(createBillingEvent(subscriptionId3, plan3StartDate, plan3, plan3Phase1, TEN, 20));
+        events.add(createBillingEvent(subscriptionId3, plan3StartDate, plan3, plan3Phase1, 20));
         expectedAmount = TEN;
         testInvoiceGeneration(events, invoiceItems, plan3StartDate, 1, expectedAmount);
 
         // on 6/7/2011, create subscription 4
-        events.add(createBillingEvent(subscriptionId4, plan4StartDate, plan4a, plan4aPhase1, FIFTEEN, 7));
+        events.add(createBillingEvent(subscriptionId4, plan4StartDate, plan4a, plan4aPhase1, 7));
         expectedAmount = FIFTEEN;
         testInvoiceGeneration(events, invoiceItems, plan4StartDate, 1, expectedAmount);
 
         // on 6/10/2011, invoice subscription 2 (discount)
-        events.add(createBillingEvent(subscriptionId2, plan2PhaseChangeToDiscountDate, plan2, plan2Phase2, THIRTY, 10));
+        events.add(createBillingEvent(subscriptionId2, plan2PhaseChangeToDiscountDate, plan2, plan2Phase2, 10));
         expectedAmount = THIRTY;
         testInvoiceGeneration(events, invoiceItems, plan2PhaseChangeToDiscountDate, 1, expectedAmount);
 
@@ -376,7 +364,7 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 6, 20), 1, expectedAmount);
 
         // on 6/21/2011, create add-on (subscription 5)
-        events.add(createBillingEvent(subscriptionId5, plan5StartDate, plan5, plan5Phase1, TWENTY, 10));
+        events.add(createBillingEvent(subscriptionId5, plan5StartDate, plan5, plan5Phase1, 10));
         expectedAmount = TWENTY.multiply(NINETEEN.divide(THIRTY, NUMBER_OF_DECIMALS, ROUNDING_METHOD)).setScale(NUMBER_OF_DECIMALS);
         testInvoiceGeneration(events, invoiceItems, plan5StartDate, 1, expectedAmount);
 
@@ -393,14 +381,14 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 7, 20), 1, expectedAmount);
 
         // on 7/31/2011, convert subscription 3 to annual
-        events.add(createAnnualBillingEvent(subscriptionId3, plan3UpgradeToAnnualDate, plan3, plan3Phase2, ONE_HUNDRED, 31));
+        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);
         testInvoiceGeneration(events, invoiceItems, plan3UpgradeToAnnualDate, 3, expectedAmount);
 
         // on 8/7/2011, invoice subscription 4 (plan 2)
-        events.add(createBillingEvent(subscriptionId4, plan4ChangeOfPlanDate, plan4b, plan4bPhase1, TWENTY_FOUR, 7));
+        events.add(createBillingEvent(subscriptionId4, plan4ChangeOfPlanDate, plan4b, plan4bPhase1, 7));
         expectedAmount = TWENTY_FOUR;
         testInvoiceGeneration(events, invoiceItems, plan4ChangeOfPlanDate, 1, expectedAmount);
 
@@ -413,12 +401,12 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 9, 7), 1, expectedAmount);
 
         // on 9/10/2011, invoice plan 2 (evergreen), invoice subscription 5
-        events.add(createBillingEvent(subscriptionId2, plan2PhaseChangeToEvergreenDate, plan2, plan2Phase3, FORTY, 10));
+        events.add(createBillingEvent(subscriptionId2, plan2PhaseChangeToEvergreenDate, plan2, plan2Phase3, 10));
         expectedAmount = FORTY.add(TWENTY);
         testInvoiceGeneration(events, invoiceItems, plan2PhaseChangeToEvergreenDate, 2, expectedAmount);
 
         // on 10/7/2011, invoice subscription 4 (plan 2), cancel subscription 5
-        events.add(createBillingEvent(subscriptionId5, plan5CancelDate, plan5, plan5Phase2, ZERO, 10));
+        events.add(createBillingEvent(subscriptionId5, plan5CancelDate, plan5, plan5Phase2, 10));
         expectedAmount = TWENTY_FOUR.add(TWENTY.multiply(THREE.divide(THIRTY)).negate().setScale(NUMBER_OF_DECIMALS));
         testInvoiceGeneration(events, invoiceItems, plan5CancelDate, 3, expectedAmount);
 
@@ -427,24 +415,32 @@ public class DefaultInvoiceGeneratorTests extends InvoicingTestBase {
         testInvoiceGeneration(events, invoiceItems, buildDateTime(2011, 10, 10), 1, expectedAmount);
     }
 
-    private DefaultBillingEvent createBillingEvent(final UUID subscriptionId, final DateTime startDate,
-                                                   final Plan plan, final PlanPhase planPhase,
-                                                   final BigDecimal rate, final int billCycleDay) {
-        Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(subscriptionId));
+    private MockPlanPhase createMockMonthlyPlanPhase() {
+        return new MockPlanPhase(null, null, BillingPeriod.MONTHLY);
+    }
 
-        return new DefaultBillingEvent(sub, startDate, plan, planPhase,
-                                       new InternationalPriceMock(ZERO),
-                                       new InternationalPriceMock(rate), BillingPeriod.MONTHLY,
-                                       billCycleDay, BillingModeType.IN_ADVANCE,"Test");
+    private MockPlanPhase createMockMonthlyPlanPhase(@Nullable final BigDecimal recurringRate) {
+        return new MockPlanPhase(new MockInternationalPrice(new DefaultPrice(recurringRate, Currency.USD)),
+                                 null, BillingPeriod.MONTHLY);
+    }
+
+    private MockPlanPhase createMockMonthlyPlanPhase(final BigDecimal recurringRate, final PhaseType phaseType) {
+        return new MockPlanPhase(new MockInternationalPrice(new DefaultPrice(recurringRate, Currency.USD)),
+                                 null, BillingPeriod.MONTHLY, phaseType);
     }
 
-    private DefaultBillingEvent createAnnualBillingEvent(final UUID subscriptionId, final DateTime startDate,
-                                                         final Plan plan, final PlanPhase planPhase,
-                                                         final BigDecimal rate, final int billCycleDay) {
+    private MockPlanPhase createMockAnnualPlanPhase(final BigDecimal recurringRate, final PhaseType phaseType) {
+        return new MockPlanPhase(new MockInternationalPrice(new DefaultPrice(recurringRate, Currency.USD)),
+                                 null, BillingPeriod.ANNUAL, phaseType);
+    }
+
+    private DefaultBillingEvent createBillingEvent(final UUID subscriptionId, final DateTime startDate,
+                                                   final Plan plan, final PlanPhase planPhase, final int billCycleDay) {
         Subscription sub = new SubscriptionData(new SubscriptionBuilder().setId(subscriptionId));
+
         return new DefaultBillingEvent(sub, startDate, plan, planPhase,
-                                       new InternationalPriceMock(ZERO),
-                                       new InternationalPriceMock(rate), BillingPeriod.ANNUAL,
+                                       planPhase.getFixedPrice(),
+                                       planPhase.getRecurringPrice(), planPhase.getBillingPeriod(),
                                        billCycleDay, BillingModeType.IN_ADVANCE,"Test");
     }
 

payment/pom.xml 2(+1 -1)

diff --git a/payment/pom.xml b/payment/pom.xml
index 17acd85..3e050f0 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>
diff --git a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
index 5e3f076..22d3c50 100644
--- a/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
+++ b/payment/src/test/java/com/ning/billing/payment/api/TestPaymentApi.java
@@ -74,6 +74,7 @@ public abstract class TestPaymentApi {
                                            "Test",
                                            amount,
                                            new BigDecimal("1.0"),
+                                           null,
                                            Currency.USD));
 
         List<Either<PaymentError, PaymentInfo>> results = paymentApi.createPayment(account.getExternalKey(), Arrays.asList(invoice.getId().toString()));
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 c690352..b4df1ba 100644
--- a/payment/src/test/java/com/ning/billing/payment/TestHelper.java
+++ b/payment/src/test/java/com/ning/billing/payment/TestHelper.java
@@ -71,8 +71,9 @@ public class TestHelper {
                                                item.getStartDate(),
                                                item.getEndDate(),
                                                item.getDescription(),
-                                               item.getAmount(),
-                                               item.getRate(),
+                                               item.getRecurringAmount(),
+                                               item.getRecurringRate(),
+                                               item.getFixedAmount(),
                                                item.getCurrency()));
         }
         invoiceDao.create(invoice);
@@ -83,7 +84,7 @@ public class TestHelper {
         final DateTime now = new DateTime(DateTimeZone.UTC);
         final UUID subscriptionId = UUID.randomUUID();
         final BigDecimal amount = new BigDecimal("10.00");
-        final InvoiceItem item = new DefaultInvoiceItem(null, subscriptionId, now, now.plusMonths(1), "Test", amount, new BigDecimal("1.0"), Currency.USD);
+        final InvoiceItem item = new DefaultInvoiceItem(null, subscriptionId, now, now.plusMonths(1), "Test", amount, new BigDecimal("1.0"), null, Currency.USD);
 
         return createTestInvoice(account, now, Currency.USD, item);
     }

pom.xml 2(+1 -1)

diff --git a/pom.xml b/pom.xml
index 7aa42a0..5ec08b5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -17,7 +17,7 @@
     <groupId>com.ning.billing</groupId>
     <artifactId>killbill</artifactId>
     <packaging>pom</packaging>
-    <version>0.1.4-SNAPSHOT</version>
+    <version>0.1.5-SNAPSHOT</version>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>
     <url>http://github.com/ning/killbill</url>

util/pom.xml 2(+1 -1)

diff --git a/util/pom.xml b/util/pom.xml
index 8013122..b16ecfa 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -13,7 +13,7 @@
     <parent>
         <groupId>com.ning.billing</groupId>
         <artifactId>killbill</artifactId>
-        <version>0.1.4-SNAPSHOT</version>
+        <version>0.1.5-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>