killbill-memoizeit

entitlement: fix issue with EntitlementDateHelper Make

10/18/2013 10:34:02 AM

Details

diff --git a/entitlement/src/main/java/com/ning/billing/entitlement/api/EntitlementDateHelper.java b/entitlement/src/main/java/com/ning/billing/entitlement/api/EntitlementDateHelper.java
index e15ee06..744dc65 100644
--- a/entitlement/src/main/java/com/ning/billing/entitlement/api/EntitlementDateHelper.java
+++ b/entitlement/src/main/java/com/ning/billing/entitlement/api/EntitlementDateHelper.java
@@ -22,9 +22,9 @@ import org.joda.time.LocalDate;
 
 import com.ning.billing.account.api.Account;
 import com.ning.billing.account.api.AccountApiException;
-import com.ning.billing.clock.Clock;
-import com.ning.billing.callcontext.InternalTenantContext;
 import com.ning.billing.account.api.AccountInternalApi;
+import com.ning.billing.callcontext.InternalTenantContext;
+import com.ning.billing.clock.Clock;
 
 public class EntitlementDateHelper {
 
@@ -52,7 +52,6 @@ public class EntitlementDateHelper {
 
     public DateTime fromLocalDateAndReferenceTime(final LocalDate requestedDate, final DateTime referenceDateTime, final InternalTenantContext callContext) throws EntitlementApiException {
         try {
-
             final Account account = accountApi.getAccountByRecordId(callContext.getAccountRecordId(), callContext);
             return fromLocalDateAndReferenceTime(requestedDate, referenceDateTime, account.getTimeZone());
         } catch (AccountApiException e) {
@@ -74,10 +73,13 @@ public class EntitlementDateHelper {
         return adjustDateTimeToNotBeInFutureIfLocaDateIsToday(t2, accountTimeZone);
     }
 
-    private final DateTime adjustDateTimeToNotBeInFutureIfLocaDateIsToday(final DateTime inputUtc, final DateTimeZone accountTimeZone) {
+    private DateTime adjustDateTimeToNotBeInFutureIfLocaDateIsToday(final DateTime inputUtc, final DateTimeZone accountTimeZone) {
         // If the LocalDate is TODAY but after adding the reference time we end up in the future, we correct it to be NOW,
-        // so change occurs immediately
-        if (isBeforeOrEqualsToday(inputUtc, accountTimeZone) && inputUtc.compareTo(clock.getUTCNow()) > 0) {
+        // so change occurs immediately.
+        // If the LocalDate is TODAY but after adding the reference time we end up in the past, we also correct it to NOW,
+        // so we don't end up having events between this time and NOW.
+        // Note that in both these cases, we won't respect the reference time.
+        if (isEqualsToday(inputUtc, accountTimeZone)) {
             return clock.getUTCNow();
         } else {
             return inputUtc;
@@ -85,13 +87,27 @@ public class EntitlementDateHelper {
     }
 
     /**
+     * Check if the date portion of a date/time is equals at today (as returned by the clock).
+     *
+     * @param inputDate       the fully qualified DateTime
+     * @param accountTimeZone the account timezone
+     * @return true if the inputDate, once converted into a LocalDate using account timezone is equals at today
+     */
+    private boolean isEqualsToday(final DateTime inputDate, final DateTimeZone accountTimeZone) {
+        final LocalDate localDateNowInAccountTimezone = new LocalDate(clock.getUTCNow(), accountTimeZone);
+        final LocalDate targetDateInAccountTimezone = new LocalDate(inputDate, accountTimeZone);
+
+        return targetDateInAccountTimezone.compareTo(localDateNowInAccountTimezone) == 0;
+    }
+
+    /**
+     * Check if the date portion of a date/time is before or equals at now (as returned by the clock).
      *
      * @param inputDate       the fully qualified DateTime
      * @param accountTimeZone the account timezone
      * @return true if the inputDate, once converted into a LocalDate using account timezone is less or equals than today
      */
     public boolean isBeforeOrEqualsToday(final DateTime inputDate, final DateTimeZone accountTimeZone) {
-
         final LocalDate localDateNowInAccountTimezone = new LocalDate(clock.getUTCNow(), accountTimeZone);
         final LocalDate targetDateInAccountTimezone = new LocalDate(inputDate, accountTimeZone);
 
diff --git a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlement.java b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlement.java
index faee74d..56e62ee 100644
--- a/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlement.java
+++ b/entitlement/src/test/java/com/ning/billing/entitlement/api/TestDefaultEntitlement.java
@@ -165,4 +165,31 @@ public class TestDefaultEntitlement extends EntitlementTestSuiteWithEmbeddedDB {
         assertEquals(entitlement4.getState(), EntitlementState.CANCELLED);
         assertEquals(entitlement4.getEffectiveEndDate(), new LocalDate(ctd));
     }
+
+    @Test(groups = "slow")
+    public void testCancelWithEntitlementPolicyEOTNoCTDAndImmediateChange() throws AccountApiException, EntitlementApiException, SubscriptionApiException, InterruptedException {
+        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);
+
+        // Create entitlement and check each field
+        final Entitlement entitlement = entitlementApi.createBaseEntitlement(account.getId(), spec, account.getExternalKey(), initialDate, callContext);
+
+        // Immediate change during trial
+        entitlement.changePlan("Assault-Rifle", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME, callContext);
+        // Verify the change is immediate
+        final Entitlement entitlement2 = entitlementApi.getEntitlementForId(entitlement.getId(), callContext);
+        assertEquals(entitlement2.getLastActivePhase().getPlan().getProduct().getName(), "Assault-Rifle");
+
+        final Entitlement cancelledEntitlement = entitlement.cancelEntitlementWithPolicy(EntitlementActionPolicy.END_OF_TERM, callContext);
+        assertEquals(cancelledEntitlement.getState(), EntitlementState.CANCELLED);
+        assertEquals(cancelledEntitlement.getEffectiveEndDate(), initialDate);
+
+        // Entitlement started in trial on 2013-08-07, which is when we want the billing cancellation date to occur
+        final Subscription subscription = subscriptionApi.getSubscriptionForEntitlementId(entitlement.getBaseEntitlementId(), callContext);
+        assertEquals(subscription.getBillingEndDate().compareTo(new LocalDate(2013, 8, 7)), 0, "Unexpected billing end date: " + subscription.getBillingEndDate());
+    }
 }