killbill-aplcache
Changes
account/pom.xml 2(+1 -1)
api/pom.xml 2(+1 -1)
api/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransition.java 2(+0 -2)
beatrix/pom.xml 2(+1 -1)
catalog/pom.xml 2(+1 -1)
currency/pom.xml 2(+1 -1)
entitlement/pom.xml 2(+1 -1)
entitlement/src/main/java/org/killbill/billing/entitlement/api/DefaultSubscriptionEvent.java 3(+1 -2)
entitlement/src/main/java/org/killbill/billing/entitlement/api/SubscriptionEventOrdering.java 1(+0 -1)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionApi.java 73(+73 -0)
entitlement/src/test/java/org/killbill/billing/entitlement/api/TestDefaultSubscriptionBundleTimeline.java 2(+0 -2)
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/killbill/pom.xml 2(+1 -1)
profiles/killpay/pom.xml 2(+1 -1)
profiles/pom.xml 2(+1 -1)
subscription/pom.xml 2(+1 -1)
subscription/src/main/java/org/killbill/billing/subscription/api/migration/DefaultSubscriptionBaseMigrationApi.java 3(+1 -2)
subscription/src/main/java/org/killbill/billing/subscription/api/SubscriptionBaseApiService.java 10(+5 -5)
subscription/src/main/java/org/killbill/billing/subscription/api/svcs/DefaultSubscriptionInternalApi.java 40(+19 -21)
subscription/src/main/java/org/killbill/billing/subscription/api/timeline/DefaultSubscriptionBaseTimeline.java 4(+2 -2)
subscription/src/main/java/org/killbill/billing/subscription/api/transfer/DefaultSubscriptionBaseTransferApi.java 4(+1 -3)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultEffectiveSubscriptionEvent.java 3(+1 -2)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultRequestedSubscriptionEvent.java 2(+1 -1)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBase.java 22(+15 -7)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionBaseApiService.java 71(+32 -39)
subscription/src/main/java/org/killbill/billing/subscription/api/user/DefaultSubscriptionEvent.java 4(+2 -2)
subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionBaseTransitionData.java 14(+0 -14)
subscription/src/main/java/org/killbill/billing/subscription/api/user/SubscriptionSpecifier.java 12(+1 -11)
subscription/src/main/java/org/killbill/billing/subscription/engine/core/DefaultSubscriptionBaseService.java 4(+2 -2)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/DefaultSubscriptionDao.java 11(+4 -7)
subscription/src/main/java/org/killbill/billing/subscription/engine/dao/model/SubscriptionEventModelDao.java 5(+2 -3)
subscription/src/main/java/org/killbill/billing/subscription/events/EventBaseBuilder.java 12(+0 -12)
subscription/src/main/java/org/killbill/billing/subscription/events/phase/PhaseEventData.java 4(+1 -3)
subscription/src/main/java/org/killbill/billing/subscription/events/SubscriptionBaseEvent.java 2(+0 -2)
subscription/src/test/java/org/killbill/billing/subscription/alignment/TestPlanAligner.java 13(+6 -7)
subscription/src/test/java/org/killbill/billing/subscription/api/user/TestUserApiChangePlan.java 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>
entitlement/pom.xml 2(+1 -1)
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>
profiles/killbill/pom.xml 2(+1 -1)
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>
profiles/killpay/pom.xml 2(+1 -1)
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>
subscription/pom.xml 2(+1 -1)
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);
+ }
+}