killbill-uncached
Changes
entitlement/src/main/java/com/ning/billing/entitlement/alignment/MigrationPlanAligner.java 132(+123 -9)
Details
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/MigrationPlanAligner.java b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/MigrationPlanAligner.java
index da1eb4d..66613d3 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/alignment/MigrationPlanAligner.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/alignment/MigrationPlanAligner.java
@@ -16,16 +16,22 @@
package com.ning.billing.entitlement.alignment;
+
import org.joda.time.DateTime;
import com.google.inject.Inject;
+import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Duration;
+import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
+import com.ning.billing.catalog.api.PlanPhaseSpecifier;
import com.ning.billing.entitlement.api.migration.EntitlementMigrationApiException;
-import com.ning.billing.entitlement.api.user.SubscriptionData;
+import com.ning.billing.entitlement.api.migration.EntitlementMigrationApi.EntitlementSubscriptionMigrationCase;
import com.ning.billing.entitlement.events.EntitlementEvent.EventType;
import com.ning.billing.entitlement.events.user.ApiEventType;
+import com.ning.billing.util.clock.DefaultClock;
public class MigrationPlanAligner {
@@ -37,15 +43,84 @@ public class MigrationPlanAligner {
}
- public TimedMigration [] getEventsOnRegularMigration(SubscriptionData subscription,
- Plan plan, PlanPhase initialPhase, String priceList, DateTime effectiveDate) {
+ public TimedMigration [] getEventsMigration(EntitlementSubscriptionMigrationCase [] input, DateTime now)
+ throws EntitlementMigrationApiException {
+
+ try {
+ TimedMigration [] events = null;
+ Plan plan0 = catalogService.getCatalog().findPlan(input[0].getPlanPhaseSpecifer().getProductName(),
+ input[0].getPlanPhaseSpecifer().getBillingPeriod(), input[0].getPlanPhaseSpecifer().getPriceListName());
+
+ Plan plan1 = (input.length > 1) ? catalogService.getCatalog().findPlan(input[1].getPlanPhaseSpecifer().getProductName(),
+ input[1].getPlanPhaseSpecifer().getBillingPeriod(), input[1].getPlanPhaseSpecifer().getPriceListName()) :
+ null;
+
+ DateTime migrationStartDate = now;
+
+ if (isRegularMigratedSubscription(input)) {
+
+ events = getEventsOnRegularMigration(plan0,
+ getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
+ input[0].getPlanPhaseSpecifer().getPriceListName(),
+ now);
+
+ } else if (isRegularFutureCancelledMigratedSubscription(input)) {
+
+ events = getEventsOnFuturePlanCancelMigration(plan0,
+ getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
+ input[0].getPlanPhaseSpecifer().getPriceListName(),
+ now,
+ input[0].getCancelledDate());
+
+ } else if (isPhaseChangeMigratedSubscription(input)) {
+
+ PhaseType curPhaseType = input[0].getPlanPhaseSpecifer().getPhaseType();
+ Duration curPhaseDuration = null;
+ for (PlanPhase cur : plan0.getAllPhases()) {
+ if (cur.getPhaseType() == curPhaseType) {
+ curPhaseDuration = cur.getDuration();
+ break;
+ }
+ }
+ if (curPhaseDuration == null) {
+ throw new EntitlementMigrationApiException(String.format("Failed to compute current phase duration for plan %s and phase %s",
+ plan0.getName(), curPhaseType));
+ }
+
+ migrationStartDate = DefaultClock.removeDuration(input[1].getEffectiveDate(), curPhaseDuration);
+ events = getEventsOnFuturePhaseChangeMigration(plan0,
+ getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
+ input[0].getPlanPhaseSpecifer().getPriceListName(),
+ migrationStartDate,
+ input[1].getEffectiveDate());
+
+ } else if (isPlanChangeMigratedSubscription(input)) {
+
+ events = getEventsOnFuturePlanChangeMigration(plan0,
+ getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
+ plan1,
+ getPlanPhase(plan1, input[1].getPlanPhaseSpecifer().getPhaseType()),
+ input[0].getPlanPhaseSpecifer().getPriceListName(),
+ now,
+ input[1].getEffectiveDate());
+
+ } else {
+ throw new EntitlementMigrationApiException("Unknown migration type");
+ }
+
+ return events;
+ } catch (CatalogApiException e) {
+ throw new EntitlementMigrationApiException(e);
+ }
+ }
+
+ private TimedMigration [] getEventsOnRegularMigration(Plan plan, PlanPhase initialPhase, String priceList, DateTime effectiveDate) {
TimedMigration [] result = new TimedMigration[1];
result[0] = new TimedMigration(effectiveDate, EventType.API_USER, ApiEventType.MIGRATE_ENTITLEMENT, plan, initialPhase, priceList);
return result;
}
- public TimedMigration [] getEventsOnFuturePhaseChangeMigration(SubscriptionData subscription,
- Plan plan, PlanPhase initialPhase, String priceList, DateTime effectiveDate, DateTime effectiveDateForNextPhase)
+ private TimedMigration [] getEventsOnFuturePhaseChangeMigration(Plan plan, PlanPhase initialPhase, String priceList, DateTime effectiveDate, DateTime effectiveDateForNextPhase)
throws EntitlementMigrationApiException {
TimedMigration [] result = new TimedMigration[2];
@@ -69,19 +144,58 @@ public class MigrationPlanAligner {
return result;
}
- public TimedMigration [] getEventsOnFuturePlanChangeMigration(SubscriptionData subscription,
- Plan currentPlan, PlanPhase currentPhase, Plan newPlan, PlanPhase newPhase, String priceList, DateTime effectiveDate, DateTime effectiveDateForChangePlan) {
+ private TimedMigration [] getEventsOnFuturePlanChangeMigration(Plan currentPlan, PlanPhase currentPhase, Plan newPlan, PlanPhase newPhase, String priceList, DateTime effectiveDate, DateTime effectiveDateForChangePlan) {
TimedMigration [] result = new TimedMigration[2];
result[0] = new TimedMigration(effectiveDate, EventType.API_USER, ApiEventType.MIGRATE_ENTITLEMENT, currentPlan, currentPhase, priceList);
result[1] = new TimedMigration(effectiveDateForChangePlan, EventType.API_USER, ApiEventType.CHANGE, newPlan, newPhase, priceList);
return result;
}
- public TimedMigration [] getEventsOnFuturePlanCancelMigration(SubscriptionData subscription,
- Plan plan, PlanPhase initialPhase, String priceList, DateTime effectiveDate, DateTime effectiveDateForCancellation) {
+ private TimedMigration [] getEventsOnFuturePlanCancelMigration(Plan plan, PlanPhase initialPhase, String priceList, DateTime effectiveDate, DateTime effectiveDateForCancellation) {
TimedMigration [] result = new TimedMigration[2];
result[0] = new TimedMigration(effectiveDate, EventType.API_USER, ApiEventType.MIGRATE_ENTITLEMENT, plan, initialPhase, priceList);
result[1] = new TimedMigration(effectiveDateForCancellation, EventType.API_USER, ApiEventType.CANCEL, null, null, null);
return result;
}
+
+
+ // STEPH should be in catalog
+ private PlanPhase getPlanPhase(Plan plan, PhaseType phaseType) throws EntitlementMigrationApiException {
+ for (PlanPhase cur: plan.getAllPhases()) {
+ if (cur.getPhaseType() == phaseType) {
+ return cur;
+ }
+ }
+ throw new EntitlementMigrationApiException(String.format("Cannot find PlanPhase from Plan %s and type %s", plan.getName(), phaseType));
+ }
+
+ private boolean isRegularMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
+ return (input.length == 1 && input[0].getCancelledDate() == null);
+ }
+
+ private boolean isRegularFutureCancelledMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
+ return (input.length == 1 && input[0].getCancelledDate() != null);
+ }
+
+ private boolean isPhaseChangeMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
+ if (input.length != 2) {
+ return false;
+ }
+ return isSamePlan(input[0].getPlanPhaseSpecifer(), input[1].getPlanPhaseSpecifer());
+ }
+
+ private boolean isPlanChangeMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
+ if (input.length != 2) {
+ return false;
+ }
+ return ! isSamePlan(input[0].getPlanPhaseSpecifer(), input[1].getPlanPhaseSpecifer());
+ }
+
+ private boolean isSamePlan(PlanPhaseSpecifier plan0, PlanPhaseSpecifier plan1) {
+ if (plan0.getPriceListName().equals(plan1.getPriceListName()) &&
+ plan0.getProductName().equals(plan1.getProductName())) {
+ return true;
+ }
+ return false;
+ }
}
diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
index b847ebb..aa16ac7 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/migration/DefaultEntitlementMigrationApi.java
@@ -27,6 +27,7 @@ import org.joda.time.DateTime;
import com.google.inject.Inject;
import com.ning.billing.catalog.api.CatalogApiException;
import com.ning.billing.catalog.api.CatalogService;
+import com.ning.billing.catalog.api.Duration;
import com.ning.billing.catalog.api.PhaseType;
import com.ning.billing.catalog.api.Plan;
import com.ning.billing.catalog.api.PlanPhase;
@@ -51,6 +52,7 @@ import com.ning.billing.entitlement.events.user.ApiEventChange;
import com.ning.billing.entitlement.events.user.ApiEventMigrate;
import com.ning.billing.entitlement.exceptions.EntitlementError;
import com.ning.billing.util.clock.Clock;
+import com.ning.billing.util.clock.DefaultClock;
public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
@@ -129,86 +131,21 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
EntitlementSubscriptionMigrationCase [] input, DateTime now)
throws EntitlementMigrationApiException {
- try {
- final DateTime bundleStartDate = now;
-
- List<EntitlementEvent> emptyEvents = Collections.emptyList();
-
- SubscriptionData subscriptionData = factory.createSubscription(new SubscriptionBuilder()
+ TimedMigration [] events = migrationAligner.getEventsMigration(input, now);
+ DateTime migrationStartDate= events[0].getEventTime();
+ List<EntitlementEvent> emptyEvents = Collections.emptyList();
+ SubscriptionData subscriptionData = factory.createSubscription(new SubscriptionBuilder()
.setId(UUID.randomUUID())
.setBundleId(bundleId)
.setCategory(productCategory)
- .setBundleStartDate(bundleStartDate)
- .setStartDate(now),
+ .setBundleStartDate(migrationStartDate)
+ .setStartDate(migrationStartDate),
emptyEvents);
-
- TimedMigration [] events = null;
- Plan plan0 = catalogService.getCatalog().findPlan(input[0].getPlanPhaseSpecifer().getProductName(),
- input[0].getPlanPhaseSpecifer().getBillingPeriod(), input[0].getPlanPhaseSpecifer().getPriceListName());
-
- Plan plan1 = (input.length > 1) ? catalogService.getCatalog().findPlan(input[1].getPlanPhaseSpecifer().getProductName(),
- input[1].getPlanPhaseSpecifer().getBillingPeriod(), input[1].getPlanPhaseSpecifer().getPriceListName()) :
- null;
-
- if (isRegularMigratedSubscription(input)) {
-
- events = migrationAligner.getEventsOnRegularMigration(subscriptionData,
- plan0,
- getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
- input[0].getPlanPhaseSpecifer().getPriceListName(),
- now);
-
- } else if (isRegularFutureCancelledMigratedSubscription(input)) {
-
- events = migrationAligner.getEventsOnFuturePlanCancelMigration(subscriptionData,
- plan0,
- getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
- input[0].getPlanPhaseSpecifer().getPriceListName(),
- now,
- input[0].getCancelledDate());
-
- } else if (isPhaseChangeMigratedSubscription(input)) {
-
- events = migrationAligner.getEventsOnFuturePhaseChangeMigration(subscriptionData,
- plan0,
- getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
- input[0].getPlanPhaseSpecifer().getPriceListName(),
- now,
- input[1].getEffectiveDate());
-
- } else if (isPlanChangeMigratedSubscription(input)) {
-
- events = migrationAligner.getEventsOnFuturePlanChangeMigration(subscriptionData,
- plan0,
- getPlanPhase(plan0, input[0].getPlanPhaseSpecifer().getPhaseType()),
- plan1,
- getPlanPhase(plan1, input[1].getPlanPhaseSpecifer().getPhaseType()),
- input[0].getPlanPhaseSpecifer().getPriceListName(),
- now,
- input[1].getEffectiveDate());
-
- } else {
- throw new EntitlementMigrationApiException("Unknown migration type");
- }
- return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, events));
- } catch (CatalogApiException e) {
- throw new EntitlementMigrationApiException(e);
- }
- }
-
- // STEPH should be in catalog
- private PlanPhase getPlanPhase(Plan plan, PhaseType phaseType) throws EntitlementMigrationApiException {
- for (PlanPhase cur: plan.getAllPhases()) {
- if (cur.getPhaseType() == phaseType) {
- return cur;
- }
- }
- throw new EntitlementMigrationApiException(String.format("Cannot find PlanPhase from Plan %s and type %s", plan.getName(), phaseType));
+ return new SubscriptionMigrationData(subscriptionData, toEvents(subscriptionData, now, events));
}
private List<EntitlementEvent> toEvents(SubscriptionData subscriptionData, DateTime now, TimedMigration [] migrationEvents) {
-
List<EntitlementEvent> events = new ArrayList<EntitlementEvent>(migrationEvents.length);
for (TimedMigration cur : migrationEvents) {
@@ -248,34 +185,4 @@ public class DefaultEntitlementMigrationApi implements EntitlementMigrationApi {
}
return events;
}
-
- private boolean isRegularMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
- return (input.length == 1 && input[0].getCancelledDate() == null);
- }
-
- private boolean isRegularFutureCancelledMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
- return (input.length == 1 && input[0].getCancelledDate() != null);
- }
-
- private boolean isPhaseChangeMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
- if (input.length != 2) {
- return false;
- }
- return isSamePlan(input[0].getPlanPhaseSpecifer(), input[1].getPlanPhaseSpecifer());
- }
-
- private boolean isPlanChangeMigratedSubscription(EntitlementSubscriptionMigrationCase [] input) {
- if (input.length != 2) {
- return false;
- }
- return ! isSamePlan(input[0].getPlanPhaseSpecifer(), input[1].getPlanPhaseSpecifer());
- }
-
- private boolean isSamePlan(PlanPhaseSpecifier plan0, PlanPhaseSpecifier plan1) {
- if (plan0.getPriceListName().equals(plan1.getPriceListName()) &&
- plan0.getProductName().equals(plan1.getProductName())) {
- return true;
- }
- return false;
- }
}
diff --git a/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java b/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
index 8d61ba5..bad6a0a 100644
--- a/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
+++ b/util/src/main/java/com/ning/billing/util/clock/DefaultClock.java
@@ -42,21 +42,21 @@ public class DefaultClock implements Clock {
return input.minus(input.getMillisOfSecond());
}
- public static DateTime addDuration(DateTime input, List<Duration> durations) {
+ public static DateTime addOrRemoveDuration(DateTime input, List<Duration> durations, boolean add) {
DateTime result = input;
for (Duration cur : durations) {
switch (cur.getUnit()) {
case DAYS:
- result = result.plusDays(cur.getNumber());
+ result = add ? result.plusDays(cur.getNumber()) : result.minusDays(cur.getNumber());
break;
case MONTHS:
- result = result.plusMonths(cur.getNumber());
+ result = add ? result.plusMonths(cur.getNumber()) : result.minusMonths(cur.getNumber());
break;
case YEARS:
- result = result.plusYears(cur.getNumber());
+ result = add ? result.plusYears(cur.getNumber()) : result.minusYears(cur.getNumber());
break;
case UNLIMITED:
default:
@@ -66,9 +66,23 @@ public class DefaultClock implements Clock {
return result;
}
+ public static DateTime addDuration(DateTime input, List<Duration> durations) {
+ return addOrRemoveDuration(input, durations, true);
+ }
+
+ public static DateTime removeDuration(DateTime input, List<Duration> durations) {
+ return addOrRemoveDuration(input, durations, false);
+ }
+
public static DateTime addDuration(DateTime input, Duration duration) {
List<Duration> list = new ArrayList<Duration>();
list.add(duration);
- return addDuration(input, list);
+ return addOrRemoveDuration(input, list, true);
+ }
+
+ public static DateTime removeDuration(DateTime input, Duration duration) {
+ List<Duration> list = new ArrayList<Duration>();
+ list.add(duration);
+ return addOrRemoveDuration(input, list, false);
}
}