killbill-aplcache

Changes

Details

diff --git a/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java b/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java
index 0d87399..fd90b86 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/billing/EntitlementBillingApi.java
@@ -36,7 +36,7 @@ public interface EntitlementBillingApi {
     public SortedSet<BillingEvent> getBillingEventsForAccount(UUID accountId);
 
     public UUID getAccountIdFromSubscriptionId(UUID subscriptionId);
-
+    
     public void setChargedThroughDate(UUID subscriptionId, DateTime ctd, CallContext context);
 
     public void setChargedThroughDateFromTransaction(Transmogrifier transactionalDao, UUID subscriptionId,
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/EntitlementService.java b/api/src/main/java/com/ning/billing/entitlement/api/EntitlementService.java
index 28084b2..9f284a1 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/EntitlementService.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/EntitlementService.java
@@ -18,6 +18,7 @@ package com.ning.billing.entitlement.api;
 
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
+import com.ning.billing.entitlement.api.repair.EntitlementRepairApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.lifecycle.KillbillService;
 
@@ -31,4 +32,6 @@ public interface EntitlementService extends KillbillService {
     public EntitlementBillingApi getBillingApi();
 
     public EntitlementMigrationApi getMigrationApi();
+    
+    public EntitlementRepairApi getRepairApi();    
 }
diff --git a/api/src/main/java/com/ning/billing/entitlement/api/repair/RepairEntitlementEvent.java b/api/src/main/java/com/ning/billing/entitlement/api/repair/RepairEntitlementEvent.java
index 63af70f..e5bebad 100644
--- a/api/src/main/java/com/ning/billing/entitlement/api/repair/RepairEntitlementEvent.java
+++ b/api/src/main/java/com/ning/billing/entitlement/api/repair/RepairEntitlementEvent.java
@@ -23,7 +23,9 @@ import com.ning.billing.util.bus.BusEvent;
 
 public interface RepairEntitlementEvent extends BusEvent {
 
-    UUID getBundleId();
+    public UUID getAccountId();
+    
+    public UUID getBundleId();
 
-    DateTime getEffectiveDate();
+    public DateTime getEffectiveDate();
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java
index ffa25e6..e62fede 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestBusHandler.java
@@ -27,6 +27,7 @@ import org.testng.Assert;
 
 import com.google.common.base.Joiner;
 import com.google.common.eventbus.Subscribe;
+import com.ning.billing.entitlement.api.repair.RepairEntitlementEvent;
 import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.invoice.api.InvoiceCreationEvent;
 import com.ning.billing.payment.api.PaymentErrorEvent;
@@ -55,7 +56,15 @@ public class TestBusHandler {
         RESUME,
         PHASE,
         INVOICE,
-        PAYMENT
+        PAYMENT,
+        REPAIR_BUNDLE
+    }
+    
+    @Subscribe
+    public void handleEntitlementEvents(RepairEntitlementEvent event) {
+        log.info(String.format("TestBusHandler Got RepairEntitlementEvent event %s", event.toString()));
+        assertEqualsNicely(NextEvent.REPAIR_BUNDLE);
+        notifyIfStackEmpty();
     }
 
     @Subscribe
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
index e334966..61912fc 100644
--- a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegration.java
@@ -21,241 +21,34 @@ import static org.testng.Assert.assertNotNull;
 import static org.testng.Assert.assertTrue;
 import static org.testng.Assert.fail;
 
-import java.io.IOException;
 import java.math.BigDecimal;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 
 import com.ning.billing.account.api.AccountApiException;
 import com.ning.billing.catalog.api.PhaseType;
-import com.ning.billing.dbi.MysqlTestingHelper;
 import com.ning.billing.entitlement.api.user.EntitlementUserApiException;
 
 import com.ning.billing.invoice.api.Invoice;
-import com.ning.billing.invoice.api.InvoiceItem;
-import com.ning.billing.invoice.model.InvoicingConfiguration;
-import com.ning.billing.util.callcontext.CallContext;
-import com.ning.billing.util.callcontext.CallOrigin;
-import com.ning.billing.util.callcontext.UserType;
-import com.ning.billing.util.callcontext.DefaultCallContextFactory;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.RandomStringUtils;
 import org.joda.time.DateTime;
-import org.joda.time.DateTimeZone;
+
 import org.joda.time.Interval;
-import org.skife.jdbi.v2.Handle;
-import org.skife.jdbi.v2.IDBI;
-import org.skife.jdbi.v2.TransactionCallback;
-import org.skife.jdbi.v2.TransactionStatus;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import org.testng.annotations.AfterMethod;
-import org.testng.annotations.AfterSuite;
-
-import org.testng.annotations.BeforeMethod;
-import org.testng.annotations.BeforeSuite;
 import org.testng.annotations.Guice;
 import org.testng.annotations.Test;
 
-import com.google.inject.Inject;
 import com.ning.billing.account.api.Account;
-import com.ning.billing.account.api.AccountData;
-import com.ning.billing.account.api.AccountService;
-import com.ning.billing.account.api.AccountUserApi;
 import com.ning.billing.beatrix.integration.TestBusHandler.NextEvent;
-import com.ning.billing.beatrix.lifecycle.Lifecycle;
 import com.ning.billing.catalog.api.BillingPeriod;
 import com.ning.billing.catalog.api.Currency;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.PriceListSet;
 import com.ning.billing.catalog.api.ProductCategory;
-import com.ning.billing.entitlement.api.EntitlementService;
-import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.SubscriptionBundle;
 import com.ning.billing.entitlement.api.user.SubscriptionData;
-import com.ning.billing.invoice.api.InvoiceService;
-import com.ning.billing.invoice.api.InvoiceUserApi;
-
-import com.ning.billing.util.clock.ClockMock;
-import com.ning.billing.util.bus.BusService;
 
 @Test(groups = "slow")
 @Guice(modules = {MockModule.class})
-public class TestIntegration {
-    private static final int NUMBER_OF_DECIMALS = InvoicingConfiguration.getNumberOfDecimals();
-    private static final int ROUNDING_METHOD = InvoicingConfiguration.getRoundingMode();
-
-    private static final BigDecimal ONE = new BigDecimal("1.0000").setScale(NUMBER_OF_DECIMALS);
-    private static final BigDecimal TWENTY_NINE = new BigDecimal("29.0000").setScale(NUMBER_OF_DECIMALS);
-    private static final BigDecimal THIRTY = new BigDecimal("30.0000").setScale(NUMBER_OF_DECIMALS);
-    private static final BigDecimal THIRTY_ONE = new BigDecimal("31.0000").setScale(NUMBER_OF_DECIMALS);
-
-    private static final Logger log = LoggerFactory.getLogger(TestIntegration.class);
-    private static long AT_LEAST_ONE_MONTH_MS =  31L * 24L * 3600L * 1000L;
-
-    private static final long DELAY = 5000;
-
-    @Inject IDBI dbi;
-
-    @Inject
-    private ClockMock clock;
-    private CallContext context;
-
-    @Inject
-    private Lifecycle lifecycle;
-
-    @Inject
-    private BusService busService;
-
-    @Inject
-    private EntitlementService entitlementService;
-
-    @Inject
-    private InvoiceService invoiceService;
-
-    @Inject
-    private AccountService accountService;
-
-    @Inject
-    private MysqlTestingHelper helper;
-
-    private EntitlementUserApi entitlementUserApi;
-
-    private InvoiceUserApi invoiceUserApi;
-
-    private AccountUserApi accountUserApi;
-
-    private TestBusHandler busHandler;
-
-    private void setupMySQL() throws IOException
-    {
-        final String accountDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/account/ddl.sql"));
-        final String entitlementDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/entitlement/ddl.sql"));
-        final String invoiceDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/invoice/ddl.sql"));
-        final String paymentDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/payment/ddl.sql"));
-        final String utilDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
-
-        helper.startMysql();
-
-        helper.initDb(accountDdl);
-        helper.initDb(entitlementDdl);
-        helper.initDb(invoiceDdl);
-        helper.initDb(paymentDdl);
-        helper.initDb(utilDdl);
-    }
-
-    @BeforeSuite(groups = "slow")
-    public void setup() throws Exception{
-
-        setupMySQL();
-
-        context = new DefaultCallContextFactory(clock).createCallContext("Integration Test", CallOrigin.TEST, UserType.TEST);
-
-        /**
-         * Initialize lifecyle for subset of services
-         */
-        busHandler = new TestBusHandler();
-        lifecycle.fireStartupSequencePriorEventRegistration();
-        busService.getBus().register(busHandler);
-        lifecycle.fireStartupSequencePostEventRegistration();
-
-
-
-        /**
-         * Retrieve APIs
-         */
-        entitlementUserApi = entitlementService.getUserApi();
-        invoiceUserApi = invoiceService.getUserApi();
-        accountUserApi = accountService.getAccountUserApi();
-    }
-
-    @AfterSuite(groups = "slow")
-    public void tearDown() throws Exception {
-        lifecycle.fireShutdownSequencePriorEventUnRegistration();
-        busService.getBus().unregister(busHandler);
-        lifecycle.fireShutdownSequencePostEventUnRegistration();
-        helper.stopMysql();
-    }
-
-
-    @BeforeMethod(groups = "slow")
-    public void setupTest() {
-
-        log.warn("\n");
-        log.warn("RESET TEST FRAMEWORK\n\n");
-        busHandler.reset();
-        clock.resetDeltaFromReality();
-        cleanupData();
-    }
-
-    @AfterMethod(groups = "slow")
-    public void cleanupTest() {
-        log.warn("DONE WITH TEST\n");
-    }
-
-    private void cleanupData() {
-        dbi.inTransaction(new TransactionCallback<Void>() {
-            @Override
-            public Void inTransaction(Handle h, TransactionStatus status)
-                    throws Exception {
-                h.execute("truncate table accounts");
-                h.execute("truncate table entitlement_events");
-                h.execute("truncate table subscriptions");
-                h.execute("truncate table bundles");
-                h.execute("truncate table notifications");
-                h.execute("truncate table claimed_notifications");
-                h.execute("truncate table invoices");
-                h.execute("truncate table fixed_invoice_items");
-                h.execute("truncate table recurring_invoice_items");
-                h.execute("truncate table tag_definitions");
-                h.execute("truncate table tags");
-                h.execute("truncate table custom_fields");
-                h.execute("truncate table invoice_payments");
-                h.execute("truncate table payment_attempts");
-                h.execute("truncate table payments");
-                return null;
-            }
-        });
-    }
-
-    private void verifyTestResult(UUID accountId, UUID subscriptionId,
-                                  DateTime startDate, DateTime endDate,
-                                  BigDecimal amount, DateTime chargeThroughDate,
-                                  int totalInvoiceItemCount) {
-        SubscriptionData subscription = (SubscriptionData) entitlementUserApi.getSubscriptionFromId(subscriptionId);
-
-        List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(accountId);
-        List<InvoiceItem> invoiceItems = new ArrayList<InvoiceItem>();
-        for (Invoice invoice : invoices) {
-            invoiceItems.addAll(invoice.getInvoiceItems());
-        }
-        assertEquals(invoiceItems.size(), totalInvoiceItemCount);
-
-        boolean wasFound = false;
-
-        for (InvoiceItem item : invoiceItems) {
-            if (item.getStartDate().compareTo(startDate) == 0) {
-                if (item.getEndDate().compareTo(endDate) == 0) {
-                    if (item.getAmount().compareTo(amount) == 0) {
-                        wasFound = true;
-                        break;
-                    }
-                }
-            }
-        }
-
-        if (!wasFound) {
-            fail();
-        }
-
-        DateTime ctd = subscription.getChargedThroughDate();
-        assertNotNull(ctd);
-        log.info("Checking CTD: " + ctd.toString() + "; clock is " + clock.getUTCNow().toString());
-        assertTrue(clock.getUTCNow().isBefore(ctd));
-        assertTrue(ctd.compareTo(chargeThroughDate) == 0);
-    }
+public class TestIntegration extends TestIntegrationBase {
 
     @Test(groups = "slow", enabled = true)
     public void testBasePlanCompleteWithBillingDayInPast() throws Exception {
@@ -642,88 +435,4 @@ public class TestIntegration {
         assertNotNull(invoices);
         assertTrue(invoices.size() == 3);
     }
-
-    protected AccountData getAccountData(final int billingDay) {
-
-        final String someRandomKey = RandomStringUtils.randomAlphanumeric(10);
-        return new AccountData() {
-            @Override
-            public String getName() {
-                return "firstName lastName";
-            }
-            @Override
-            public int getFirstNameLength() {
-                return "firstName".length();
-            }
-            @Override
-            public String getEmail() {
-                return  someRandomKey + "@laposte.fr";
-            }
-            @Override
-            public String getPhone() {
-                return "4152876341";
-            }
-            @Override
-            public String getExternalKey() {
-                return someRandomKey;
-            }
-            @Override
-            public int getBillCycleDay() {
-                return billingDay;
-            }
-            @Override
-            public Currency getCurrency() {
-                return Currency.USD;
-            }
-            @Override
-            public String getPaymentProviderName() {
-                return MockModule.PLUGIN_NAME;
-            }
-
-            @Override
-            public DateTimeZone getTimeZone() {
-                return null;
-            }
-
-            @Override
-            public String getLocale() {
-                return null;
-            }
-
-            @Override
-            public String getAddress1() {
-                return null;
-            }
-
-            @Override
-            public String getAddress2() {
-                return null;
-            }
-
-            @Override
-            public String getCompanyName() {
-                return null;
-            }
-
-            @Override
-            public String getCity() {
-                return null;
-            }
-
-            @Override
-            public String getStateOrProvince() {
-                return null;
-            }
-
-            @Override
-            public String getPostalCode() {
-                return null;
-            }
-
-            @Override
-            public String getCountry() {
-                return null;
-            }
-        };
-    }
 }
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
new file mode 100644
index 0000000..ca2ceae
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestIntegrationBase.java
@@ -0,0 +1,331 @@
+/* 
+ * 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.beatrix.integration;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.RandomStringUtils;
+import org.joda.time.DateTime;
+import org.joda.time.DateTimeZone;
+import org.skife.jdbi.v2.Handle;
+import org.skife.jdbi.v2.IDBI;
+import org.skife.jdbi.v2.TransactionCallback;
+import org.skife.jdbi.v2.TransactionStatus;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeMethod;
+
+import com.google.inject.Inject;
+import com.ning.billing.account.api.AccountData;
+import com.ning.billing.account.api.AccountService;
+import com.ning.billing.account.api.AccountUserApi;
+import com.ning.billing.beatrix.lifecycle.Lifecycle;
+import com.ning.billing.catalog.api.Currency;
+import com.ning.billing.dbi.MysqlTestingHelper;
+import com.ning.billing.entitlement.api.EntitlementService;
+import com.ning.billing.entitlement.api.repair.EntitlementRepairApi;
+import com.ning.billing.entitlement.api.user.EntitlementUserApi;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.invoice.api.Invoice;
+import com.ning.billing.invoice.api.InvoiceItem;
+import com.ning.billing.invoice.api.InvoiceService;
+import com.ning.billing.invoice.api.InvoiceUserApi;
+import com.ning.billing.invoice.model.InvoicingConfiguration;
+import com.ning.billing.util.bus.BusService;
+import com.ning.billing.util.callcontext.CallContext;
+import com.ning.billing.util.callcontext.CallOrigin;
+import com.ning.billing.util.callcontext.DefaultCallContextFactory;
+import com.ning.billing.util.callcontext.UserType;
+import com.ning.billing.util.clock.ClockMock;
+
+public class TestIntegrationBase {
+
+    protected static final int NUMBER_OF_DECIMALS = InvoicingConfiguration.getNumberOfDecimals();
+    protected static final int ROUNDING_METHOD = InvoicingConfiguration.getRoundingMode();
+
+    protected static final BigDecimal ONE = new BigDecimal("1.0000").setScale(NUMBER_OF_DECIMALS);
+    protected static final BigDecimal TWENTY_NINE = new BigDecimal("29.0000").setScale(NUMBER_OF_DECIMALS);
+    protected static final BigDecimal THIRTY = new BigDecimal("30.0000").setScale(NUMBER_OF_DECIMALS);
+    protected static final BigDecimal THIRTY_ONE = new BigDecimal("31.0000").setScale(NUMBER_OF_DECIMALS);
+
+    protected static final Logger log = LoggerFactory.getLogger(TestIntegration.class);
+    protected static long AT_LEAST_ONE_MONTH_MS =  31L * 24L * 3600L * 1000L;
+
+    protected static final long DELAY = 5000;
+
+    @Inject
+    protected IDBI dbi;
+
+    @Inject
+    protected ClockMock clock;
+    
+    protected CallContext context;
+
+    @Inject
+    protected Lifecycle lifecycle;
+
+    @Inject
+    protected BusService busService;
+
+    @Inject
+    protected EntitlementService entitlementService;
+
+    @Inject
+    protected InvoiceService invoiceService;
+
+    @Inject
+    protected AccountService accountService;
+
+    @Inject
+    protected MysqlTestingHelper helper;
+
+    protected EntitlementUserApi entitlementUserApi;
+
+    protected EntitlementRepairApi repairApi;
+    
+    protected InvoiceUserApi invoiceUserApi;
+
+    protected AccountUserApi accountUserApi;
+
+    protected TestBusHandler busHandler;
+
+    protected void setupMySQL() throws IOException
+    {
+        final String accountDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/account/ddl.sql"));
+        final String entitlementDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/entitlement/ddl.sql"));
+        final String invoiceDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/invoice/ddl.sql"));
+        final String paymentDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/payment/ddl.sql"));
+        final String utilDdl = IOUtils.toString(TestIntegration.class.getResourceAsStream("/com/ning/billing/util/ddl.sql"));
+
+        helper.startMysql();
+
+        helper.initDb(accountDdl);
+        helper.initDb(entitlementDdl);
+        helper.initDb(invoiceDdl);
+        helper.initDb(paymentDdl);
+        helper.initDb(utilDdl);
+    }
+
+    @BeforeClass(groups = "slow")
+    public void setup() throws Exception{
+
+        setupMySQL();
+
+        context = new DefaultCallContextFactory(clock).createCallContext("Integration Test", CallOrigin.TEST, UserType.TEST);
+
+        /**
+         * Initialize lifecyle for subset of services
+         */
+        busHandler = new TestBusHandler();
+        lifecycle.fireStartupSequencePriorEventRegistration();
+        busService.getBus().register(busHandler);
+        lifecycle.fireStartupSequencePostEventRegistration();
+
+
+
+        /**
+         * Retrieve APIs
+         */
+        entitlementUserApi = entitlementService.getUserApi();
+        repairApi = entitlementService.getRepairApi();
+        invoiceUserApi = invoiceService.getUserApi();
+        accountUserApi = accountService.getAccountUserApi();
+    }
+
+    @AfterClass(groups = "slow")
+    public void tearDown() throws Exception {
+        lifecycle.fireShutdownSequencePriorEventUnRegistration();
+        busService.getBus().unregister(busHandler);
+        lifecycle.fireShutdownSequencePostEventUnRegistration();
+        helper.stopMysql();
+    }
+
+
+    @BeforeMethod(groups = "slow")
+    public void setupTest() {
+
+        log.warn("\n");
+        log.warn("RESET TEST FRAMEWORK\n\n");
+        busHandler.reset();
+        clock.resetDeltaFromReality();
+        cleanupData();
+    }
+
+    @AfterMethod(groups = "slow")
+    public void cleanupTest() {
+        log.warn("DONE WITH TEST\n");
+    }
+
+    protected void cleanupData() {
+        dbi.inTransaction(new TransactionCallback<Void>() {
+            @Override
+            public Void inTransaction(Handle h, TransactionStatus status)
+                    throws Exception {
+                h.execute("truncate table accounts");
+                h.execute("truncate table entitlement_events");
+                h.execute("truncate table subscriptions");
+                h.execute("truncate table bundles");
+                h.execute("truncate table notifications");
+                h.execute("truncate table claimed_notifications");
+                h.execute("truncate table invoices");
+                h.execute("truncate table fixed_invoice_items");
+                h.execute("truncate table recurring_invoice_items");
+                h.execute("truncate table tag_definitions");
+                h.execute("truncate table tags");
+                h.execute("truncate table custom_fields");
+                h.execute("truncate table invoice_payments");
+                h.execute("truncate table payment_attempts");
+                h.execute("truncate table payments");
+                return null;
+            }
+        });
+    }
+
+    protected void verifyTestResult(UUID accountId, UUID subscriptionId,
+                                  DateTime startDate, DateTime endDate,
+                                  BigDecimal amount, DateTime chargeThroughDate,
+                                  int totalInvoiceItemCount) {
+        SubscriptionData subscription = (SubscriptionData) entitlementUserApi.getSubscriptionFromId(subscriptionId);
+
+        List<Invoice> invoices = invoiceUserApi.getInvoicesByAccount(accountId);
+        List<InvoiceItem> invoiceItems = new ArrayList<InvoiceItem>();
+        for (Invoice invoice : invoices) {
+            invoiceItems.addAll(invoice.getInvoiceItems());
+        }
+        assertEquals(invoiceItems.size(), totalInvoiceItemCount);
+
+        boolean wasFound = false;
+
+        for (InvoiceItem item : invoiceItems) {
+            if (item.getStartDate().compareTo(startDate) == 0) {
+                if (item.getEndDate().compareTo(endDate) == 0) {
+                    if (item.getAmount().compareTo(amount) == 0) {
+                        wasFound = true;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (!wasFound) {
+            fail();
+        }
+
+        DateTime ctd = subscription.getChargedThroughDate();
+        assertNotNull(ctd);
+        log.info("Checking CTD: " + ctd.toString() + "; clock is " + clock.getUTCNow().toString());
+        assertTrue(clock.getUTCNow().isBefore(ctd));
+        assertTrue(ctd.compareTo(chargeThroughDate) == 0);
+    }
+    
+    
+    protected AccountData getAccountData(final int billingDay) {
+
+        final String someRandomKey = RandomStringUtils.randomAlphanumeric(10);
+        return new AccountData() {
+            @Override
+            public String getName() {
+                return "firstName lastName";
+            }
+            @Override
+            public int getFirstNameLength() {
+                return "firstName".length();
+            }
+            @Override
+            public String getEmail() {
+                return  someRandomKey + "@laposte.fr";
+            }
+            @Override
+            public String getPhone() {
+                return "4152876341";
+            }
+            @Override
+            public String getExternalKey() {
+                return someRandomKey;
+            }
+            @Override
+            public int getBillCycleDay() {
+                return billingDay;
+            }
+            @Override
+            public Currency getCurrency() {
+                return Currency.USD;
+            }
+            @Override
+            public String getPaymentProviderName() {
+                return MockModule.PLUGIN_NAME;
+            }
+
+            @Override
+            public DateTimeZone getTimeZone() {
+                return null;
+            }
+
+            @Override
+            public String getLocale() {
+                return null;
+            }
+
+            @Override
+            public String getAddress1() {
+                return null;
+            }
+
+            @Override
+            public String getAddress2() {
+                return null;
+            }
+
+            @Override
+            public String getCompanyName() {
+                return null;
+            }
+
+            @Override
+            public String getCity() {
+                return null;
+            }
+
+            @Override
+            public String getStateOrProvince() {
+                return null;
+            }
+
+            @Override
+            public String getPostalCode() {
+                return null;
+            }
+
+            @Override
+            public String getCountry() {
+                return null;
+            }
+        };
+    }
+}
diff --git a/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
new file mode 100644
index 0000000..f58482a
--- /dev/null
+++ b/beatrix/src/test/java/com/ning/billing/beatrix/integration/TestRepairIntegration.java
@@ -0,0 +1,337 @@
+/* 
+ * 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.beatrix.integration;
+
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
+import static org.testng.Assert.assertTrue;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.UUID;
+
+import org.joda.time.DateTime;
+import org.joda.time.Interval;
+import org.testng.Assert;
+import org.testng.annotations.Guice;
+import org.testng.annotations.Test;
+
+import com.ning.billing.account.api.Account;
+import com.ning.billing.beatrix.integration.TestBusHandler.NextEvent;
+import com.ning.billing.catalog.api.BillingPeriod;
+import com.ning.billing.catalog.api.PhaseType;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
+import com.ning.billing.catalog.api.PriceListSet;
+import com.ning.billing.catalog.api.ProductCategory;
+import com.ning.billing.entitlement.api.SubscriptionTransitionType;
+import com.ning.billing.entitlement.api.repair.BundleRepair;
+import com.ning.billing.entitlement.api.repair.SubscriptionRepair;
+import com.ning.billing.entitlement.api.repair.SubscriptionRepair.DeletedEvent;
+import com.ning.billing.entitlement.api.repair.SubscriptionRepair.ExistingEvent;
+import com.ning.billing.entitlement.api.repair.SubscriptionRepair.NewEvent;
+import com.ning.billing.entitlement.api.user.SubscriptionBundle;
+import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.user.SubscriptionEvents;
+import com.ning.billing.entitlement.api.user.Subscription.SubscriptionState;
+
+@Test(groups = "slow")
+@Guice(modules = {MockModule.class})
+public class TestRepairIntegration extends TestIntegrationBase {
+    
+    @Test(groups={"slow"}, enabled=true)
+    public void testRepairChangeBPWithAddonIncluded() throws Exception {
+        
+        DateTime initialDate = new DateTime(2012, 4, 25, 0, 3, 42, 0);
+        clock.setDeltaFromReality(initialDate.getMillis() - clock.getUTCNow().getMillis());
+        
+        Account account = accountUserApi.createAccount(getAccountData(25), null, null, context);
+        assertNotNull(account);
+
+        SubscriptionBundle bundle = entitlementUserApi.createBundleForAccount(account.getId(), "whatever", context);
+
+        String productName = "Shotgun";
+        BillingPeriod term = BillingPeriod.MONTHLY;
+        String planSetName = PriceListSet.DEFAULT_PRICELIST_NAME;
+
+        busHandler.pushExpectedEvent(NextEvent.CREATE);
+        busHandler.pushExpectedEvent(NextEvent.INVOICE);
+        SubscriptionData baseSubscription = (SubscriptionData) entitlementUserApi.createSubscription(bundle.getId(),
+                new PlanPhaseSpecifier(productName, ProductCategory.BASE, term, planSetName, null), null, context);
+        assertNotNull(baseSubscription);
+        assertTrue(busHandler.isCompleted(DELAY));
+   
+        // MOVE CLOCK A LITTLE BIT-- STILL IN TRIAL
+        Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+        clock.addDeltaFromReality(it.toDurationMillis());
+
+
+        SubscriptionData aoSubscription = (SubscriptionData) entitlementUserApi.createSubscription(bundle.getId(),
+                new PlanPhaseSpecifier("Telescopic-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null), null, context);
+        
+        SubscriptionData aoSubscription2 = (SubscriptionData) entitlementUserApi.createSubscription(bundle.getId(),
+                new PlanPhaseSpecifier("Laser-Scope", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null), null, context); 
+
+        // MOVE CLOCK A LITTLE BIT MORE -- STILL IN TRIAL
+        it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3));
+        clock.addDeltaFromReality(it.toDurationMillis());
+
+
+        BundleRepair bundleRepair = repairApi.getBundleRepair(bundle.getId());
+        sortEventsOnBundle(bundleRepair);
+        
+        // Quick check
+        SubscriptionRepair bpRepair = getSubscriptionRepair(baseSubscription.getId(), bundleRepair);
+        assertEquals(bpRepair.getExistingEvents().size(), 2);
+        
+        SubscriptionRepair aoRepair = getSubscriptionRepair(aoSubscription.getId(), bundleRepair);
+        assertEquals(aoRepair.getExistingEvents().size(), 2);
+
+        SubscriptionRepair aoRepair2 = getSubscriptionRepair(aoSubscription2.getId(), bundleRepair);
+        assertEquals(aoRepair2.getExistingEvents().size(), 2);
+
+        DateTime bpChangeDate = clock.getUTCNow().minusDays(1);
+        
+        List<DeletedEvent> des = new LinkedList<SubscriptionRepair.DeletedEvent>();
+        des.add(createDeletedEvent(bpRepair.getExistingEvents().get(1).getEventId()));        
+        
+        PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Assault-Rifle", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, PhaseType.TRIAL);
+        NewEvent ne = createNewEvent(SubscriptionTransitionType.CHANGE, bpChangeDate, spec);
+        
+        bpRepair = createSubscriptionReapir(baseSubscription.getId(), des, Collections.singletonList(ne));
+        
+        bundleRepair =  createBundleRepair(bundle.getId(), bundleRepair.getViewId(), Collections.singletonList(bpRepair));
+        
+        // TIME TO  REPAIR
+        busHandler.pushExpectedEvent(NextEvent.REPAIR_BUNDLE);
+        BundleRepair realRunBundleRepair = repairApi.repairBundle(bundleRepair, false, context);
+        assertTrue(busHandler.isCompleted(DELAY));
+        
+        aoRepair = getSubscriptionRepair(aoSubscription.getId(), realRunBundleRepair);
+        assertEquals(aoRepair.getExistingEvents().size(), 2);
+
+        bpRepair = getSubscriptionRepair(baseSubscription.getId(), realRunBundleRepair);
+        assertEquals(bpRepair.getExistingEvents().size(), 3);        
+        
+        // Check expected for AO
+        List<ExistingEvent> expectedAO = new LinkedList<SubscriptionRepair.ExistingEvent>();
+        expectedAO.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, "Telescopic-Scope", PhaseType.DISCOUNT,
+                ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription.getStartDate()));
+        expectedAO.add(createExistingEventForAssertion(SubscriptionTransitionType.CANCEL, "Telescopic-Scope", PhaseType.DISCOUNT,
+                ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, bpChangeDate));
+        int index = 0;
+        for (ExistingEvent e : expectedAO) {
+           validateExistingEventForAssertion(e, aoRepair.getExistingEvents().get(index++));           
+        }
+
+        List<ExistingEvent> expectedAO2 = new LinkedList<SubscriptionRepair.ExistingEvent>();
+        expectedAO2.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, "Laser-Scope", PhaseType.DISCOUNT,
+                ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription2.getStartDate()));
+        expectedAO2.add(createExistingEventForAssertion(SubscriptionTransitionType.PHASE, "Laser-Scope", PhaseType.EVERGREEN,
+                ProductCategory.ADD_ON, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, aoSubscription2.getStartDate().plusMonths(1)));
+        index = 0;
+        for (ExistingEvent e : expectedAO2) {
+           validateExistingEventForAssertion(e, aoRepair2.getExistingEvents().get(index++));           
+        }
+        
+        // Check expected for BP        
+        List<ExistingEvent> expectedBP = new LinkedList<SubscriptionRepair.ExistingEvent>();
+        expectedBP.add(createExistingEventForAssertion(SubscriptionTransitionType.CREATE, "Shotgun", PhaseType.TRIAL,
+                ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, baseSubscription.getStartDate()));
+        expectedBP.add(createExistingEventForAssertion(SubscriptionTransitionType.CHANGE, "Assault-Rifle", PhaseType.TRIAL,
+                ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.NO_BILLING_PERIOD, bpChangeDate));
+        expectedBP.add(createExistingEventForAssertion(SubscriptionTransitionType.PHASE, "Assault-Rifle", PhaseType.EVERGREEN,
+                ProductCategory.BASE, PriceListSet.DEFAULT_PRICELIST_NAME, BillingPeriod.MONTHLY, baseSubscription.getStartDate().plusDays(30)));
+        index = 0;
+        for (ExistingEvent e : expectedBP) {
+           validateExistingEventForAssertion(e, bpRepair.getExistingEvents().get(index++));           
+        }
+
+        SubscriptionData newAoSubscription = (SubscriptionData)  entitlementUserApi.getSubscriptionFromId(aoSubscription.getId());
+        assertEquals(newAoSubscription.getState(), SubscriptionState.CANCELLED);
+        assertEquals(newAoSubscription.getAllTransitions().size(), 2);
+        assertEquals(newAoSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
+            
+        SubscriptionData newAoSubscription2 = (SubscriptionData)  entitlementUserApi.getSubscriptionFromId(aoSubscription2.getId());
+        assertEquals(newAoSubscription2.getState(), SubscriptionState.ACTIVE);
+        assertEquals(newAoSubscription2.getAllTransitions().size(), 2);
+        assertEquals(newAoSubscription2.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
+
+        
+        SubscriptionData newBaseSubscription = (SubscriptionData)  entitlementUserApi.getSubscriptionFromId(baseSubscription.getId());
+        assertEquals(newBaseSubscription.getState(), SubscriptionState.ACTIVE);
+        assertEquals(newBaseSubscription.getAllTransitions().size(), 3);
+        assertEquals(newBaseSubscription.getActiveVersion(), SubscriptionEvents.INITIAL_VERSION + 1);
+        
+    
+ 
+    }
+    
+    protected SubscriptionRepair createSubscriptionReapir(final UUID id, final List<DeletedEvent> deletedEvents, final List<NewEvent> newEvents) {
+        return new SubscriptionRepair() {
+            @Override
+            public UUID getId() {
+                return id;
+            }
+            @Override
+            public List<NewEvent> getNewEvents() {
+                return newEvents;
+            }
+            @Override
+            public List<ExistingEvent> getExistingEvents() {
+                return null;
+            }
+            @Override
+            public List<DeletedEvent> getDeletedEvents() {
+                return deletedEvents;
+            }
+        };
+    }
+
+    
+    protected BundleRepair createBundleRepair(final UUID bundleId, final String viewId, final List<SubscriptionRepair> subscriptionRepair) {
+        return new BundleRepair() {
+            @Override
+            public String getViewId() {
+                return viewId;
+            }
+            @Override
+            public List<SubscriptionRepair> getSubscriptions() {
+                return subscriptionRepair;
+            }
+            @Override
+            public UUID getBundleId() {
+                return bundleId;
+            }
+        };
+    }
+
+    protected ExistingEvent createExistingEventForAssertion(final SubscriptionTransitionType type, 
+            final String productName, final PhaseType phaseType, final ProductCategory category, final String priceListName, final BillingPeriod billingPeriod,
+            final DateTime effectiveDateTime) {
+
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier(productName, category, billingPeriod, priceListName, phaseType);
+        ExistingEvent ev = new ExistingEvent() {
+            @Override
+            public SubscriptionTransitionType getSubscriptionTransitionType() {
+                return type;
+            }
+             @Override
+            public DateTime getRequestedDate() {
+                 return null;
+            }
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                return spec;
+            }
+            @Override
+            public UUID getEventId() {
+                return null;
+            }
+            @Override
+            public DateTime getEffectiveDate() {
+                return effectiveDateTime;
+            }
+        };
+        return ev;
+    }
+    
+    protected SubscriptionRepair getSubscriptionRepair(final UUID id, final BundleRepair bundleRepair) {
+        for (SubscriptionRepair cur : bundleRepair.getSubscriptions()) {
+            if (cur.getId().equals(id)) {
+                return cur;
+            }
+        }
+        Assert.fail("Failed to find SubscriptionReapir " + id);
+        return null;
+    }
+    protected void validateExistingEventForAssertion(final ExistingEvent expected, final ExistingEvent input) {
+        
+        log.info(String.format("Got %s -> Expected %s", input.getPlanPhaseSpecifier().getProductName(), expected.getPlanPhaseSpecifier().getProductName()));
+        assertEquals(input.getPlanPhaseSpecifier().getProductName(), expected.getPlanPhaseSpecifier().getProductName());
+        log.info(String.format("Got %s -> Expected %s", input.getPlanPhaseSpecifier().getPhaseType(), expected.getPlanPhaseSpecifier().getPhaseType()));
+        assertEquals(input.getPlanPhaseSpecifier().getPhaseType(), expected.getPlanPhaseSpecifier().getPhaseType());
+        log.info(String.format("Got %s -> Expected %s", input.getPlanPhaseSpecifier().getProductCategory(), expected.getPlanPhaseSpecifier().getProductCategory()));
+        assertEquals(input.getPlanPhaseSpecifier().getProductCategory(), expected.getPlanPhaseSpecifier().getProductCategory());                    
+        log.info(String.format("Got %s -> Expected %s", input.getPlanPhaseSpecifier().getPriceListName(), expected.getPlanPhaseSpecifier().getPriceListName()));
+        assertEquals(input.getPlanPhaseSpecifier().getPriceListName(), expected.getPlanPhaseSpecifier().getPriceListName());                    
+        log.info(String.format("Got %s -> Expected %s", input.getPlanPhaseSpecifier().getBillingPeriod(), expected.getPlanPhaseSpecifier().getBillingPeriod()));
+        assertEquals(input.getPlanPhaseSpecifier().getBillingPeriod(), expected.getPlanPhaseSpecifier().getBillingPeriod());
+        log.info(String.format("Got %s -> Expected %s", input.getEffectiveDate(), expected.getEffectiveDate()));
+        assertEquals(input.getEffectiveDate(), expected.getEffectiveDate());        
+    }
+    
+    protected DeletedEvent createDeletedEvent(final UUID eventId) {
+        return new DeletedEvent() {
+            @Override
+            public UUID getEventId() {
+                return eventId;
+            }
+        };
+    }
+
+    protected NewEvent createNewEvent(final SubscriptionTransitionType type, final DateTime requestedDate, final PlanPhaseSpecifier spec) {
+
+        return new NewEvent() {
+            @Override
+            public SubscriptionTransitionType getSubscriptionTransitionType() {
+                return type;
+            }
+            @Override
+            public DateTime getRequestedDate() {
+                return requestedDate;
+            }
+            @Override
+            public PlanPhaseSpecifier getPlanPhaseSpecifier() {
+                return spec;
+            }
+        };
+    }
+
+    protected void sortEventsOnBundle(final BundleRepair bundle) {
+        if (bundle.getSubscriptions() == null) {
+            return;
+        }
+        for (SubscriptionRepair cur : bundle.getSubscriptions()) {
+            if (cur.getExistingEvents() != null) {
+                sortExistingEvent(cur.getExistingEvents());
+            }
+            if (cur.getNewEvents() != null) {
+                sortNewEvent(cur.getNewEvents());
+            }
+        }
+    }
+
+    protected void sortExistingEvent(final List<ExistingEvent> events) {
+        Collections.sort(events, new Comparator<ExistingEvent>() {
+            @Override
+            public int compare(ExistingEvent arg0, ExistingEvent arg1) {
+                return arg0.getEffectiveDate().compareTo(arg1.getEffectiveDate());
+            }
+        });
+    }
+    protected void sortNewEvent(final List<NewEvent> events) {
+        Collections.sort(events, new Comparator<NewEvent>() {
+            @Override
+            public int compare(NewEvent arg0, NewEvent arg1) {
+                return arg0.getRequestedDate().compareTo(arg1.getRequestedDate());
+            }
+        });
+    }
+    
+
+}
diff --git a/beatrix/src/test/resources/catalogSample.xml b/beatrix/src/test/resources/catalogSample.xml
index 5b7aeaf..8c13707 100644
--- a/beatrix/src/test/resources/catalogSample.xml
+++ b/beatrix/src/test/resources/catalogSample.xml
@@ -1,43 +1,23 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!--
-  ~ 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.
-  -->
+<!-- ~ 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. -->
 
-<!-- 
-Use cases covered so far:
-	Tiered Product (Pistol/Shotgun/Assault-Rifle)
-	Multiple changeEvent plan policies
-	Multiple PlanAlignment (see below, trial add-on alignments and rescue discount package)
-	Product transition rules
-	Add on (Scopes, Holster)
-	Multi-pack addon (Extra-Ammo)
-	Addon Trial aligned to base plan (holster-monthly-regular)
-	Addon Trial aligned to creation (holster-monthly-special)
-	Rescue discount package (assault-rifle-annual-rescue)
-	Plan phase with a recurring and a one off (refurbish-maintenance)
-	Plan with more than 2 phase (gunclub discount plans)
-		
-Use Cases to do:
-	Tiered Add On
-	Riskfree period
-	
-
-
- -->
+<!-- Use cases covered so far: Tiered Product (Pistol/Shotgun/Assault-Rifle) 
+	Multiple changeEvent plan policies Multiple PlanAlignment (see below, trial 
+	add-on alignments and rescue discount package) Product transition rules Add 
+	on (Scopes, Hoster) Multi-pack addon (Extra-Ammo) Addon Trial aligned to 
+	base plan (holster-monthly-regular) Addon Trial aligned to creation (holster-monthly-special) 
+	Rescue discount package (assault-rifle-annual-rescue) Plan phase with a reccurring 
+	and a one off (refurbish-maintenance) Phan with more than 2 phase (gunclub 
+	discount plans) Use Cases to do: Tiered Add On Riskfree period -->
 <catalog xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:noNamespaceSchemaLocation="CatalogSchema.xsd">
+	xsi:noNamespaceSchemaLocation="CatalogSchema.xsd ">
 
 	<effectiveDate>2011-01-01T00:00:00+00:00</effectiveDate>
 	<catalogName>Firearms</catalogName>
@@ -47,24 +27,24 @@ Use Cases to do:
 		<currency>EUR</currency>
 		<currency>GBP</currency>
 	</currencies>
-	
+
 	<products>
+		<product name="Blowdart">
+			<category>BASE</category>
+		</product>
 		<product name="Pistol">
 			<category>BASE</category>
+		</product>
+		<product name="Shotgun">
+			<category>BASE</category>
 			<available>
 				<addonProduct>Telescopic-Scope</addonProduct>
 				<addonProduct>Laser-Scope</addonProduct>
 			</available>
 		</product>
-        <product name="Blowdart">
-            <category>BASE</category>
-        </product>
-		<product name="Shotgun">
-			<category>BASE</category>
-		</product>
 		<product name="Assault-Rifle">
 			<category>BASE</category>
-			<included> 
+			<included>
 				<addonProduct>Telescopic-Scope</addonProduct>
 			</included>
 			<available>
@@ -87,60 +67,42 @@ Use Cases to do:
 			<category>ADD_ON</category>
 		</product>
 	</products>
-	 
+
 	<rules>
 		<changePolicy>
-			<changePolicyCase> 
+			<changePolicyCase>
 				<phaseType>TRIAL</phaseType>
 				<policy>IMMEDIATE</policy>
 			</changePolicyCase>
-			<changePolicyCase> 
-				<toProduct>Pistol</toProduct>
-				<policy>END_OF_TERM</policy>
+			<changePolicyCase>
+				<toProduct>Assault-Rifle</toProduct>
+				<policy>IMMEDIATE</policy>
 			</changePolicyCase>
-			<changePolicyCase> 
-				<toPriceList>rescue</toPriceList>
-				<policy>END_OF_TERM</policy>
-			</changePolicyCase>		
-			<changePolicyCase> 
+			<changePolicyCase>
 				<fromProduct>Pistol</fromProduct>
 				<toProduct>Shotgun</toProduct>
 				<policy>IMMEDIATE</policy>
 			</changePolicyCase>
-			<changePolicyCase> 
-				<fromProduct>Assault-Rifle</fromProduct>
-				<toProduct>Shotgun</toProduct>
-				<policy>END_OF_TERM</policy>
-			</changePolicyCase>
-			<changePolicyCase> 
-				<fromBillingPeriod>MONTHLY</fromBillingPeriod>
-				<toProduct>Assault-Rifle</toProduct>
-				<toBillingPeriod>MONTHLY</toBillingPeriod>
+			<changePolicyCase>
+				<toPriceList>rescue</toPriceList>
 				<policy>END_OF_TERM</policy>
 			</changePolicyCase>
-			<changePolicyCase> 
-				<toProduct>Assault-Rifle</toProduct>
-				<policy>IMMEDIATE</policy>
-			</changePolicyCase>
-			<changePolicyCase> 
+			<changePolicyCase>
 				<fromBillingPeriod>MONTHLY</fromBillingPeriod>
 				<toBillingPeriod>ANNUAL</toBillingPeriod>
 				<policy>IMMEDIATE</policy>
 			</changePolicyCase>
-			<changePolicyCase> 
+			<changePolicyCase>
 				<fromBillingPeriod>ANNUAL</fromBillingPeriod>
 				<toBillingPeriod>MONTHLY</toBillingPeriod>
 				<policy>END_OF_TERM</policy>
 			</changePolicyCase>
-			<changePolicyCase> 
+			<changePolicyCase>
 				<policy>END_OF_TERM</policy>
 			</changePolicyCase>
 		</changePolicy>
 		<changeAlignment>
 			<changeAlignmentCase>
-				<alignment>START_OF_SUBSCRIPTION</alignment>
-			</changeAlignmentCase>
-			<changeAlignmentCase>
 				<toPriceList>rescue</toPriceList>
 				<alignment>CHANGE_OF_PLAN</alignment>
 			</changeAlignmentCase>
@@ -149,18 +111,25 @@ Use Cases to do:
 				<toPriceList>rescue</toPriceList>
 				<alignment>CHANGE_OF_PRICELIST</alignment>
 			</changeAlignmentCase>
+			<changeAlignmentCase>
+				<alignment>START_OF_SUBSCRIPTION</alignment>
+			</changeAlignmentCase>
 		</changeAlignment>
 		<cancelPolicy>
 			<cancelPolicyCase>
-				<policy>END_OF_TERM</policy>
-			</cancelPolicyCase>
-			<cancelPolicyCase>
 				<phaseType>TRIAL</phaseType>
 				<policy>IMMEDIATE</policy>
 			</cancelPolicyCase>
+			<cancelPolicyCase>
+				<policy>END_OF_TERM</policy>
+			</cancelPolicyCase>
 		</cancelPolicy>
 		<createAlignment>
 			<createAlignmentCase>
+				<product>Laser-Scope</product>
+				<alignment>START_OF_SUBSCRIPTION</alignment>
+			</createAlignmentCase>
+			<createAlignmentCase>
 				<alignment>START_OF_BUNDLE</alignment>
 			</createAlignmentCase>
 		</createAlignment>
@@ -186,21 +155,7 @@ Use Cases to do:
 	</rules>
 
 	<plans>
-		<plan name="pistol-monthly-no-trial">
-			<product>Pistol</product>
-			<finalPhase type="EVERGREEN">
-				<duration>
-					<unit>UNLIMITED</unit>
-				</duration>
-				<billingPeriod>MONTHLY</billingPeriod>
-				<recurringPrice>
-					<price><currency>GBP</currency><value>29.95</value></price>
-					<price><currency>EUR</currency><value>29.95</value></price> 
-					<price><currency>USD</currency><value>29.95</value></price>								
-				</recurringPrice>
-			</finalPhase>
-		</plan>
-        <plan name="blowdart-monthly">
+		<plan name="blowdart-monthly">
 			<product>Blowdart</product>
 			<initialPhases>
 				<phase type="TRIAL">
@@ -219,9 +174,18 @@ Use Cases to do:
 					</duration>
 					<billingPeriod>MONTHLY</billingPeriod>
 					<recurringPrice>
-						<price><currency>USD</currency><value>9.95</value></price>
-						<price><currency>EUR</currency><value>9.95</value></price>
-						<price><currency>GBP</currency><value>9.95</value></price>
+						<price>
+							<currency>USD</currency>
+							<value>9.95</value>
+						</price>
+						<price>
+							<currency>EUR</currency>
+							<value>9.95</value>
+						</price>
+						<price>
+							<currency>GBP</currency>
+							<value>9.95</value>
+						</price>
 					</recurringPrice>
 				</phase>
 			</initialPhases>
@@ -231,25 +195,34 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>29.95</value></price>
-					<price><currency>EUR</currency><value>29.95</value></price>
-					<price><currency>GBP</currency><value>29.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>29.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>29.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>29.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
+
 		<plan name="pistol-monthly">
 			<product>Pistol</product>
 			<initialPhases>
-                <phase type="TRIAL">
-                    <duration>
-                        <unit>DAYS</unit>
-                        <number>30</number>
-                    </duration>
-                    <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
-                    <fixedPrice>
-                    </fixedPrice>
-                    <!-- no price implies $0 -->
-                </phase>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice> <!-- empty price implies $0 -->
+					</fixedPrice>
+				</phase>
 			</initialPhases>
 			<finalPhase type="EVERGREEN">
 				<duration>
@@ -257,9 +230,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>GBP</currency><value>29.95</value></price>
-					<price><currency>EUR</currency><value>29.95</value></price> 
-					<price><currency>USD</currency><value>29.95</value></price>								
+					<price>
+						<currency>GBP</currency>
+						<value>29.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>29.95</value>
+					</price>
+					<price>
+						<currency>USD</currency>
+						<value>29.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -271,10 +253,9 @@ Use Cases to do:
 						<unit>DAYS</unit>
 						<number>30</number>
 					</duration>
-                    <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
-                    <fixedPrice>
-                    </fixedPrice>
-				    <!-- no price implies $0 -->
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice></fixedPrice>
+					<!-- no price implies $0 -->
 				</phase>
 			</initialPhases>
 			<finalPhase type="EVERGREEN">
@@ -284,25 +265,33 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>249.95</value></price>								
-					<price><currency>EUR</currency><value>149.95</value></price>
-					<price><currency>GBP</currency><value>169.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>249.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>149.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>169.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
 		<plan name="assault-rifle-monthly">
 			<product>Assault-Rifle</product>
 			<initialPhases>
-                                <phase type="TRIAL">
-                                        <duration>
-                                                <unit>DAYS</unit>
-                                                <number>30</number>
-                                        </duration>
-                                        <billingPeriod>NO_BILLING_PERIOD</billingPeriod>
-                                        <fixedPrice>
-                                        </fixedPrice>
-                                    <!-- no price implies $0 -->
-                                </phase>
+				<phase type="TRIAL">
+					<duration>
+						<unit>DAYS</unit>
+						<number>30</number>
+					</duration>
+					<billingPeriod>NO_BILLING_PERIOD</billingPeriod>
+					<fixedPrice>
+					</fixedPrice>
+				</phase>
 			</initialPhases>
 			<finalPhase type="EVERGREEN">
 				<duration>
@@ -310,9 +299,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>599.95</value></price>								
-					<price><currency>EUR</currency><value>349.95</value></price>
-					<price><currency>GBP</currency><value>399.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>599.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>349.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>399.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -335,9 +333,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>199.95</value></price>								
-					<price><currency>EUR</currency><value>199.95</value></price>
-					<price><currency>GBP</currency><value>199.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>199.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -360,9 +367,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>2399.95</value></price>								
-					<price><currency>EUR</currency><value>1499.95</value></price>
-					<price><currency>GBP</currency><value>1699.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>2399.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>1499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>1699.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -385,9 +401,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>5999.95</value></price>								
-					<price><currency>EUR</currency><value>3499.95</value></price>
-					<price><currency>GBP</currency><value>3999.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>5999.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>3499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>3999.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -410,9 +435,18 @@ Use Cases to do:
 					</duration>
 					<billingPeriod>MONTHLY</billingPeriod>
 					<recurringPrice>
-						<price><currency>USD</currency><value>9.95</value></price>								
-						<price><currency>EUR</currency><value>9.95</value></price>
-						<price><currency>GBP</currency><value>9.95</value></price>
+						<price>
+							<currency>USD</currency>
+							<value>9.95</value>
+						</price>
+						<price>
+							<currency>EUR</currency>
+							<value>9.95</value>
+						</price>
+						<price>
+							<currency>GBP</currency>
+							<value>9.95</value>
+						</price>
 					</recurringPrice>
 				</phase>
 			</initialPhases>
@@ -422,9 +456,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>199.95</value></price>								
-					<price><currency>EUR</currency><value>199.95</value></price>
-					<price><currency>GBP</currency><value>199.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>199.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -447,9 +490,18 @@ Use Cases to do:
 					</duration>
 					<billingPeriod>MONTHLY</billingPeriod>
 					<recurringPrice>
-						<price><currency>USD</currency><value>19.95</value></price>								
-						<price><currency>EUR</currency><value>49.95</value></price>
-						<price><currency>GBP</currency><value>69.95</value></price>
+						<price>
+							<currency>USD</currency>
+							<value>19.95</value>
+						</price>
+						<price>
+							<currency>EUR</currency>
+							<value>49.95</value>
+						</price>
+						<price>
+							<currency>GBP</currency>
+							<value>69.95</value>
+						</price>
 					</recurringPrice>
 				</phase>
 			</initialPhases>
@@ -459,9 +511,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>2399.95</value></price>								
-					<price><currency>EUR</currency><value>1499.95</value></price>
-					<price><currency>GBP</currency><value>1699.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>2399.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>1499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>1699.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -484,10 +545,19 @@ Use Cases to do:
 					</duration>
 					<billingPeriod>MONTHLY</billingPeriod>
 					<recurringPrice>
-						<price><currency>USD</currency><value>99.95</value></price>								
-						<price><currency>EUR</currency><value>99.95</value></price>
-						<price><currency>GBP</currency><value>99.95</value></price>
-						</recurringPrice>
+						<price>
+							<currency>USD</currency>
+							<value>99.95</value>
+						</price>
+						<price>
+							<currency>EUR</currency>
+							<value>99.95</value>
+						</price>
+						<price>
+							<currency>GBP</currency>
+							<value>99.95</value>
+						</price>
+					</recurringPrice>
 				</phase>
 			</initialPhases>
 			<finalPhase type="EVERGREEN">
@@ -496,37 +566,110 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>5999.95</value></price>								
-					<price><currency>EUR</currency><value>3499.95</value></price>
-					<price><currency>GBP</currency><value>3999.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>5999.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>3499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>3999.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
 		<plan name="laser-scope-monthly">
-		<product>Laser-Scope</product>
+			<product>Laser-Scope</product>
+			<initialPhases>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>1</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price>
+							<currency>USD</currency>
+							<value>999.95</value>
+						</price>
+						<price>
+							<currency>EUR</currency>
+							<value>499.95</value>
+						</price>
+						<price>
+							<currency>GBP</currency>
+							<value>999.95</value>
+						</price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
 			<finalPhase type="EVERGREEN">
 				<duration>
 					<unit>UNLIMITED</unit>
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>1999.95</value></price>								
-					<price><currency>EUR</currency><value>1499.95</value></price>
-					<price><currency>GBP</currency><value>1999.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>1999.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>1499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>1999.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
 		<plan name="telescopic-scope-monthly">
 			<product>Telescopic-Scope</product>
+			<initialPhases>
+				<phase type="DISCOUNT">
+					<duration>
+						<unit>MONTHS</unit>
+						<number>1</number>
+					</duration>
+					<billingPeriod>MONTHLY</billingPeriod>
+					<recurringPrice>
+						<price>
+							<currency>USD</currency>
+							<value>399.95</value>
+						</price>
+						<price>
+							<currency>EUR</currency>
+							<value>299.95</value>
+						</price>
+						<price>
+							<currency>GBP</currency>
+							<value>399.95</value>
+						</price>
+					</recurringPrice>
+				</phase>
+			</initialPhases>
 			<finalPhase type="EVERGREEN">
 				<duration>
 					<unit>UNLIMITED</unit>
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>999.95</value></price>								
-					<price><currency>EUR</currency><value>499.95</value></price>
-					<price><currency>GBP</currency><value>999.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>999.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>999.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -538,9 +681,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>999.95</value></price>								
-					<price><currency>EUR</currency><value>499.95</value></price>
-					<price><currency>GBP</currency><value>999.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>999.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>999.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 			<plansAllowedInBundle>-1</plansAllowedInBundle> <!-- arbitrary number of these (multipack) -->
@@ -564,9 +716,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>199.95</value></price>								
-					<price><currency>EUR</currency><value>199.95</value></price>
-					<price><currency>GBP</currency><value>199.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>199.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -589,9 +750,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>199.95</value></price>								
-					<price><currency>EUR</currency><value>199.95</value></price>
-					<price><currency>GBP</currency><value>199.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>199.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -605,9 +775,18 @@ Use Cases to do:
 					</duration>
 					<billingPeriod>ANNUAL</billingPeriod>
 					<recurringPrice>
-						<price><currency>USD</currency><value>5999.95</value></price>								
-						<price><currency>EUR</currency><value>3499.95</value></price>
-						<price><currency>GBP</currency><value>3999.95</value></price>
+						<price>
+							<currency>USD</currency>
+							<value>5999.95</value>
+						</price>
+						<price>
+							<currency>EUR</currency>
+							<value>3499.95</value>
+						</price>
+						<price>
+							<currency>GBP</currency>
+							<value>3999.95</value>
+						</price>
 					</recurringPrice>
 				</phase>
 			</initialPhases>
@@ -617,9 +796,18 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>ANNUAL</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>5999.95</value></price>								
-					<price><currency>EUR</currency><value>3499.95</value></price>
-					<price><currency>GBP</currency><value>3999.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>5999.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>3499.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>3999.95</value>
+					</price>
 				</recurringPrice>
 			</finalPhase>
 		</plan>
@@ -632,23 +820,40 @@ Use Cases to do:
 				</duration>
 				<billingPeriod>MONTHLY</billingPeriod>
 				<recurringPrice>
-					<price><currency>USD</currency><value>199.95</value></price>								
-					<price><currency>EUR</currency><value>199.95</value></price>
-					<price><currency>GBP</currency><value>199.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>199.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>199.95</value>
+					</price>
 				</recurringPrice>
 				<fixedPrice>
-					<price><currency>USD</currency><value>599.95</value></price>								
-					<price><currency>EUR</currency><value>599.95</value></price>
-					<price><currency>GBP</currency><value>599.95</value></price>
+					<price>
+						<currency>USD</currency>
+						<value>599.95</value>
+					</price>
+					<price>
+						<currency>EUR</currency>
+						<value>599.95</value>
+					</price>
+					<price>
+						<currency>GBP</currency>
+						<value>599.95</value>
+					</price>
 				</fixedPrice>
 			</finalPhase>
 		</plan>
 	</plans>
-
 	<priceLists>
-		<defaultPriceList name="DEFAULT"> 
+		<defaultPriceList name="DEFAULT">
 			<plans>
-                <plan>blowdart-monthly</plan>
+			    <plan>blowdart-monthly</plan>
 				<plan>pistol-monthly</plan>
 				<plan>shotgun-monthly</plan>
 				<plan>assault-rifle-monthly</plan>
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 e7f8a78..237b927 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
@@ -49,6 +49,7 @@ import com.ning.billing.catalog.api.Plan;
 import com.ning.billing.catalog.api.PlanPhase;
 import com.ning.billing.catalog.api.PlanPhaseSpecifier;
 import com.ning.billing.catalog.api.Product;
+import com.ning.billing.catalog.api.ProductCategory;
 import com.ning.billing.entitlement.api.SubscriptionFactory;
 import com.ning.billing.entitlement.api.SubscriptionTransitionType;
 import com.ning.billing.entitlement.api.user.Subscription;
@@ -88,13 +89,17 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
 
         List<SubscriptionBundle> bundles = entitlementDao.getSubscriptionBundleForAccount(accountId);
         SortedSet<BillingEvent> result = new TreeSet<BillingEvent>();
+        
         for (final SubscriptionBundle bundle: bundles) {
         	List<Subscription> subscriptions = entitlementDao.getSubscriptions(subscriptionFactory, bundle.getId());
 
+        	DateTime bundleStartDate = bundle.getStartDate(); 
         	for (final Subscription subscription: subscriptions) {
-        		for (final SubscriptionEventTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
+        	    // STEPH hack -- see RI-1169
+                bundleStartDate = (subscription.getCategory() == ProductCategory.BASE && bundleStartDate == null) ? subscription.getStartDate() : bundleStartDate;
+        	    for (final SubscriptionEventTransition transition : ((SubscriptionData) subscription).getBillingTransitions()) {
         			try {
-        				BillingEvent event = new DefaultBillingEvent(transition, subscription, calculateBcd(bundle, subscription, transition, accountId), currency);
+        				BillingEvent event = new DefaultBillingEvent(transition, subscription, calculateBcd(bundle, subscription, transition, accountId, bundleStartDate), currency);
         				result.add(event);
         			} catch (CatalogApiException e) {
         				log.error("Failing to identify catalog components while creating BillingEvent from transition: " +
@@ -114,7 +119,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
     }
 
     private int calculateBcd(final SubscriptionBundle bundle, final Subscription subscription,
-                             final SubscriptionEventTransition transition, final UUID accountId) throws CatalogApiException, AccountApiException {
+                             final SubscriptionEventTransition transition, final UUID accountId, DateTime bundleStartDate) throws CatalogApiException, AccountApiException {
     	Catalog catalog = catalogService.getFullCatalog();
     	Plan plan =  (transition.getTransitionType() != SubscriptionTransitionType.CANCEL) ?
     	        transition.getNextPlan() : transition.getPreviousPlan();
@@ -143,7 +148,7 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
     			}
     		break;
     		case BUNDLE :
-    			result = bundle.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
+    			result = bundleStartDate.toDateTime(account.getTimeZone()).getDayOfMonth();
     		break;
     		case SUBSCRIPTION :
     			result = subscription.getStartDate().toDateTime(account.getTimeZone()).getDayOfMonth();
@@ -214,6 +219,4 @@ public class DefaultEntitlementBillingApi implements EntitlementBillingApi {
             }
         }
     }
-
-
 }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java
index 9813448..a3efd7a 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultEntitlementRepairApi.java
@@ -112,6 +112,7 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
             if (bundle == null) {
                 throw new EntitlementRepairException(ErrorCode.ENT_REPAIR_UNKNOWN_BUNDLE, input.getBundleId());
             }
+            
 
             // Subscriptions are ordered with BASE subscription first-- if exists
             final List<Subscription> subscriptions = dao.getSubscriptions(factory, input.getBundleId());
@@ -233,7 +234,7 @@ public class DefaultEntitlementRepairApi implements EntitlementRepairApi {
                 final List<SubscriptionRepair> repairs = createGetSubscriptionRepairList(subscriptions, convertDataRepair(inRepair)); 
                 return createGetBundleRepair(input.getBundleId(), input.getViewId(), repairs);
             } else {
-                dao.repair(input.getBundleId(), inRepair, context);
+                dao.repair(bundle.getAccountId(), input.getBundleId(), inRepair, context);
                 return getBundleRepair(input.getBundleId());
             }
         } catch (CatalogApiException e) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultRepairEntitlementEvent.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultRepairEntitlementEvent.java
index f7be710..47a475c 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultRepairEntitlementEvent.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/repair/DefaultRepairEntitlementEvent.java
@@ -23,12 +23,14 @@ public class DefaultRepairEntitlementEvent implements RepairEntitlementEvent {
 
     private final UUID userToken;
     private final UUID bundleId;
+    private final UUID accountId;
     private final DateTime efectiveDate;
     
     
-    public DefaultRepairEntitlementEvent(final UUID userToken, final UUID bundleId, final DateTime efectiveDate) {
+    public DefaultRepairEntitlementEvent(final UUID userToken, final UUID acountId, final UUID bundleId, final DateTime efectiveDate) {
         this.userToken = userToken;
         this.bundleId = bundleId;
+        this.accountId = acountId;
         this.efectiveDate = efectiveDate;
     }
     
@@ -48,6 +50,11 @@ public class DefaultRepairEntitlementEvent implements RepairEntitlementEvent {
     }
 
     @Override
+    public UUID getAccountId() {
+        return accountId;
+    }
+
+    @Override
     public DateTime getEffectiveDate() {
         return efectiveDate;
     }
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
index 453020c..031d9c7 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/core/Engine.java
@@ -51,6 +51,7 @@ import com.ning.billing.entitlement.api.billing.DefaultEntitlementBillingApi;
 import com.ning.billing.entitlement.api.billing.EntitlementBillingApi;
 import com.ning.billing.entitlement.api.migration.DefaultEntitlementMigrationApi;
 import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi;
+import com.ning.billing.entitlement.api.repair.EntitlementRepairApi;
 import com.ning.billing.entitlement.api.user.DefaultEntitlementUserApi;
 import com.ning.billing.entitlement.api.user.EntitlementUserApi;
 import com.ning.billing.entitlement.api.user.Subscription;
@@ -91,6 +92,7 @@ public class Engine implements EventListener, EntitlementService {
     private final EntitlementUserApi userApi;
     private final EntitlementBillingApi billingApi;
     private final EntitlementMigrationApi migrationApi;
+    private final EntitlementRepairApi repairApi;
     private final AddonUtils addonUtils;
     private final Bus eventBus;
 
@@ -104,6 +106,7 @@ public class Engine implements EventListener, EntitlementService {
     public Engine(Clock clock, EntitlementDao dao, PlanAligner planAligner,
             EntitlementConfig config, DefaultEntitlementUserApi userApi,
             DefaultEntitlementBillingApi billingApi,
+            EntitlementRepairApi repairApi,
             DefaultEntitlementMigrationApi migrationApi, AddonUtils addonUtils, Bus eventBus,
             NotificationQueueService notificationQueueService,
             SubscriptionFactory subscriptionFactory,
@@ -113,6 +116,7 @@ public class Engine implements EventListener, EntitlementService {
         this.dao = dao;
         this.planAligner = planAligner;
         this.userApi = userApi;
+        this.repairApi = repairApi;
         this.billingApi = billingApi;
         this.migrationApi = migrationApi;
         this.addonUtils = addonUtils;
@@ -200,6 +204,10 @@ public class Engine implements EventListener, EntitlementService {
         return migrationApi;
     }
 
+    @Override
+    public EntitlementRepairApi getRepairApi() {
+        return repairApi;
+    }
 
     @Override
     public void processEventReady(final EntitlementEvent event, final int seqId, final CallContext context) {
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
index 5136a72..ac397b6 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementDao.java
@@ -81,7 +81,7 @@ public interface EntitlementDao {
     public void migrate(final UUID accountId, final AccountMigrationData data, final CallContext context);
 
     // Repair
-    public void repair(final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final CallContext context);
+    public void repair(final UUID accountId, final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final CallContext context);
     
     // Custom Fields
     public void saveCustomFields(final SubscriptionData subscription, final CallContext context);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
index 0256883..14e0dfd 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/EntitlementSqlDao.java
@@ -601,7 +601,7 @@ public class EntitlementSqlDao implements EntitlementDao {
         });
     }
 
-    public void repair(final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final CallContext context) {
+    public void repair(final UUID accountId, final UUID bundleId, final List<SubscriptionDataRepair> inRepair, final CallContext context) {
         subscriptionsDao.inTransaction(new Transaction<Void, SubscriptionSqlDao>() {
 
             @Override
@@ -624,7 +624,7 @@ public class EntitlementSqlDao implements EntitlementDao {
                     }
                 }
                 try {
-                    RepairEntitlementEvent busEvent = new DefaultRepairEntitlementEvent(context.getUserToken(), bundleId, clock.getUTCNow());
+                    RepairEntitlementEvent busEvent = new DefaultRepairEntitlementEvent(context.getUserToken(), accountId, bundleId, clock.getUTCNow());
                     eventBus.postFromTransaction(busEvent, transactional);
                 } catch (EventBusException e) {
                     log.warn("Failed to post repair entitlement event for bundle " + bundleId);
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
index 098dc4b..178ea2d 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/engine/dao/RepairEntitlementDao.java
@@ -242,7 +242,7 @@ public class RepairEntitlementDao implements EntitlementDao, RepairEntitlementLi
     }
 
     @Override
-    public void repair(UUID bundleId, List<SubscriptionDataRepair> inRepair,
+    public void repair(UUID accountId, UUID bundleId, List<SubscriptionDataRepair> inRepair,
             CallContext context) {
         throw new EntitlementError("Not implemented");
     }
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
index 57b59b9..e905008 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/engine/dao/MockEntitlementDaoMemory.java
@@ -456,7 +456,7 @@ public class MockEntitlementDaoMemory implements EntitlementDao, MockEntitlement
     }
 
     @Override
-    public void repair(UUID bundleId, List<SubscriptionDataRepair> inRepair,
+    public void repair(UUID accountId, UUID bundleId, List<SubscriptionDataRepair> inRepair,
             CallContext context) {
     }
 }
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 b02c3e8..49d175f 100644
--- a/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
+++ b/invoice/src/main/java/com/ning/billing/invoice/InvoiceListener.java
@@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory;
 
 import com.google.common.eventbus.Subscribe;
 import com.google.inject.Inject;
+import com.ning.billing.entitlement.api.repair.RepairEntitlementEvent;
 import com.ning.billing.entitlement.api.user.SubscriptionEventTransition;
 import com.ning.billing.invoice.api.InvoiceApiException;
 
@@ -43,6 +44,19 @@ public class InvoiceListener {
     }
 
     @Subscribe
+    public void handleRepairEntitlementEvent(final RepairEntitlementEvent repairEvent) {
+        // STEPH
+        /*
+        try {
+            CallContext context = factory.createCallContext("RepairBundle", CallOrigin.INTERNAL, UserType.SYSTEM, repairEvent.getUserToken());
+            dispatcher.processAccount(repairEvent.getAccountId(), repairEvent.getEffectiveDate(), false, context);
+        } catch (InvoiceApiException e) {
+            log.error(e.getMessage());
+        }
+        */
+    }
+    
+    @Subscribe
     public void handleSubscriptionTransition(final SubscriptionEventTransition transition) {
         try {
             if (transition.getRemainingEventsForUserOperation() > 0) {