killbill-aplcache

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)

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

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

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

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

NEWS 3(+3 -0)

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

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

pom.xml 4(+2 -2)

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

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

usage/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 09a34d0..d28390d 100644
--- a/account/pom.xml
+++ b/account/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-account</artifactId>

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

diff --git a/api/pom.xml b/api/pom.xml
index 8da04fe..3ef8182 100644
--- a/api/pom.xml
+++ b/api/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-internal-api</artifactId>
diff --git a/api/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransition.java b/api/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransition.java
index 5ab44a4..035a349 100644
--- a/api/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransition.java
+++ b/api/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransition.java
@@ -58,8 +58,6 @@ public interface SubscriptionBaseTransition {
 
     public PriceList getNextPriceList();
 
-    public DateTime getRequestedTransitionTime();
-
     public DateTime getEffectiveTransitionTime();
 
     public SubscriptionBaseTransitionType getTransitionType();

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

diff --git a/beatrix/pom.xml b/beatrix/pom.xml
index cb151f6..37aa74e 100644
--- a/beatrix/pom.xml
+++ b/beatrix/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-beatrix</artifactId>
diff --git a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
index c1cfa81..6483fff 100644
--- a/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
+++ b/beatrix/src/test/java/org/killbill/billing/beatrix/integration/TestSubscription.java
@@ -24,6 +24,7 @@ import java.util.List;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.killbill.billing.account.api.Account;
+import org.killbill.billing.account.api.AccountApiException;
 import org.killbill.billing.api.TestApiListener.NextEvent;
 import org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck;
 import org.killbill.billing.catalog.api.BillingActionPolicy;
@@ -34,7 +35,11 @@ import org.killbill.billing.catalog.api.ProductCategory;
 import org.killbill.billing.entitlement.api.DefaultEntitlement;
 import org.killbill.billing.entitlement.api.DefaultEntitlementSpecifier;
 import org.killbill.billing.entitlement.api.Entitlement;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
+import org.killbill.billing.entitlement.api.EntitlementApiException;
 import org.killbill.billing.entitlement.api.EntitlementSpecifier;
+import org.killbill.billing.entitlement.api.Subscription;
+import org.killbill.billing.entitlement.api.SubscriptionApiException;
 import org.killbill.billing.entitlement.api.SubscriptionEventType;
 import org.killbill.billing.invoice.api.DryRunType;
 import org.killbill.billing.invoice.api.Invoice;
@@ -237,4 +242,41 @@ public class TestSubscription extends TestIntegrationBase {
         invoiceChecker.checkInvoice(invoices.get(0).getId(), callContext, toBeChecked);
 
     }
+
+
+
+    @Test(groups = "slow")
+    public void testCancelFutureSubscription() throws Exception {
+
+        final LocalDate initialDate = new LocalDate(2015, 9, 1);
+        clock.setDay(initialDate);
+
+        final Account account = createAccountWithNonOsgiPaymentMethod(getAccountData(1));
+
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+        final LocalDate futureDate = new LocalDate(2015, 10, 1);
+
+        // No CREATE event as this is set in the future
+        final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, ImmutableList.<PluginProperty>of(), callContext);
+        assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
+        assertEquals(createdEntitlement.getEffectiveEndDate(), null);
+
+
+        final Entitlement cancelledEntitlement = createdEntitlement.cancelEntitlementWithPolicyOverrideBillingPolicy(EntitlementActionPolicy.IMMEDIATE, BillingActionPolicy.IMMEDIATE, null, callContext);
+        assertEquals(cancelledEntitlement.getEffectiveEndDate().compareTo(futureDate), 0);
+        assertListenerStatus();
+
+        // Move off trial and reach start/cancellation date
+        // NextEvent.INVOICE is required because of #467
+        busHandler.pushExpectedEvents(NextEvent.CREATE, NextEvent.INVOICE, NextEvent.BLOCK, NextEvent.CANCEL);
+        clock.addDays(30);
+
+        assertListenerStatus();
+
+        // Just to make sure we really don't invoice for anything move to next month
+        clock.addMonths(1);
+        assertListenerStatus();
+
+    }
 }

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

diff --git a/catalog/pom.xml b/catalog/pom.xml
index 73321a6..714169b 100644
--- a/catalog/pom.xml
+++ b/catalog/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-catalog</artifactId>

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

diff --git a/currency/pom.xml b/currency/pom.xml
index cbd0abd..dfec699 100644
--- a/currency/pom.xml
+++ b/currency/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-currency</artifactId>
diff --git a/entitlement/pom.xml b/entitlement/pom.xml
index da6cc59..c66ead0 100644
--- a/entitlement/pom.xml
+++ b/entitlement/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-entitlement</artifactId>
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
index 18f9399..065076f 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/BlockingStateOrdering.java
@@ -241,7 +241,6 @@ public class BlockingStateOrdering extends EntitlementOrderingBase {
         return new DefaultSubscriptionEvent(in.getId(),
                                             entitlementId,
                                             in.getEffectiveDate(),
-                                            in.getCreatedDate(),
                                             eventType,
                                             in.isBlockEntitlement(),
                                             in.isBlockBilling(),
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
index 9ff10b3..dffcddb 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultEntitlement.java
@@ -421,7 +421,7 @@ public class DefaultEntitlement extends EntityBase implements Entitlement {
             default:
                 throw new RuntimeException("Unsupported policy " + entitlementPolicy);
         }
-        return cancellationDate;
+        return (cancellationDate.compareTo(getEffectiveStartDate()) < 0) ? getEffectiveStartDate() : cancellationDate;
     }
 
     @Override
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java
index 83292a7..9035efc 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java
@@ -55,7 +55,6 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
     public DefaultSubscriptionEvent(final UUID id,
                                     final UUID entitlementId,
                                     final DateTime effectiveDate,
-                                    final DateTime requestedDate,
                                     final SubscriptionEventType eventType,
                                     final boolean blockingEntitlement,
                                     final boolean blockingBilling,
@@ -76,7 +75,7 @@ public class DefaultSubscriptionEvent implements SubscriptionEvent {
         this.id = id;
         this.entitlementId = entitlementId;
         this.effectiveDate = effectiveDate;
-        this.requestedDate = requestedDate;
+        this.requestedDate = effectiveDate;
         this.eventType = eventType;
         this.isBlockingEntitlement = blockingEntitlement;
         this.isBlockingBilling = blockingBilling;
diff --git a/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java b/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
index 5d793a7..26ae84e 100644
--- a/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
+++ b/entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java
@@ -154,7 +154,6 @@ public class SubscriptionEventOrdering extends EntitlementOrderingBase {
         return new DefaultSubscriptionEvent(in.getId(),
                                             in.getSubscriptionId(),
                                             in.getEffectiveTransitionTime(),
-                                            in.getRequestedTransitionTime(),
                                             eventType,
                                             false,
                                             false,
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
index 7a90cfc..474eb3e 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java
@@ -20,6 +20,8 @@ import java.util.List;
 import java.util.UUID;
 
 import org.joda.time.LocalDate;
+import org.killbill.billing.catalog.api.BillingActionPolicy;
+import org.killbill.billing.entitlement.api.Entitlement.EntitlementActionPolicy;
 import org.killbill.billing.payment.api.PluginProperty;
 import org.testng.Assert;
 import org.testng.annotations.Test;
@@ -249,6 +251,77 @@ public class TestDefaultSubscriptionApi extends EntitlementTestSuiteWithEmbedded
         checkSubscriptionEventAuditLog(transitions, 8, SubscriptionEventType.STOP_BILLING);
     }
 
+
+    @Test(groups = "slow")
+    public void testSubscriptionCreationWithFutureDate() throws AccountApiException, SubscriptionApiException, EntitlementApiException {
+        final String externalKey = "vritti";
+
+        final LocalDate initialDate = new LocalDate(2013, 8, 7);
+        clock.setDay(initialDate);
+
+        final Account account = accountApi.createAccount(getAccountData(7), callContext);
+
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+        //2013-08-07
+        final LocalDate effectiveDate = initialDate.plusMonths(1);
+
+        // Create entitlement and check each field
+        final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, externalKey, null, effectiveDate, ImmutableList.<PluginProperty>of(), callContext);
+
+        final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(entitlement.getId(), callContext);
+
+        final List<SubscriptionEvent> events = subscription.getSubscriptionEvents();
+        assertEquals(events.size(), 3);
+
+        assertEquals(events.get(0).getSubscriptionEventType(), SubscriptionEventType.START_ENTITLEMENT);
+        assertEquals(events.get(0).getEffectiveDate().compareTo(effectiveDate), 0);
+        assertEquals(events.get(0).getRequestedDate().compareTo(effectiveDate), 0);
+
+        assertEquals(events.get(1).getSubscriptionEventType(), SubscriptionEventType.START_BILLING);
+        assertEquals(events.get(1).getEffectiveDate().compareTo(effectiveDate), 0);
+        assertEquals(events.get(1).getRequestedDate().compareTo(effectiveDate), 0);
+
+        assertEquals(events.get(2).getSubscriptionEventType(), SubscriptionEventType.PHASE);
+        assertEquals(events.get(2).getEffectiveDate().compareTo(effectiveDate.plusMonths(1)), 0);
+        assertEquals(events.get(2).getRequestedDate().compareTo(effectiveDate.plusMonths(1)), 0);
+
+        assertListenerStatus();
+
+    }
+
+
+    @Test(groups = "slow")
+    public void testCancelFutureSubscription() throws AccountApiException, EntitlementApiException, SubscriptionApiException {
+
+        final LocalDate initialDate = new LocalDate(2013, 8, 7);
+        clock.setDay(initialDate);
+
+        final Account account = accountApi.createAccount(getAccountData(7), callContext);
+
+        final PlanPhaseSpecifier spec = new PlanPhaseSpecifier("Shotgun", ProductCategory.BASE, BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME, null);
+
+        final LocalDate futureDate = new LocalDate(2013, 9, 1);
+
+        // No CREATE event as this is set in the future
+        final Entitlement createdEntitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), null, futureDate, ImmutableList.<PluginProperty>of(), callContext);
+        assertEquals(createdEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
+        assertEquals(createdEntitlement.getEffectiveEndDate(), null);
+
+        final Entitlement baseEntitlement = entitlementApi.getEntitlementForId(createdEntitlement.getId(), callContext);
+        assertEquals(baseEntitlement.getEffectiveStartDate().compareTo(futureDate), 0);
+        assertEquals(baseEntitlement.getEffectiveEndDate(), null);
+
+        final Entitlement cancelledEntitlement = baseEntitlement.cancelEntitlementWithPolicyOverrideBillingPolicy(EntitlementActionPolicy.IMMEDIATE, BillingActionPolicy.IMMEDIATE, null, callContext);
+        assertEquals(cancelledEntitlement.getEffectiveEndDate().compareTo(futureDate), 0);
+
+        final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(cancelledEntitlement.getId(), callContext);
+        assertEquals(subscription.getEffectiveEndDate().compareTo(futureDate), 0);
+
+        assertListenerStatus();
+    }
+
+
     private void checkSubscriptionEventAuditLog(final List<SubscriptionEvent> transitions, final int idx, final SubscriptionEventType expectedType) {
         assertEquals(transitions.get(idx).getSubscriptionEventType(), expectedType);
         final List<AuditLog> auditLogs = auditUserApi.getAuditLogs(transitions.get(idx).getId(), transitions.get(idx).getSubscriptionEventType().getObjectType(), AuditLevel.FULL, callContext);
diff --git a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
index b9f5c6a..7c67a0e 100644
--- a/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
+++ b/entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java
@@ -68,7 +68,6 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
             return new DefaultSubscriptionEvent(UUID.randomUUID(),
                                                 subscriptionId,
                                                 effectiveDate,
-                                                null,
                                                 type,
                                                 true,
                                                 true,
@@ -1391,7 +1390,6 @@ public class TestDefaultSubscriptionBundleTimeline extends EntitlementTestSuiteN
                                                   bundleId,
                                                   eventType,
                                                   apiEventType,
-                                                  requestedDate,
                                                   effectiveDate,
                                                   null,
                                                   null,

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

diff --git a/invoice/pom.xml b/invoice/pom.xml
index 857e2b7..ddba6d5 100644
--- a/invoice/pom.xml
+++ b/invoice/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-invoice</artifactId>

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

diff --git a/jaxrs/pom.xml b/jaxrs/pom.xml
index 15db23c..0921bda 100644
--- a/jaxrs/pom.xml
+++ b/jaxrs/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-jaxrs</artifactId>

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

diff --git a/junction/pom.xml b/junction/pom.xml
index 279db21..8d3bcb6 100644
--- a/junction/pom.xml
+++ b/junction/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-junction</artifactId>

NEWS 3(+3 -0)

diff --git a/NEWS b/NEWS
index c428f7f..2bb5bfe 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+0.16.0
+    TBD (point to 0.16 release page)
+
 0.15.10
     See https://github.com/killbill/killbill/releases/tag/killbill-0.15.10
 

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

diff --git a/overdue/pom.xml b/overdue/pom.xml
index 5b9cf56..c04472b 100644
--- a/overdue/pom.xml
+++ b/overdue/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-overdue</artifactId>

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

diff --git a/payment/pom.xml b/payment/pom.xml
index cc36953..97119a8 100644
--- a/payment/pom.xml
+++ b/payment/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-payment</artifactId>
diff --git a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java
index 595b3a9..ad1b38e 100644
--- a/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java
+++ b/payment/src/main/java/org/killbill/billing/payment/api/DefaultPaymentGatewayApi.java
@@ -1,6 +1,6 @@
 /*
- * Copyright 2014-2015 Groupon, Inc
- * Copyright 2014-2015 The Billing Project, LLC
+ * Copyright 2014-2016 Groupon, Inc
+ * Copyright 2014-2016 The Billing Project, LLC
  *
  * The Billing Project 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
@@ -38,6 +38,7 @@ import org.killbill.billing.payment.dispatcher.PluginDispatcher;
 import org.killbill.billing.payment.dispatcher.PluginDispatcher.PluginDispatcherReturnType;
 import org.killbill.billing.payment.plugin.api.GatewayNotification;
 import org.killbill.billing.payment.plugin.api.HostedPaymentPageFormDescriptor;
+import org.killbill.billing.util.PluginProperties;
 import org.killbill.billing.util.callcontext.CallContext;
 import org.killbill.billing.util.callcontext.InternalCallContextFactory;
 import org.killbill.billing.util.config.PaymentConfig;
@@ -78,7 +79,8 @@ public class DefaultPaymentGatewayApi extends DefaultApiBase implements PaymentG
 
     @Override
     public HostedPaymentPageFormDescriptor buildFormDescriptorWithPaymentControl(final Account account, final UUID paymentMethodId, final Iterable<PluginProperty> customFields, final Iterable<PluginProperty> properties, final PaymentOptions paymentOptions, final CallContext callContext) throws PaymentApiException {
-        return executeWithPaymentControl(account, paymentMethodId, properties, paymentOptions, callContext, paymentPluginFormDispatcher, new WithPaymentControlCallback<HostedPaymentPageFormDescriptor>() {
+        final Iterable<PluginProperty> mergedProperties = PluginProperties.merge(customFields, properties);
+        return executeWithPaymentControl(account, paymentMethodId, mergedProperties, paymentOptions, callContext, paymentPluginFormDispatcher, new WithPaymentControlCallback<HostedPaymentPageFormDescriptor>() {
             @Override
             public HostedPaymentPageFormDescriptor doPaymentGatewayApiOperation(final UUID adjustedPaymentMethodId, final Iterable<PluginProperty> adjustedPluginProperties) throws PaymentApiException {
                 return buildFormDescriptor(false, account, adjustedPaymentMethodId, customFields, adjustedPluginProperties, callContext);
@@ -97,9 +99,9 @@ public class DefaultPaymentGatewayApi extends DefaultApiBase implements PaymentG
             @Override
             public GatewayNotification doPaymentGatewayApiOperation(final UUID adjustedPaymentMethodId, final Iterable<PluginProperty> adjustedPluginProperties) throws PaymentApiException {
                 if (adjustedPaymentMethodId == null) {
-                    return paymentGatewayProcessor.processNotification(false, notification, pluginName, properties, callContext);
+                    return paymentGatewayProcessor.processNotification(false, notification, pluginName, adjustedPluginProperties, callContext);
                 } else {
-                    return paymentGatewayProcessor.processNotification(false, notification, adjustedPaymentMethodId, properties, callContext);
+                    return paymentGatewayProcessor.processNotification(false, notification, adjustedPaymentMethodId, adjustedPluginProperties, callContext);
                 }
             }
         });

pom.xml 4(+2 -2)

diff --git a/pom.xml b/pom.xml
index 1256982..a85090e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,10 +21,10 @@
     <parent>
         <artifactId>killbill-oss-parent</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.77-SNAPSHOT</version>
+        <version>0.80-SNAPSHOT</version>
     </parent>
     <artifactId>killbill</artifactId>
-    <version>0.15.11-SNAPSHOT</version>
+    <version>0.16.1-SNAPSHOT</version>
     <packaging>pom</packaging>
     <name>killbill</name>
     <description>Library for managing recurring subscriptions and the associated billing</description>
diff --git a/profiles/killbill/pom.xml b/profiles/killbill/pom.xml
index 482be27..62c6d0c 100644
--- a/profiles/killbill/pom.xml
+++ b/profiles/killbill/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killbill</artifactId>
diff --git a/profiles/killpay/pom.xml b/profiles/killpay/pom.xml
index f6627e8..98b792d 100644
--- a/profiles/killpay/pom.xml
+++ b/profiles/killpay/pom.xml
@@ -20,7 +20,7 @@
     <parent>
         <artifactId>killbill-profiles</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles-killpay</artifactId>

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

diff --git a/profiles/pom.xml b/profiles/pom.xml
index 48eff8c..5bbaef8 100644
--- a/profiles/pom.xml
+++ b/profiles/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-profiles</artifactId>
diff --git a/subscription/pom.xml b/subscription/pom.xml
index ac5080d..0b9f959 100644
--- a/subscription/pom.xml
+++ b/subscription/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-subscription</artifactId>
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
index 8d76cbd..fe4e369 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/alignment/PlanAligner.java
@@ -70,7 +70,6 @@ public class PlanAligner extends BaseAligner {
      * @param plan            the current Plan
      * @param initialPhase    the initialPhase on which we should create that subscription. can be null
      * @param priceList       the priceList
-     * @param requestedDate   the requested date (only used to loadDefaultCatalog the catalog)
      * @param effectiveDate   the effective creation date (driven by the catalog policy, i.e. when the creation occurs)
      * @return the current and next phases
      * @throws CatalogApiException         for catalog errors
@@ -81,7 +80,6 @@ public class PlanAligner extends BaseAligner {
                                                             final Plan plan,
                                                             @Nullable final PhaseType initialPhase,
                                                             final String priceList,
-                                                            final DateTime requestedDate,
                                                             final DateTime effectiveDate,
                                                             final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
         final List<TimedPhase> timedPhases = getTimedPhaseOnCreate(alignStartDate,
@@ -89,7 +87,7 @@ public class PlanAligner extends BaseAligner {
                                                                    plan,
                                                                    initialPhase,
                                                                    priceList,
-                                                                   requestedDate,
+                                                                   effectiveDate,
                                                                    context);
         final TimedPhase[] result = new TimedPhase[2];
         result[0] = getTimedPhase(timedPhases, effectiveDate, WhichPhase.CURRENT);
@@ -104,7 +102,6 @@ public class PlanAligner extends BaseAligner {
      *                      are looked at)
      * @param plan          the current Plan
      * @param priceList     the priceList on which we should change that subscription.
-     * @param requestedDate the requested date
      * @param effectiveDate the effective change date (driven by the catalog policy, i.e. when the change occurs)
      * @return the current phase
      * @throws CatalogApiException         for catalog errors
@@ -113,10 +110,9 @@ public class PlanAligner extends BaseAligner {
     public TimedPhase getCurrentTimedPhaseOnChange(final DefaultSubscriptionBase subscription,
                                                    final Plan plan,
                                                    final String priceList,
-                                                   final DateTime requestedDate,
                                                    final DateTime effectiveDate,
                                                    final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
-        return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.CURRENT, context);
+        return getTimedPhaseOnChange(subscription, plan, priceList, effectiveDate, WhichPhase.CURRENT, context);
     }
 
     /**
@@ -126,7 +122,6 @@ public class PlanAligner extends BaseAligner {
      *                      are looked at)
      * @param plan          the current Plan
      * @param priceList     the priceList on which we should change that subscription.
-     * @param requestedDate the requested date
      * @param effectiveDate the effective change date (driven by the catalog policy, i.e. when the change occurs)
      * @return the next phase
      * @throws CatalogApiException         for catalog errors
@@ -135,21 +130,18 @@ public class PlanAligner extends BaseAligner {
     public TimedPhase getNextTimedPhaseOnChange(final DefaultSubscriptionBase subscription,
                                                 final Plan plan,
                                                 final String priceList,
-                                                final DateTime requestedDate,
                                                 final DateTime effectiveDate,
                                                 final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
-        return getTimedPhaseOnChange(subscription, plan, priceList, requestedDate, effectiveDate, WhichPhase.NEXT, context);
+        return getTimedPhaseOnChange(subscription, plan, priceList, effectiveDate, WhichPhase.NEXT, context);
     }
 
     /**
      * Returns next Phase for that SubscriptionBase at a point in time
      *
      * @param subscription  the subscription for which we need to compute the next Phase event
-     * @param requestedDate the requested date
-     * @param effectiveDate the date at which we look to compute that event. effective needs to be after last Plan change or initial Plan
      * @return the next phase
      */
-    public TimedPhase getNextTimedPhase(final DefaultSubscriptionBase subscription, final DateTime requestedDate, final DateTime effectiveDate, final InternalTenantContext context) {
+    public TimedPhase getNextTimedPhase(final DefaultSubscriptionBase subscription, final DateTime effectiveDate, final InternalTenantContext context) {
         try {
             final SubscriptionBaseTransitionData lastPlanTransition = subscription.getLastTransitionForCurrentPlan();
             if (effectiveDate.isBefore(lastPlanTransition.getEffectiveTransitionTime())) {
@@ -168,10 +160,9 @@ public class PlanAligner extends BaseAligner {
                                                                                lastPlanTransition.getNextPlan(),
                                                                                lastPlanTransition.getNextPhase().getPhaseType(),
                                                                                lastPlanTransition.getNextPriceList().getName(),
-                                                                               requestedDate,
+                                                                               effectiveDate,
                                                                                context);
                     return getTimedPhase(timedPhases, effectiveDate, WhichPhase.NEXT);
-                // If we went through Plan changes, borrow the logic for changePlanWithRequestedDate alignment
                 case CHANGE:
                     return getTimedPhaseOnChange(subscription.getAlignStartDate(),
                                                  subscription.getBundleStartDate(),
@@ -180,7 +171,6 @@ public class PlanAligner extends BaseAligner {
                                                  lastPlanTransition.getPreviousPriceList().getName(),
                                                  lastPlanTransition.getNextPlan(),
                                                  lastPlanTransition.getNextPriceList().getName(),
-                                                 requestedDate,
                                                  effectiveDate,
                                                  lastPlanTransition.getEffectiveTransitionTime(),
                                                  WhichPhase.NEXT,
@@ -199,7 +189,7 @@ public class PlanAligner extends BaseAligner {
                                                    final Plan plan,
                                                    @Nullable final PhaseType initialPhase,
                                                    final String priceList,
-                                                   final DateTime requestedDate,
+                                                   final DateTime effectiveDate,
                                                    final InternalTenantContext context)
             throws CatalogApiException, SubscriptionBaseApiException {
         final Catalog catalog = catalogService.getFullCatalog(context);
@@ -210,7 +200,7 @@ public class PlanAligner extends BaseAligner {
                                                               priceList);
 
         final DateTime planStartDate;
-        final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, requestedDate);
+        final PlanAlignmentCreate alignment = catalog.planCreateAlignment(planSpecifier, effectiveDate);
         switch (alignment) {
             case START_OF_SUBSCRIPTION:
                 planStartDate = subscriptionStartDate;
@@ -228,7 +218,6 @@ public class PlanAligner extends BaseAligner {
     private TimedPhase getTimedPhaseOnChange(final DefaultSubscriptionBase subscription,
                                              final Plan nextPlan,
                                              final String nextPriceList,
-                                             final DateTime requestedDate,
                                              final DateTime effectiveDate,
                                              final WhichPhase which,
                                              final InternalTenantContext context) throws CatalogApiException, SubscriptionBaseApiException {
@@ -239,7 +228,6 @@ public class PlanAligner extends BaseAligner {
                                      subscription.getCurrentPriceList().getName(),
                                      nextPlan,
                                      nextPriceList,
-                                     requestedDate,
                                      effectiveDate,
                                      // This method is only called while doing the change, hence we want to pass the change effective date
                                      effectiveDate,
@@ -254,7 +242,6 @@ public class PlanAligner extends BaseAligner {
                                              final String currentPriceList,
                                              final Plan nextPlan,
                                              final String priceList,
-                                             final DateTime requestedDate,
                                              final DateTime effectiveDate,
                                              final DateTime lastOrCurrentChangeEffectiveDate,
                                              final WhichPhase which,
@@ -273,7 +260,7 @@ public class PlanAligner extends BaseAligner {
                                                                 priceList);
 
         final DateTime planStartDate;
-        final PlanAlignmentChange alignment = catalog.planChangeAlignment(fromPlanPhaseSpecifier, toPlanSpecifier, requestedDate);
+        final PlanAlignmentChange alignment = catalog.planChangeAlignment(fromPlanPhaseSpecifier, toPlanSpecifier, effectiveDate);
         switch (alignment) {
             case START_OF_SUBSCRIPTION:
                 planStartDate = subscriptionStartDate;
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
index 01746a9..436e64e 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java
@@ -206,13 +206,12 @@ public class DefaultSubscriptionBaseMigrationApi extends SubscriptionApiBase imp
                     .setEventPriceList(cur.getPriceList())
                     .setActiveVersion(defaultSubscriptionBase.getActiveVersion())
                     .setEffectiveDate(cur.getEventTime())
-                    .setRequestedDate(now)
                     .setFromDisk(true);
 
             if (cur.getEventType() == EventType.PHASE) {
                 nextEventDate = nextEventDate != null && nextEventDate.compareTo(cur.getEventTime()) < 0 ? nextEventDate : cur.getEventTime();
                 final PhaseEvent nextPhaseEvent = PhaseEventData.createNextPhaseEvent(defaultSubscriptionBase.getId(), defaultSubscriptionBase.getActiveVersion(),
-                                                                                      cur.getPhase().getName(), now, cur.getEventTime());
+                                                                                      cur.getPhase().getName(), cur.getEventTime());
                 events.add(nextPhaseEvent);
 
             } else if (cur.getEventType() == EventType.API_USER) {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
index 26c6a3d..a4fefd0 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java
@@ -43,7 +43,7 @@ import org.killbill.billing.util.callcontext.TenantContext;
 public interface SubscriptionBaseApiService {
 
     public DefaultSubscriptionBase createPlan(SubscriptionBuilder builder, Plan plan, PhaseType initialPhase,
-                                              String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
+                                              String realPriceList, DateTime effectiveDate, DateTime processedDate,
                                               CallContext context)
             throws SubscriptionBaseApiException;
 
@@ -91,16 +91,16 @@ public interface SubscriptionBaseApiService {
     //
     public List<SubscriptionBaseEvent> getEventsOnCreation(UUID bundleId, UUID subscriptionId, DateTime alignStartDate, DateTime bundleStartDate, long activeVersion,
                                                            Plan plan, PhaseType initialPhase,
-                                                           String realPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
+                                                           String realPriceList, DateTime effectiveDate, DateTime processedDate,
                                                            boolean reCreate, InternalTenantContext context)
             throws CatalogApiException, SubscriptionBaseApiException;
 
     public List<SubscriptionBaseEvent> getEventsOnChangePlan(DefaultSubscriptionBase subscription, Plan newPlan,
-                                                             String newPriceList, DateTime requestedDate, DateTime effectiveDate, DateTime processedDate,
+                                                             String newPriceList, DateTime effectiveDate, DateTime processedDate,
                                                              boolean addCancellationAddOnForEventsIfRequired, InternalTenantContext context)
             throws CatalogApiException, SubscriptionBaseApiException;
 
     public List<SubscriptionBaseEvent> getEventsOnCancelPlan(final DefaultSubscriptionBase subscription,
-                                                             final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
-                                                             final boolean addCancellationAddOnForEventsIfRequired, final InternalTenantContext context) throws CatalogApiException;
+                                                             final DateTime effectiveDate, final DateTime processedDate,
+                                                             final boolean addCancellationAddOnForEventsIfRequired, final InternalTenantContext internalTenantContext) throws CatalogApiException;
 }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
index 5155064..db39491 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java
@@ -125,19 +125,18 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
         try {
             final String realPriceList = (spec.getPriceListName() == null) ? PriceListSet.DEFAULT_PRICELIST_NAME : spec.getPriceListName();
             final DateTime now = clock.getUTCNow();
-            final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+            final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
             /*
             if (requestedDate.isAfter(now)) {
                 throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE, now.toString(), requestedDate.toString());
             }
             */
-            final DateTime effectiveDate = requestedDate;
 
             final CallContext callContext = internalCallContextFactory.createCallContext(context);
             final Catalog catalog = catalogService.getFullCatalog(context);
             final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(overrides, callContext);
 
-            final Plan plan = catalog.createOrFindPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, overridesWithContext, requestedDate);
+            final Plan plan = catalog.createOrFindPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, overridesWithContext, effectiveDate);
             final PlanPhase phase = plan.getAllPhases()[0];
             if (phase == null) {
                 throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
@@ -150,14 +149,14 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
             }
 
             final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
-            final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, requestedDate, effectiveDate, context);
+            final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, effectiveDate, context);
             return apiService.createPlan(new SubscriptionBuilder()
                                                  .setId(UUIDs.randomUUID())
                                                  .setBundleId(bundleId)
                                                  .setCategory(plan.getProduct().getCategory())
                                                  .setBundleStartDate(bundleStartDate)
                                                  .setAlignStartDate(effectiveDate),
-                                         plan, spec.getPhaseType(), realPriceList, requestedDate, effectiveDate, now, callContext);
+                                         plan, spec.getPhaseType(), realPriceList, effectiveDate, now, callContext);
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
         }
@@ -167,7 +166,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     public SubscriptionBase createBaseSubscriptionWithAddOns(final UUID bundleId, final Iterable<EntitlementSpecifier> entitlements, final DateTime requestedDateWithMs, final InternalCallContext context) throws SubscriptionBaseApiException {
 
         final DateTime now = clock.getUTCNow();
-        final DateTime requestedDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
+        final DateTime effectiveDate = (requestedDateWithMs != null) ? DefaultClock.truncateMs(requestedDateWithMs) : now;
 
         try {
             final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
@@ -181,7 +180,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                 final PlanPhasePriceOverridesWithCallContext overridesWithContext = new DefaultPlanPhasePriceOverridesWithCallContext(entitlement.getOverrides(), callContext);
 
-                final Plan plan = catalog.createOrFindPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, overridesWithContext, requestedDate);
+                final Plan plan = catalog.createOrFindPlan(spec.getProductName(), spec.getBillingPeriod(), realPriceList, overridesWithContext, effectiveDate);
                 final PlanPhase phase = plan.getAllPhases()[0];
                 if (phase == null) {
                     throw new SubscriptionBaseError(String.format("No initial PlanPhase for Product %s, term %s and set %s does not exist in the catalog",
@@ -195,8 +194,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                 SubscriptionSpecifier subscription = new SubscriptionSpecifier();
                 subscription.setRealPriceList(realPriceList);
-                subscription.setRequestedDate(requestedDate);
-                subscription.setEffectiveDate(requestedDate);
+                subscription.setEffectiveDate(effectiveDate);
                 subscription.setProcessedDate(now);
                 subscription.setPlan(plan);
                 subscription.setInitialPhase(spec.getPhaseType());
@@ -204,8 +202,8 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                                 .setId(UUIDs.randomUUID())
                                                 .setBundleId(bundleId)
                                                 .setCategory(plan.getProduct().getCategory())
-                                                .setBundleStartDate(requestedDate)
-                                                .setAlignStartDate(requestedDate));
+                                                .setBundleStartDate(effectiveDate)
+                                                .setAlignStartDate(effectiveDate));
 
                 subscriptions.add(subscription);
             }
@@ -485,10 +483,10 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
 
                         final DefaultSubscriptionBase baseSubscription = (DefaultSubscriptionBase) dao.getBaseSubscription(bundleId, context);
                         final DateTime startEffectiveDate = dryRunArguments.getEffectiveDate() != null ? dryRunArguments.getEffectiveDate() : utcNow;
-                        final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, startEffectiveDate, context);
+                        final DateTime bundleStartDate = getBundleStartDateWithSanity(bundleId, baseSubscription, plan, startEffectiveDate, context);
                         final UUID subscriptionId = UUIDs.randomUUID();
                         dryRunEvents = apiService.getEventsOnCreation(bundleId, subscriptionId, startEffectiveDate, bundleStartDate, 1L, plan, inputSpec.getPhaseType(), realPriceList,
-                                                                      utcNow, startEffectiveDate, utcNow, false, context);
+                                                                      startEffectiveDate, utcNow, false, context);
                         final SubscriptionBuilder builder = new SubscriptionBuilder()
                                 .setId(subscriptionId)
                                 .setBundleId(bundleId)
@@ -512,9 +510,9 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                                                                                          dryRunArguments.getPlanPhaseSpecifier().getPriceListName(), utcNow, tenantContext);
                                 policy = planChangeResult.getPolicy();
                             }
-                            changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy);
+                            changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(subscriptionForChange.getStartDate(), policy);
                         }
-                        dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, realPriceList, utcNow, changeEffectiveDate, utcNow, true, context);
+                        dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, realPriceList, changeEffectiveDate, utcNow, true, context);
                         break;
 
                     case STOP_BILLING:
@@ -532,9 +530,9 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                                                                                        subscriptionForCancellation.getCurrentPhase().getPhaseType());
                                 policy = catalogService.getFullCatalog(context).planCancelPolicy(spec, utcNow);
                             }
-                            cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy);
+                            cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(subscriptionForCancellation.getStartDate(), policy);
                         }
-                        dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, utcNow, cancelEffectiveDate, utcNow, true, context);
+                        dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, cancelEffectiveDate, utcNow, true, context);
                         break;
 
                     default:
@@ -587,14 +585,14 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
     }
 
     private DateTime getBundleStartDateWithSanity(final UUID bundleId, @Nullable final DefaultSubscriptionBase baseSubscription, final Plan plan,
-                                                  final DateTime requestedDate, final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
+                                                  final DateTime effectiveDate, final InternalTenantContext context) throws SubscriptionBaseApiException, CatalogApiException {
         switch (plan.getProduct().getCategory()) {
             case BASE:
                 if (baseSubscription != null &&
                     baseSubscription.getState() == EntitlementState.ACTIVE) {
                     throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundleId);
                 }
-                return requestedDate;
+                return effectiveDate;
 
             case ADD_ON:
                 if (baseSubscription == null) {
@@ -603,7 +601,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                 if (effectiveDate.isBefore(baseSubscription.getStartDate())) {
                     throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE, effectiveDate.toString(), baseSubscription.getStartDate().toString());
                 }
-                addonUtils.checkAddonCreationRights(baseSubscription, plan, requestedDate, context);
+                addonUtils.checkAddonCreationRights(baseSubscription, plan, effectiveDate, context);
                 return baseSubscription.getStartDate();
 
             case STANDALONE:
@@ -611,7 +609,7 @@ public class DefaultSubscriptionInternalApi extends SubscriptionApiBase implemen
                     throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_BP_EXISTS, bundleId);
                 }
                 // Not really but we don't care, there is no alignment for STANDALONE subscriptions
-                return requestedDate;
+                return effectiveDate;
 
             default:
                 throw new SubscriptionBaseError(String.format("Can't create subscription of type %s",
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
index 73de18a..fc33b62 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java
@@ -110,7 +110,7 @@ public class DefaultSubscriptionBaseTimeline implements SubscriptionBaseTimeline
                     apiType = userEV.getApiEventType();
                     planName = userEV.getEventPlan();
                     planPhaseName = userEV.getEventPlanPhase();
-                    final Plan plan = (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getRequestedDate(), startDate) : null;
+                    final Plan plan = (userEV.getEventPlan() != null) ? catalog.findPlan(userEV.getEventPlan(), cur.getEffectiveDate(), startDate) : null;
                     phaseType = (userEV.getEventPlanPhase() != null) ? catalog.findPhase(userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate).getPhaseType() : prevPhaseType;
                     productName = (plan != null) ? plan.getProduct().getName() : prevProductName;
                     billingPeriod = (userEV.getEventPlanPhase() != null) ? getBillingPeriod(catalog, userEV.getEventPlanPhase(), cur.getEffectiveDate(), startDate) : prevBillingPeriod;
@@ -131,7 +131,7 @@ public class DefaultSubscriptionBaseTimeline implements SubscriptionBaseTimeline
 
                 @Override
                 public DateTime getRequestedDate() {
-                    return cur.getRequestedDate();
+                    return cur.getEffectiveDate();
                 }
 
                 @Override
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
index 4abe2f7..49c3ca6 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java
@@ -103,7 +103,6 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
                 .setEventPriceList(spec.getPriceListName())
                 .setActiveVersion(subscription.getActiveVersion())
                 .setEffectiveDate(effectiveDate)
-                .setRequestedDate(effectiveDate)
                 .setFromDisk(true);
 
         switch (existingEvent.getSubscriptionTransitionType()) {
@@ -121,7 +120,7 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
 
             case PHASE:
                 newEvent = firstEvent ? new ApiEventTransfer(apiBuilder) :
-                           PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(), currentPhase.getName(), clock.getUTCNow(), effectiveDate);
+                           PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(), currentPhase.getName(), effectiveDate);
                 break;
 
             // Ignore these events except if it's the first event for the new subscription
@@ -241,7 +240,6 @@ public class DefaultSubscriptionBaseTransferApi extends SubscriptionApiBase impl
                                                                                          .setSubscriptionId(cur.getId())
                                                                                          .setActiveVersion(cur.getActiveVersion())
                                                                                          .setEffectiveDate(effectiveCancelDate)
-                                                                                         .setRequestedDate(effectiveTransferDate)
                                                                                          .setFromDisk(true));
 
                     TransferCancelData cancelData = new TransferCancelData(oldSubscription, cancelEvent);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultEffectiveSubscriptionEvent.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultEffectiveSubscriptionEvent.java
index 9d16160..aca165c 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultEffectiveSubscriptionEvent.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultEffectiveSubscriptionEvent.java
@@ -37,7 +37,6 @@ public class DefaultEffectiveSubscriptionEvent extends DefaultSubscriptionEvent 
     public DefaultEffectiveSubscriptionEvent(@JsonProperty("eventId") final UUID eventId,
                                              @JsonProperty("subscriptionId") final UUID subscriptionId,
                                              @JsonProperty("bundleId") final UUID bundleId,
-                                             @JsonProperty("requestedTransitionTime") final DateTime requestedTransitionTime,
                                              @JsonProperty("effectiveTransitionTime") final DateTime effectiveTransitionTime,
                                              @JsonProperty("previousState") final EntitlementState previousState,
                                              @JsonProperty("previousPlan") final String previousPlan,
@@ -54,7 +53,7 @@ public class DefaultEffectiveSubscriptionEvent extends DefaultSubscriptionEvent 
                                              @JsonProperty("searchKey1") final Long searchKey1,
                                              @JsonProperty("searchKey2") final Long searchKey2,
                                              @JsonProperty("userToken") final UUID userToken) {
-        super(eventId, subscriptionId, bundleId, requestedTransitionTime, effectiveTransitionTime, previousState, previousPlan,
+        super(eventId, subscriptionId, bundleId, effectiveTransitionTime, effectiveTransitionTime, previousState, previousPlan,
               previousPhase, previousPriceList, nextState, nextPlan, nextPhase, nextPriceList, totalOrdering,
               transitionType, remainingEventsForUserOperation, startDate, searchKey1, searchKey2, userToken);
     }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java
index 8394193..2c78684 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java
@@ -62,7 +62,7 @@ public class DefaultRequestedSubscriptionEvent extends DefaultSubscriptionEvent 
                                              final Long searchKey1,
                                              final Long searchKey2,
                                              final UUID userToken) {
-        this(nextEvent.getId(), nextEvent.getSubscriptionId(), subscription.getBundleId(), nextEvent.getRequestedDate(), nextEvent.getEffectiveDate(),
+        this(nextEvent.getId(), nextEvent.getSubscriptionId(), subscription.getBundleId(), nextEvent.getEffectiveDate(), nextEvent.getEffectiveDate(),
              null, null, null, null, null, null, null, null, nextEvent.getTotalOrdering(), transitionType, 0, null, searchKey1, searchKey2, userToken);
     }
 }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
index 184c3db..70e5911 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java
@@ -492,10 +492,13 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
         return getFutureEndDate() != null;
     }
 
-    public DateTime getPlanChangeEffectiveDate(final BillingActionPolicy policy) {
+    public DateTime getPlanChangeEffectiveDate(final DateTime subscriptionStartDate, final BillingActionPolicy policy) {
+
+        final DateTime candidateResult;
         switch (policy) {
             case IMMEDIATE:
-                return clock.getUTCNow();
+                candidateResult =  clock.getUTCNow();
+                break;
             case END_OF_TERM:
                 //
                 // If we have a chargedThroughDate that is 'up to date' we use it, if not default to now
@@ -503,11 +506,13 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
                 // 1. account is not being invoiced, for e.g AUTO_INVOICING_OFF nis set
                 // 2. In the case if FIXED item CTD is set using startDate of the service period
                 //
-                return (chargedThroughDate != null && chargedThroughDate.isAfter(clock.getUTCNow())) ? chargedThroughDate : clock.getUTCNow();
+                candidateResult =  (chargedThroughDate != null && chargedThroughDate.isAfter(clock.getUTCNow())) ? chargedThroughDate : clock.getUTCNow();
+                break;
             default:
                 throw new SubscriptionBaseError(String.format(
                         "Unexpected policy type %s", policy.toString()));
         }
+        return (candidateResult.compareTo(subscriptionStartDate) < 0) ? subscriptionStartDate : candidateResult;
     }
 
     public DateTime getCurrentPhaseStart() {
@@ -629,13 +634,16 @@ public class DefaultSubscriptionBase extends EntityBase implements SubscriptionB
             PlanPhase nextPhase = null;
             PriceList nextPriceList = null;
 
-            nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getRequestedDate(), getAlignStartDate()) : null;
-            nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, cur.getRequestedDate(), getAlignStartDate()) : null;
-            nextPriceList = (nextPriceListName != null) ? catalog.findPriceList(nextPriceListName, cur.getRequestedDate()) : null;
+            nextPlan = (nextPlanName != null) ? catalog.findPlan(nextPlanName, cur.getEffectiveDate(), getAlignStartDate()) : null;
+            nextPhase = (nextPhaseName != null) ? catalog.findPhase(nextPhaseName, cur.getEffectiveDate(), getAlignStartDate()) : null;
+
+            // See issue https://github.com/killbill/killbill/issues/464
+            final DateTime catalogEffectiveDateForPriceList = transitions.isEmpty() ? cur.getEffectiveDate() : transitions.get(0).getEffectiveTransitionTime();
+            nextPriceList = (nextPriceListName != null) ? catalog.findPriceList(nextPriceListName, catalogEffectiveDateForPriceList) : null;
 
             final SubscriptionBaseTransitionData transition = new SubscriptionBaseTransitionData(
                     cur.getId(), id, bundleId, cur.getType(), apiEventType,
-                    cur.getRequestedDate(), cur.getEffectiveDate(),
+                    cur.getEffectiveDate(),
                     prevEventId, prevCreatedDate,
                     previousState, previousPlan, previousPhase,
                     previousPriceList,
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
index 6e4b949..0afc9c7 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java
@@ -100,11 +100,11 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
     @Override
     public DefaultSubscriptionBase createPlan(final SubscriptionBuilder builder, final Plan plan, final PhaseType initialPhase,
-                                              final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
+                                              final String realPriceList, final DateTime effectiveDate, final DateTime processedDate,
                                               final CallContext context) throws SubscriptionBaseApiException {
         final DefaultSubscriptionBase subscription = new DefaultSubscriptionBase(builder, this, clock);
 
-        createFromSubscription(subscription, plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, false, context);
+        createFromSubscription(subscription, plan, initialPhase, realPriceList, effectiveDate, processedDate, false, context);
         return subscription;
     }
 
@@ -120,7 +120,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                 final InternalCallContext internalCallContext = createCallContextFromBundleId(subscriptionBase.getBundleId(), context);
                 final List<SubscriptionBaseEvent> events = getEventsOnCreation(subscriptionBase.getBundleId(), subscriptionBase.getId(), subscriptionBase.getAlignStartDate(),
                                                                                subscriptionBase.getBundleStartDate(), subscriptionBase.getActiveVersion(), subscription.getPlan(),
-                                                                               subscription.getInitialPhase(), subscription.getRealPriceList(), subscription.getRequestedDate(),
+                                                                               subscription.getInitialPhase(), subscription.getRealPriceList(),
                                                                                subscription.getEffectiveDate(), subscription.getProcessedDate(), false, internalCallContext);
 
                 eventsMap.put(subscriptionBase.getId(), events);
@@ -178,9 +178,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                                               spec.getProductName(), spec.getBillingPeriod().toString(), realPriceList));
             }
 
-            final DateTime processedDate = now;
-
-            createFromSubscription(subscription, plan, spec.getPhaseType(), realPriceList, now, effectiveDate, processedDate, true, context);
+            createFromSubscription(subscription, plan, spec.getPhaseType(), realPriceList, effectiveDate, now, true, context);
             return true;
         } catch (final CatalogApiException e) {
             throw new SubscriptionBaseApiException(e);
@@ -188,13 +186,13 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
     private void createFromSubscription(final DefaultSubscriptionBase subscription, final Plan plan, final PhaseType initialPhase,
-                                        final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
+                                        final String realPriceList, final DateTime effectiveDate, final DateTime processedDate,
                                         final boolean reCreate, final CallContext context) throws SubscriptionBaseApiException {
         final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
 
         try {
             final List<SubscriptionBaseEvent> events = getEventsOnCreation(subscription.getBundleId(), subscription.getId(), subscription.getAlignStartDate(), subscription.getBundleStartDate(), subscription.getActiveVersion(),
-                                                                           plan, initialPhase, realPriceList, requestedDate, effectiveDate, processedDate, reCreate, internalCallContext);
+                                                                           plan, initialPhase, realPriceList, effectiveDate, processedDate, reCreate, internalCallContext);
             if (reCreate) {
                 dao.recreateSubscription(subscription, events, internalCallContext);
             } else {
@@ -209,7 +207,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     @Override
     public boolean cancel(final DefaultSubscriptionBase subscription, final CallContext context) throws SubscriptionBaseApiException {
         final EntitlementState currentState = subscription.getState();
-        if (currentState != EntitlementState.ACTIVE) {
+        if (currentState != null && currentState != EntitlementState.ACTIVE) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
         }
         final DateTime now = clock.getUTCNow();
@@ -224,7 +222,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         try {
             final InternalTenantContext internalCallContext = createTenantContextFromBundleId(subscription.getBundleId(), context);
             final BillingActionPolicy policy = catalogService.getFullCatalog(internalCallContext).planCancelPolicy(planPhase, now);
-            final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy);
+            final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), policy);
 
             return doCancelPlan(subscription, now, effectiveDate, context);
         } catch (final CatalogApiException e) {
@@ -235,7 +233,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     @Override
     public boolean cancelWithRequestedDate(final DefaultSubscriptionBase subscription, final DateTime requestedDateWithMs, final CallContext context) throws SubscriptionBaseApiException {
         final EntitlementState currentState = subscription.getState();
-        if (currentState != EntitlementState.ACTIVE) {
+        if (currentState != null && currentState != EntitlementState.ACTIVE) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
         }
         final DateTime now = clock.getUTCNow();
@@ -246,11 +244,11 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     @Override
     public boolean cancelWithPolicy(final DefaultSubscriptionBase subscription, final BillingActionPolicy policy, final CallContext context) throws SubscriptionBaseApiException {
         final EntitlementState currentState = subscription.getState();
-        if (currentState != EntitlementState.ACTIVE) {
+        if (currentState != null && currentState != EntitlementState.ACTIVE) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
         }
         final DateTime now = clock.getUTCNow();
-        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy);
+        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), policy);
 
         return doCancelPlan(subscription, now, effectiveDate, context);
     }
@@ -260,14 +258,14 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
             validateEffectiveDate(subscription, effectiveDate);
 
             final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
-            final List<SubscriptionBaseEvent> cancelEvents = getEventsOnCancelPlan(subscription, now, effectiveDate, now, false, internalCallContext);
+            final List<SubscriptionBaseEvent> cancelEvents = getEventsOnCancelPlan(subscription, effectiveDate, now, false, internalCallContext);
             // cancelEvents will contain only one item
             dao.cancelSubscription(subscription, cancelEvents.get(0), internalCallContext, 0);
             final Catalog fullCatalog = catalogService.getFullCatalog(internalCallContext);
             subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), fullCatalog);
 
             if (subscription.getCategory() == ProductCategory.BASE) {
-                final Product baseProduct = (subscription.getState() == EntitlementState.CANCELLED) ? null : subscription.getCurrentPlan().getProduct();
+                final Product baseProduct = (subscription.getState() == null || subscription.getState() == EntitlementState.CANCELLED) ? null : subscription.getCurrentPlan().getProduct();
                 cancelAddOnsIfRequired(baseProduct, subscription.getBundleId(), effectiveDate, context);
             }
 
@@ -288,7 +286,6 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         final SubscriptionBaseEvent uncancelEvent = new ApiEventUncancel(new ApiEventBuilder()
                                                                                  .setSubscriptionId(subscription.getId())
                                                                                  .setActiveVersion(subscription.getActiveVersion())
-                                                                                 .setRequestedDate(now)
                                                                                  .setEffectiveDate(now)
                                                                                  .setFromDisk(true));
 
@@ -296,9 +293,9 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         uncancelEvents.add(uncancelEvent);
 
         final InternalCallContext internalCallContext = createCallContextFromBundleId(subscription.getBundleId(), context);
-        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now, internalCallContext);
+        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, internalCallContext);
         final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
-                                          PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(), nextTimedPhase.getPhase().getName(), now, nextTimedPhase.getStartPhase()) :
+                                          PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(), nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) :
                                           null;
         if (nextPhaseEvent != null) {
             uncancelEvents.add(nextPhaseEvent);
@@ -322,7 +319,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         validateEntitlementState(subscription);
 
         final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, now, context);
-        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(planChangeResult.getPolicy());
+        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), planChangeResult.getPolicy());
         validateEffectiveDate(subscription, effectiveDate);
 
         try {
@@ -357,7 +354,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
         validateEntitlementState(subscription);
 
-        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy);
+        final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), policy);
         try {
             return doChangePlan(subscription, productName, term, priceList, overrides, now, effectiveDate, context);
         } catch (final CatalogApiException e) {
@@ -407,7 +404,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
         if (newPlan.getProduct().getCategory() != subscription.getCategory()) {
             throw new SubscriptionBaseApiException(ErrorCode.SUB_CHANGE_INVALID, subscription.getId());
         }
-        final List<SubscriptionBaseEvent> changeEvents = getEventsOnChangePlan(subscription, newPlan, newPriceList, now, effectiveDate, now, false, internalCallContext);
+        final List<SubscriptionBaseEvent> changeEvents = getEventsOnChangePlan(subscription, newPlan, newPriceList, effectiveDate, now, false, internalCallContext);
         dao.changePlan(subscription, changeEvents, internalCallContext);
         subscription.rebuildTransitions(dao.getEventsForSubscription(subscription.getId(), internalCallContext), catalogService.getFullCatalog(internalCallContext));
 
@@ -421,10 +418,10 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     @Override
     public List<SubscriptionBaseEvent> getEventsOnCreation(final UUID bundleId, final UUID subscriptionId, final DateTime alignStartDate, final DateTime bundleStartDate, final long activeVersion,
                                                            final Plan plan, final PhaseType initialPhase,
-                                                           final String realPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
+                                                           final String realPriceList, final DateTime effectiveDate, final DateTime processedDate,
                                                            final boolean reCreate, final InternalTenantContext internalTenantContext) throws CatalogApiException, SubscriptionBaseApiException {
         final TimedPhase[] curAndNextPhases = planAligner.getCurrentAndNextTimedPhaseOnCreate(alignStartDate, bundleStartDate, plan, initialPhase,
-                                                                                              realPriceList, requestedDate, effectiveDate, internalTenantContext);
+                                                                                              realPriceList, effectiveDate, internalTenantContext);
 
         final ApiEventBuilder createBuilder = new ApiEventBuilder()
                 .setSubscriptionId(subscriptionId)
@@ -433,13 +430,12 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                 .setEventPriceList(realPriceList)
                 .setActiveVersion(activeVersion)
                 .setEffectiveDate(effectiveDate)
-                .setRequestedDate(requestedDate)
                 .setFromDisk(true);
         final ApiEvent creationEvent = (reCreate) ? new ApiEventReCreate(createBuilder) : new ApiEventCreate(createBuilder);
 
         final TimedPhase nextTimedPhase = curAndNextPhases[1];
         final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
-                                          PhaseEventData.createNextPhaseEvent(subscriptionId, activeVersion, nextTimedPhase.getPhase().getName(), processedDate, nextTimedPhase.getStartPhase()) :
+                                          PhaseEventData.createNextPhaseEvent(subscriptionId, activeVersion, nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) :
                                           null;
         final List<SubscriptionBaseEvent> events = new ArrayList<SubscriptionBaseEvent>();
         events.add(creationEvent);
@@ -451,9 +447,9 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
     @Override
     public List<SubscriptionBaseEvent> getEventsOnChangePlan(final DefaultSubscriptionBase subscription, final Plan newPlan,
-                                                             final String newPriceList, final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
+                                                             final String newPriceList, final DateTime effectiveDate, final DateTime processedDate,
                                                              final boolean addCancellationAddOnForEventsIfRequired, final InternalTenantContext internalTenantContext) throws CatalogApiException, SubscriptionBaseApiException {
-        final TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, newPriceList, requestedDate, effectiveDate, internalTenantContext);
+        final TimedPhase currentTimedPhase = planAligner.getCurrentTimedPhaseOnChange(subscription, newPlan, newPriceList, effectiveDate, internalTenantContext);
 
         final SubscriptionBaseEvent changeEvent = new ApiEventChange(new ApiEventBuilder()
                                                                              .setSubscriptionId(subscription.getId())
@@ -462,13 +458,12 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                                                              .setEventPriceList(newPriceList)
                                                                              .setActiveVersion(subscription.getActiveVersion())
                                                                              .setEffectiveDate(effectiveDate)
-                                                                             .setRequestedDate(requestedDate)
                                                                              .setFromDisk(true));
 
-        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList, processedDate, effectiveDate, internalTenantContext);
+        final TimedPhase nextTimedPhase = planAligner.getNextTimedPhaseOnChange(subscription, newPlan, newPriceList, effectiveDate, internalTenantContext);
         final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                                           PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(),
-                                                                              nextTimedPhase.getPhase().getName(), processedDate, nextTimedPhase.getStartPhase()) :
+                                                                              nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) :
                                           null;
 
         final List<SubscriptionBaseEvent> changeEvents = new ArrayList<SubscriptionBaseEvent>();
@@ -480,26 +475,25 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
         if (subscription.getCategory() == ProductCategory.BASE && addCancellationAddOnForEventsIfRequired) {
             final Product currentBaseProduct = changeEvent.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0 ? newPlan.getProduct() : subscription.getCurrentPlan().getProduct();
-            addCancellationAddOnForEventsIfRequired(changeEvents, currentBaseProduct, subscription.getBundleId(), requestedDate, effectiveDate, processedDate, internalTenantContext);
+            addCancellationAddOnForEventsIfRequired(changeEvents, currentBaseProduct, subscription.getBundleId(), effectiveDate, internalTenantContext);
         }
         return changeEvents;
     }
 
     @Override
     public List<SubscriptionBaseEvent> getEventsOnCancelPlan(final DefaultSubscriptionBase subscription,
-                                                             final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate,
+                                                             final DateTime effectiveDate, final DateTime processedDate,
                                                              final boolean addCancellationAddOnForEventsIfRequired, final InternalTenantContext internalTenantContext) throws CatalogApiException {
         final List<SubscriptionBaseEvent> cancelEvents = new ArrayList<SubscriptionBaseEvent>();
         final SubscriptionBaseEvent cancelEvent = new ApiEventCancel(new ApiEventBuilder()
                                                                              .setSubscriptionId(subscription.getId())
                                                                              .setActiveVersion(subscription.getActiveVersion())
                                                                              .setEffectiveDate(effectiveDate)
-                                                                             .setRequestedDate(requestedDate)
                                                                              .setFromDisk(true));
         cancelEvents.add(cancelEvent);
         if (subscription.getCategory() == ProductCategory.BASE && addCancellationAddOnForEventsIfRequired) {
             final Product currentBaseProduct = cancelEvent.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0 ? null : subscription.getCurrentPlan().getProduct();
-            addCancellationAddOnForEventsIfRequired(cancelEvents, currentBaseProduct, subscription.getBundleId(), requestedDate, effectiveDate, processedDate, internalTenantContext);
+            addCancellationAddOnForEventsIfRequired(cancelEvents, currentBaseProduct, subscription.getBundleId(), effectiveDate, internalTenantContext);
         }
         return cancelEvents;
     }
@@ -513,7 +507,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
         final List<SubscriptionBaseEvent> cancelEvents = new LinkedList<SubscriptionBaseEvent>();
         final InternalCallContext internalCallContext = createCallContextFromBundleId(bundleId, context);
-        final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = addCancellationAddOnForEventsIfRequired(cancelEvents, baseProduct, bundleId, now, effectiveDate, now, internalCallContext);
+        final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = addCancellationAddOnForEventsIfRequired(cancelEvents, baseProduct, bundleId, effectiveDate, internalCallContext);
         if (!subscriptionsToBeCancelled.isEmpty()) {
             dao.cancelSubscriptions(subscriptionsToBeCancelled, cancelEvents, internalCallContext);
         }
@@ -521,7 +515,7 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
     }
 
     private List<DefaultSubscriptionBase> addCancellationAddOnForEventsIfRequired(final List<SubscriptionBaseEvent> events, final Product baseProduct, final UUID bundleId,
-                                                                                  final DateTime requestedDate, final DateTime effectiveDate, final DateTime processedDate, final InternalTenantContext internalTenantContext) throws CatalogApiException {
+                                                                                  final DateTime effectiveDate, final InternalTenantContext internalTenantContext) throws CatalogApiException {
 
         final List<DefaultSubscriptionBase> subscriptionsToBeCancelled = new ArrayList<DefaultSubscriptionBase>();
 
@@ -536,8 +530,8 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
 
             final Plan addonCurrentPlan = cur.getCurrentPlan();
             if (baseProduct == null ||
-                addonUtils.isAddonIncludedFromProdName(baseProduct.getName(), addonCurrentPlan, requestedDate, internalTenantContext) ||
-                !addonUtils.isAddonAvailableFromProdName(baseProduct.getName(), addonCurrentPlan, requestedDate, internalTenantContext)) {
+                addonUtils.isAddonIncludedFromProdName(baseProduct.getName(), addonCurrentPlan, effectiveDate, internalTenantContext) ||
+                !addonUtils.isAddonAvailableFromProdName(baseProduct.getName(), addonCurrentPlan, effectiveDate, internalTenantContext)) {
                 //
                 // Perform AO cancellation using the effectiveDate of the BP
                 //
@@ -545,7 +539,6 @@ public class DefaultSubscriptionBaseApiService implements SubscriptionBaseApiSer
                                                                                      .setSubscriptionId(cur.getId())
                                                                                      .setActiveVersion(cur.getActiveVersion())
                                                                                      .setEffectiveDate(effectiveDate)
-                                                                                     .setRequestedDate(requestedDate)
                                                                                      .setFromDisk(true));
                 subscriptionsToBeCancelled.add(cur);
                 events.add(cancelEvent);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionEvent.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionEvent.java
index 8389665..04601ac 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionEvent.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionEvent.java
@@ -56,7 +56,7 @@ public abstract class DefaultSubscriptionEvent extends BusEventBase implements S
         this(in.getId(),
              in.getSubscriptionId(),
              in.getBundleId(),
-             in.getRequestedTransitionTime(),
+             in.getEffectiveTransitionTime(),
              in.getEffectiveTransitionTime(),
              in.getPreviousState(),
              (in.getPreviousPlan() != null) ? in.getPreviousPlan().getName() : null,
@@ -185,7 +185,7 @@ public abstract class DefaultSubscriptionEvent extends BusEventBase implements S
 
     @Override
     public DateTime getRequestedTransitionTime() {
-        return requestedTransitionTime;
+        return effectiveTransitionTime;
     }
 
     @Override
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransitionData.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransitionData.java
index ab71855..df2ccad 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransitionData.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransitionData.java
@@ -36,7 +36,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
     private final UUID eventId;
     private final EventType eventType;
     private final ApiEventType apiEventType;
-    private final DateTime requestedTransitionTime;
     private final DateTime effectiveTransitionTime;
     private final EntitlementState previousState;
     private final PriceList previousPriceList;
@@ -60,7 +59,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
                                           final UUID bundleId,
                                           final EventType eventType,
                                           final ApiEventType apiEventType,
-                                          final DateTime requestedTransitionTime,
                                           final DateTime effectiveTransitionTime,
                                           final UUID previousEventId,
                                           final DateTime previousEventCreatedDate,
@@ -83,7 +81,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
         this.bundleId = bundleId;
         this.eventType = eventType;
         this.apiEventType = apiEventType;
-        this.requestedTransitionTime = requestedTransitionTime;
         this.effectiveTransitionTime = effectiveTransitionTime;
         this.previousState = previousState;
         this.previousPriceList = previousPriceList;
@@ -116,7 +113,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
         this.bundleId = input.getBundleId();
         this.eventType = eventType;
         this.apiEventType = apiEventType;
-        this.requestedTransitionTime = input.getRequestedTransitionTime();
         this.effectiveTransitionTime = input.getEffectiveTransitionTime();
         this.previousEventId = input.getPreviousEventId();
         this.previousEventCreatedDate = input.getPreviousEventCreatedDate();
@@ -241,11 +237,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
     }
 
     @Override
-    public DateTime getRequestedTransitionTime() {
-        return requestedTransitionTime;
-    }
-
-    @Override
     public DateTime getEffectiveTransitionTime() {
         return effectiveTransitionTime;
     }
@@ -276,7 +267,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
         sb.append(", bundleId=").append(bundleId);
         sb.append(", eventId=").append(eventId);
         sb.append(", eventType=").append(eventType);
-        sb.append(", requestedTransitionTime=").append(requestedTransitionTime);
         sb.append(", effectiveTransitionTime=").append(effectiveTransitionTime);
         sb.append(", previousState=").append(previousState);
         sb.append(", previousPriceList=").append(previousPriceList);
@@ -349,9 +339,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
         if (remainingEventsForUserOperation != null ? !remainingEventsForUserOperation.equals(that.remainingEventsForUserOperation) : that.remainingEventsForUserOperation != null) {
             return false;
         }
-        if (requestedTransitionTime != null ? requestedTransitionTime.compareTo(that.requestedTransitionTime) != 0 : that.requestedTransitionTime != null) {
-            return false;
-        }
         if (subscriptionId != null ? !subscriptionId.equals(that.subscriptionId) : that.subscriptionId != null) {
             return false;
         }
@@ -373,7 +360,6 @@ public class SubscriptionBaseTransitionData implements SubscriptionBaseTransitio
         result = 31 * result + (eventId != null ? eventId.hashCode() : 0);
         result = 31 * result + (eventType != null ? eventType.hashCode() : 0);
         result = 31 * result + (apiEventType != null ? apiEventType.hashCode() : 0);
-        result = 31 * result + (requestedTransitionTime != null ? requestedTransitionTime.hashCode() : 0);
         result = 31 * result + (effectiveTransitionTime != null ? effectiveTransitionTime.hashCode() : 0);
         result = 31 * result + (previousState != null ? previousState.hashCode() : 0);
         result = 31 * result + (previousPriceList != null ? previousPriceList.hashCode() : 0);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionSpecifier.java b/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionSpecifier.java
index 154ee62..aa5ebf4 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionSpecifier.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionSpecifier.java
@@ -27,7 +27,6 @@ public class SubscriptionSpecifier {
     private Plan plan;
     private PhaseType initialPhase;
     private String realPriceList;
-    private DateTime requestedDate;
     private DateTime effectiveDate;
     private DateTime processedDate;
 
@@ -36,13 +35,12 @@ public class SubscriptionSpecifier {
 
     public SubscriptionSpecifier(final SubscriptionBuilder builder, final Plan plan,
                                  final PhaseType initialPhase, final String realPriceList,
-                                 final DateTime requestedDate, final DateTime effectiveDate,
+                                 final DateTime effectiveDate,
                                  final DateTime processedDate) {
         this.builder = builder;
         this.plan = plan;
         this.initialPhase = initialPhase;
         this.realPriceList = realPriceList;
-        this.requestedDate = requestedDate;
         this.effectiveDate = effectiveDate;
         this.processedDate = processedDate;
     }
@@ -79,14 +77,6 @@ public class SubscriptionSpecifier {
         this.realPriceList = realPriceList;
     }
 
-    public DateTime getRequestedDate() {
-        return requestedDate;
-    }
-
-    public void setRequestedDate(final DateTime requestedDate) {
-        this.requestedDate = requestedDate;
-    }
-
     public DateTime getEffectiveDate() {
         return effectiveDate;
     }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
index a1dcae8..8b4fbe8 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java
@@ -185,10 +185,10 @@ public class DefaultSubscriptionBaseService implements EventListener, Subscripti
     private void onPhaseEvent(final DefaultSubscriptionBase subscription, final InternalCallContext context) {
         try {
             final DateTime now = clock.getUTCNow();
-            final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, now, context);
+            final TimedPhase nextTimedPhase = planAligner.getNextTimedPhase(subscription, now, context);
             final PhaseEvent nextPhaseEvent = (nextTimedPhase != null) ?
                                               PhaseEventData.createNextPhaseEvent(subscription.getId(), subscription.getActiveVersion(),
-                                                                                  nextTimedPhase.getPhase().getName(), now, nextTimedPhase.getStartPhase()) :
+                                                                                  nextTimedPhase.getPhase().getName(), nextTimedPhase.getStartPhase()) :
                                               null;
             if (nextPhaseEvent != null) {
                 dao.createNextPhaseEvent(subscription, nextPhaseEvent, context);
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
index 4a72049..c1e403b 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java
@@ -642,7 +642,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                                                                                                                                                    entitySqlDaoWrapperFactory,
                                                                                                                                                    context);
 
-                cancelFutureEventsFromTransaction(subscriptionId, entitySqlDaoWrapperFactory, context);
+                cancelFutureEventsFromTransaction(subscriptionId, changeEvents.get(0).getEffectiveDate(), entitySqlDaoWrapperFactory, context);
 
                 for (final SubscriptionBaseEvent cur : changeEventsTweakedWithMigrateBilling) {
 
@@ -728,7 +728,6 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                     .setSubscriptionId(migrateBillingEvent.getSubscriptionId())
                     .setCreatedDate(now)
                     .setUpdatedDate(now)
-                    .setRequestedDate(migrateBillingEvent.getRequestedDate())
                     .setEffectiveDate(migrateBillingEvent.getEffectiveDate())
                     .setActiveVersion(migrateBillingEvent.getCurrentVersion())
                     .setEventPlan(prevPlan)
@@ -777,7 +776,7 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
     private void cancelSubscriptionFromTransaction(final DefaultSubscriptionBase subscription, final SubscriptionBaseEvent cancelEvent, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalCallContext context, final int seqId)
             throws EntityPersistenceException {
         final UUID subscriptionId = subscription.getId();
-        cancelFutureEventsFromTransaction(subscriptionId, entitySqlDaoWrapperFactory, context);
+        cancelFutureEventsFromTransaction(subscriptionId, cancelEvent.getEffectiveDate(), entitySqlDaoWrapperFactory, context);
         entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).create(new SubscriptionEventModelDao(cancelEvent), context);
 
         final boolean isBusEvent = cancelEvent.getEffectiveDate().compareTo(clock.getUTCNow()) <= 0;
@@ -791,9 +790,8 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
         cancelFutureEventFromTransaction(subscriptionId, entitySqlDaoWrapperFactory, EventType.PHASE, null, context);
     }
 
-    private void cancelFutureEventsFromTransaction(final UUID subscriptionId, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalCallContext context) {
-        final Date now = clock.getUTCNow().toDate();
-        final List<SubscriptionEventModelDao> eventModels = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getFutureActiveEventForSubscription(subscriptionId.toString(), now, context);
+    private void cancelFutureEventsFromTransaction(final UUID subscriptionId, final DateTime effectiveDate, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalCallContext context) {
+        final List<SubscriptionEventModelDao> eventModels = entitySqlDaoWrapperFactory.become(SubscriptionEventSqlDao.class).getFutureActiveEventForSubscription(subscriptionId.toString(), effectiveDate.toDate(), context);
         for (final SubscriptionEventModelDao cur : eventModels) {
             unactivateEventFromTransaction(cur, entitySqlDaoWrapperFactory, context);
         }
@@ -936,7 +934,6 @@ public class DefaultSubscriptionDao extends EntityDaoBase<SubscriptionBundleMode
                                                                                                   .setSubscriptionId(reloaded.getId())
                                                                                                   .setActiveVersion(((DefaultSubscriptionBase) reloaded).getActiveVersion())
                                                                                                   .setEffectiveDate(baseTriggerEventForAddOnCancellation.getEffectiveDate())
-                                                                                                  .setRequestedDate(now)
                                                                                                   .setCreatedDate(baseTriggerEventForAddOnCancellation.getCreatedDate())
                                                                                                   // This event is only there to indicate the ADD_ON is future canceled, but it is not there
                                                                                                   // on disk until the base plan cancellation becomes effective
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java
index 58d75af..73d4492 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java
@@ -47,7 +47,7 @@ public class SubscriptionEventModelDao extends EntityModelDaoBase implements Ent
     private long totalOrdering;
     private EventType eventType;
     private ApiEventType userType;
-    private DateTime requestedDate;
+    private DateTime requestedDate; // deprecated (similar to effectiveDate)
     private DateTime effectiveDate;
     private UUID subscriptionId;
     private String planName;
@@ -83,7 +83,7 @@ public class SubscriptionEventModelDao extends EntityModelDaoBase implements Ent
         this.totalOrdering = src.getTotalOrdering();
         this.eventType = src.getType();
         this.userType = eventType == EventType.API_USER ? ((ApiEvent) src).getApiEventType() : null;
-        this.requestedDate = src.getRequestedDate();
+        this.requestedDate = src.getEffectiveDate();
         this.effectiveDate = src.getEffectiveDate();
         this.subscriptionId = src.getSubscriptionId();
         this.planName = eventType == EventType.API_USER ? ((ApiEvent) src).getEventPlan() : null;
@@ -200,7 +200,6 @@ public class SubscriptionEventModelDao extends EntityModelDaoBase implements Ent
                 .setSubscriptionId(src.getSubscriptionId())
                 .setCreatedDate(src.getCreatedDate())
                 .setUpdatedDate(src.getUpdatedDate())
-                .setRequestedDate(src.getRequestedDate())
                 .setEffectiveDate(src.getEffectiveDate())
                 .setActiveVersion(src.getCurrentVersion())
                 .setActive(src.isActive());
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/events/EventBase.java b/subscription/src/main/java/org/killbill/billing/subscription/events/EventBase.java
index 35fdd1e..ed379f8 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/events/EventBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/events/EventBase.java
@@ -28,7 +28,6 @@ public abstract class EventBase implements SubscriptionBaseEvent {
     private final UUID subscriptionId;
     private final DateTime createdDate;
     private final DateTime updatedDate;
-    private final DateTime requestedDate;
     private final DateTime effectiveDate;
 
     private final long totalOrdering;
@@ -41,18 +40,12 @@ public abstract class EventBase implements SubscriptionBaseEvent {
         this.subscriptionId = builder.getSubscriptionId();
         this.createdDate = builder.getCreatedDate();
         this.updatedDate = builder.getUpdatedDate();
-        this.requestedDate = builder.getRequestedDate();
         this.effectiveDate = builder.getEffectiveDate();
         this.activeVersion = builder.getActiveVersion();
         this.isActive = builder.isActive();
     }
 
     @Override
-    public DateTime getRequestedDate() {
-        return requestedDate;
-    }
-
-    @Override
     public DateTime getEffectiveDate() {
         return effectiveDate;
     }
@@ -111,10 +104,6 @@ public abstract class EventBase implements SubscriptionBaseEvent {
             return -1;
         } else if (effectiveDate.isAfter(other.getEffectiveDate())) {
             return 1;
-        } else if (requestedDate.isBefore(other.getRequestedDate())) {
-            return -1;
-        } else if (requestedDate.isAfter(other.getRequestedDate())) {
-            return 1;
         } else if (getType() != other.getType()) {
             return (getType() == EventType.PHASE) ? -1 : 1;
         } else if (getType() == EventType.API_USER) {
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/events/EventBaseBuilder.java b/subscription/src/main/java/org/killbill/billing/subscription/events/EventBaseBuilder.java
index 7487b8a..4dd7b96 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/events/EventBaseBuilder.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/events/EventBaseBuilder.java
@@ -29,7 +29,6 @@ public abstract class EventBaseBuilder<T extends EventBaseBuilder<T>> {
     private UUID subscriptionId;
     private DateTime createdDate;
     private DateTime updatedDate;
-    private DateTime requestedDate;
     private DateTime effectiveDate;
 
     private long activeVersion;
@@ -44,7 +43,6 @@ public abstract class EventBaseBuilder<T extends EventBaseBuilder<T>> {
     public EventBaseBuilder(final SubscriptionBaseEvent event) {
         this.uuid = event.getId();
         this.subscriptionId = event.getSubscriptionId();
-        this.requestedDate = event.getRequestedDate();
         this.effectiveDate = event.getEffectiveDate();
         this.createdDate = event.getCreatedDate();
         this.updatedDate = event.getUpdatedDate();
@@ -56,7 +54,6 @@ public abstract class EventBaseBuilder<T extends EventBaseBuilder<T>> {
     public EventBaseBuilder(final EventBaseBuilder<?> copy) {
         this.uuid = copy.uuid;
         this.subscriptionId = copy.subscriptionId;
-        this.requestedDate = copy.requestedDate;
         this.effectiveDate = copy.effectiveDate;
         this.createdDate = copy.getCreatedDate();
         this.updatedDate = copy.getUpdatedDate();
@@ -90,11 +87,6 @@ public abstract class EventBaseBuilder<T extends EventBaseBuilder<T>> {
         return (T) this;
     }
 
-    public T setRequestedDate(final DateTime requestedDate) {
-        this.requestedDate = requestedDate;
-        return (T) this;
-    }
-
     public T setEffectiveDate(final DateTime effectiveDate) {
         this.effectiveDate = effectiveDate;
         return (T) this;
@@ -130,10 +122,6 @@ public abstract class EventBaseBuilder<T extends EventBaseBuilder<T>> {
         return subscriptionId;
     }
 
-    public DateTime getRequestedDate() {
-        return requestedDate;
-    }
-
     public DateTime getEffectiveDate() {
         return effectiveDate;
     }
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/events/phase/PhaseEventData.java b/subscription/src/main/java/org/killbill/billing/subscription/events/phase/PhaseEventData.java
index 6da067c..07afcdf 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/events/phase/PhaseEventData.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/events/phase/PhaseEventData.java
@@ -50,19 +50,17 @@ public class PhaseEventData extends EventBase implements PhaseEvent {
                 + ", phaseName=" + phaseName
                 + ", getType()=" + getType()
                 + ", getPhase()=" + getPhase()
-                + ", getRequestedDate()=" + getRequestedDate()
                 + ", getEffectiveDate()=" + getEffectiveDate()
                 + ", getActiveVersion()=" + getActiveVersion()
                 + ", getSubscriptionId()=" + getSubscriptionId()
                 + ", isActive()=" + isActive() + "]\n";
     }
 
-    public static PhaseEvent createNextPhaseEvent(final UUID subscriptionId, final long activeVersion, final String phaseName,  final DateTime now, final DateTime effectiveDate) {
+    public static PhaseEvent createNextPhaseEvent(final UUID subscriptionId, final long activeVersion, final String phaseName, final DateTime effectiveDate) {
         return (phaseName == null) ?
                 null :
                 new PhaseEventData(new PhaseEventBuilder()
                                            .setSubscriptionId(subscriptionId)
-                                           .setRequestedDate(now)
                                            .setEffectiveDate(effectiveDate)
                                            .setActiveVersion(activeVersion)
                                            .setPhaseName(phaseName));
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/events/SubscriptionBaseEvent.java b/subscription/src/main/java/org/killbill/billing/subscription/events/SubscriptionBaseEvent.java
index c610aa0..1f81e63 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/events/SubscriptionBaseEvent.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/events/SubscriptionBaseEvent.java
@@ -38,8 +38,6 @@ public interface SubscriptionBaseEvent extends Comparable<SubscriptionBaseEvent>
 
     public boolean isActive();
 
-    public DateTime getRequestedDate();
-
     public DateTime getEffectiveDate();
 
     public UUID getSubscriptionId();
diff --git a/subscription/src/main/java/org/killbill/billing/subscription/events/user/ApiEventBase.java b/subscription/src/main/java/org/killbill/billing/subscription/events/user/ApiEventBase.java
index be40564..98f6b9e 100644
--- a/subscription/src/main/java/org/killbill/billing/subscription/events/user/ApiEventBase.java
+++ b/subscription/src/main/java/org/killbill/billing/subscription/events/user/ApiEventBase.java
@@ -77,7 +77,6 @@ public class ApiEventBase extends EventBase implements ApiEvent {
                + ", getEventPlan()=" + getEventPlan()
                + ", getEventPlanPhase()=" + getEventPlanPhase()
                + ", getType()=" + getType()
-               + ", getRequestedDate()=" + getRequestedDate()
                + ", getEffectiveDate()=" + getEffectiveDate()
                + ", getActiveVersion()=" + getActiveVersion()
                + ", getSubscriptionId()=" + getSubscriptionId()
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java b/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java
index 4d7a3e6..0ec542a 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java
@@ -85,7 +85,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
 
         // Verify the next phase via the other API
-        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate, internalCallContext);
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, internalCallContext);
         Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getBundleStartDate().plusDays(30));
 
         // Now look at the past, before the bundle started
@@ -96,7 +96,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
 
         // Verify the next phase via the other API
         try {
-            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast, internalCallContext);
+            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, internalCallContext);
             Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
         } catch (SubscriptionBaseError e) {
             Assert.assertTrue(true);
@@ -130,7 +130,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         Assert.assertEquals(phases[1].getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
 
         // Verify the next phase via the other API
-        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, effectiveDate, internalCallContext);
+        final TimedPhase nextTimePhase = planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDate, internalCallContext);
         Assert.assertEquals(nextTimePhase.getStartPhase(), defaultSubscriptionBase.getStartDate().plusMonths(1));
 
         // Now look at the past, before the subscription started
@@ -141,7 +141,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
 
         // Verify the next phase via the other API
         try {
-            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, effectiveDateInThePast, internalCallContext);
+            planAligner.getNextTimedPhase(defaultSubscriptionBase, effectiveDateInThePast, internalCallContext);
             Assert.fail("Can't use getNextTimedPhase(): the effective date is before the initial plan");
         } catch (SubscriptionBaseError e) {
             Assert.assertTrue(true);
@@ -219,7 +219,6 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         eventBuilder.setEventPriceList(priceList);
 
         // We don't really use the following but the code path requires it
-        eventBuilder.setRequestedDate(effectiveDate);
         eventBuilder.setFromDisk(true);
         eventBuilder.setActiveVersion(activeVersion);
 
@@ -232,7 +231,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
         // The date is used for different catalog versions - we don't care here
         final Plan newPlan = catalogService.getFullCatalog(internalCallContext).findPlan(newProductName, clock.getUTCNow());
 
-        return planAligner.getNextTimedPhaseOnChange(defaultSubscriptionBase, newPlan, priceList, effectiveChangeDate, effectiveChangeDate, internalCallContext);
+        return planAligner.getNextTimedPhaseOnChange(defaultSubscriptionBase, newPlan, priceList, effectiveChangeDate, internalCallContext);
     }
 
     private TimedPhase[] getTimedPhasesOnCreate(final String productName,
@@ -244,7 +243,7 @@ public class TestPlanAligner extends SubscriptionTestSuiteNoDB {
 
         // Same here for the requested date
         final TimedPhase[] phases = planAligner.getCurrentAndNextTimedPhaseOnCreate(defaultSubscriptionBase.getAlignStartDate(), defaultSubscriptionBase.getBundleStartDate(),
-                                                                                    plan, initialPhase, priceList, clock.getUTCNow(), effectiveDate, internalCallContext);
+                                                                                    plan, initialPhase, priceList, effectiveDate, internalCallContext);
         Assert.assertEquals(phases.length, 2);
 
         return phases;
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java b/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java
index 1141782..90b3822 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/TestEventJson.java
@@ -35,7 +35,7 @@ public class TestEventJson extends GuicyKillbillTestSuiteNoDB {
     @Test(groups = "fast")
     public void testSubscriptionEvent() throws Exception {
 
-        final EffectiveSubscriptionInternalEvent e = new DefaultEffectiveSubscriptionEvent(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), new DateTime(), new DateTime(),
+        final EffectiveSubscriptionInternalEvent e = new DefaultEffectiveSubscriptionEvent(UUID.randomUUID(), UUID.randomUUID(), UUID.randomUUID(), new DateTime(),
                                                                                            EntitlementState.ACTIVE, "pro", "TRIAL", "DEFAULT", EntitlementState.CANCELLED, null, null, null, 3L,
                                                                                            SubscriptionBaseTransitionType.CANCEL, 0, new DateTime(), 1L, 2L, null);
 
diff --git a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java
index f3418f9..01a93e7 100644
--- a/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java
+++ b/subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java
@@ -349,7 +349,7 @@ public class TestUserApiChangePlan extends SubscriptionTestSuiteWithEmbeddedDB {
         assertEquals(currentPhase.getPhaseType(), PhaseType.DISCOUNT);
 
         // ACTIVATE CHANGE BY MOVING AFTER CTD
-        testListener.pushExpectedEvent(NextEvent.CHANGE);
+        testListener.pushExpectedEvents(NextEvent.CHANGE, NextEvent.CHANGE);
         it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusMonths(1));
         clock.addDeltaFromReality(it.toDurationMillis());
         assertListenerStatus();

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

diff --git a/tenant/pom.xml b/tenant/pom.xml
index 813cffb..793b2ce 100644
--- a/tenant/pom.xml
+++ b/tenant/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-tenant</artifactId>

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

diff --git a/usage/pom.xml b/usage/pom.xml
index 8c45851..5861678 100644
--- a/usage/pom.xml
+++ b/usage/pom.xml
@@ -19,7 +19,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-usage</artifactId>

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

diff --git a/util/pom.xml b/util/pom.xml
index 26cf048..9a981a5 100644
--- a/util/pom.xml
+++ b/util/pom.xml
@@ -21,7 +21,7 @@
     <parent>
         <artifactId>killbill</artifactId>
         <groupId>org.kill-bill.billing</groupId>
-        <version>0.15.11-SNAPSHOT</version>
+        <version>0.16.1-SNAPSHOT</version>
         <relativePath>../pom.xml</relativePath>
     </parent>
     <artifactId>killbill-util</artifactId>
diff --git a/util/src/main/java/org/killbill/billing/util/PluginProperties.java b/util/src/main/java/org/killbill/billing/util/PluginProperties.java
new file mode 100644
index 0000000..c7e4e4e
--- /dev/null
+++ b/util/src/main/java/org/killbill/billing/util/PluginProperties.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.util;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nullable;
+
+import org.killbill.billing.payment.api.PluginProperty;
+
+import com.google.common.collect.ImmutableList;
+
+public abstract class PluginProperties {
+
+    // Last one has precedence
+    public static Iterable<PluginProperty> merge(final Iterable<PluginProperty>... propertiesLists) {
+        return buildPluginProperties(toMap(propertiesLists));
+    }
+
+    // Last one has precedence
+    public static Map<String, Object> toMap(final Iterable<PluginProperty>... propertiesLists) {
+        final Map<String, Object> mergedProperties = new HashMap<String, Object>();
+        for (final Iterable<PluginProperty> propertiesList : propertiesLists) {
+            for (final PluginProperty pluginProperty : propertiesList) {
+                if (pluginProperty.getKey() != null) {
+                    mergedProperties.put(pluginProperty.getKey(), pluginProperty.getValue());
+                }
+            }
+        }
+        return mergedProperties;
+    }
+
+    public static List<PluginProperty> buildPluginProperties(@Nullable final Map<String, Object> data) {
+        final ImmutableList.Builder<PluginProperty> propertiesBuilder = ImmutableList.<PluginProperty>builder();
+        if (data != null) {
+            for (final String key : data.keySet()) {
+                final PluginProperty property = new PluginProperty(key, data.get(key), false);
+                propertiesBuilder.add(property);
+            }
+        }
+        return propertiesBuilder.build();
+    }
+}
diff --git a/util/src/test/java/org/killbill/billing/util/TestPluginProperties.java b/util/src/test/java/org/killbill/billing/util/TestPluginProperties.java
new file mode 100644
index 0000000..0978e16
--- /dev/null
+++ b/util/src/test/java/org/killbill/billing/util/TestPluginProperties.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2016 Groupon, Inc
+ * Copyright 2016 The Billing Project, LLC
+ *
+ * The Billing Project 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 org.killbill.billing.util;
+
+import java.util.List;
+import java.util.Map;
+
+import org.killbill.billing.payment.api.PluginProperty;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Function;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Ordering;
+
+public class TestPluginProperties extends UtilTestSuiteNoDB {
+
+    private final List<PluginProperty> pluginProperties1 = PluginProperties.buildPluginProperties(ImmutableMap.<String, Object>of("foo", "bar",
+                                                                                                                                  "baz", 12L));
+    private final List<PluginProperty> pluginProperties2 = PluginProperties.buildPluginProperties(ImmutableMap.<String, Object>of("foo", "override",
+                                                                                                                                  "baz2", "something else"));
+
+    @Test(groups = "fast")
+    public void testMerge() throws Exception {
+        final List<PluginProperty> pluginPropertiesRaw = ImmutableList.<PluginProperty>copyOf(PluginProperties.merge(pluginProperties1, pluginProperties2));
+
+        final List<PluginProperty> pluginProperties = sort(pluginPropertiesRaw);
+
+        Assert.assertEquals(pluginProperties.size(), 3);
+        Assert.assertEquals(pluginProperties.get(0).getKey(), "baz");
+        Assert.assertEquals(pluginProperties.get(0).getValue(), (Long) 12L);
+        Assert.assertFalse(pluginProperties.get(0).getIsUpdatable());
+        Assert.assertEquals(pluginProperties.get(1).getKey(), "baz2");
+        Assert.assertEquals(pluginProperties.get(1).getValue(), "something else");
+        Assert.assertFalse(pluginProperties.get(1).getIsUpdatable());
+        Assert.assertEquals(pluginProperties.get(2).getKey(), "foo");
+        Assert.assertEquals(pluginProperties.get(2).getValue(), "override");
+        Assert.assertFalse(pluginProperties.get(2).getIsUpdatable());
+    }
+
+    @Test(groups = "fast")
+    public void testToMap() throws Exception {
+        final Map<String, Object> properties = PluginProperties.toMap(pluginProperties1, pluginProperties2);
+        Assert.assertEquals(properties.get("baz"), (Long) 12L);
+        Assert.assertEquals(properties.get("baz2"), "something else");
+        Assert.assertEquals(properties.get("foo"), "override");
+    }
+
+    @Test(groups = "fast")
+    public void testBuildPluginProperties() throws Exception {
+        Assert.assertEquals(pluginProperties1.size(), 2);
+        Assert.assertEquals(pluginProperties1.get(0).getKey(), "foo");
+        Assert.assertEquals(pluginProperties1.get(0).getValue(), "bar");
+        Assert.assertFalse(pluginProperties1.get(0).getIsUpdatable());
+        Assert.assertEquals(pluginProperties1.get(1).getKey(), "baz");
+        Assert.assertEquals(pluginProperties1.get(1).getValue(), (Long) 12L);
+        Assert.assertFalse(pluginProperties1.get(1).getIsUpdatable());
+    }
+
+    private List<PluginProperty> sort(final Iterable<PluginProperty> pluginProperties) {
+        return Ordering.natural()
+                       .onResultOf(new Function<PluginProperty, String>() {
+                           @Override
+                           public String apply(final PluginProperty pluginProperty) {
+                               return pluginProperty.getKey();
+                           }
+                       })
+                       .immutableSortedCopy(pluginProperties);
+    }
+}