Skip to content

Commit

Permalink
subscription: Code review integration for d960697. See #453
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrossie committed Jan 7, 2016
1 parent b1e8838 commit 13dc8bf
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 11 deletions.
Expand Up @@ -21,8 +21,10 @@
import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDate;
import org.killbill.billing.ErrorCode;
import org.killbill.billing.account.api.Account;
import org.killbill.billing.account.api.AccountApiException;
import org.killbill.billing.api.TestApiListener.NextEvent;
Expand All @@ -45,6 +47,7 @@
import org.killbill.billing.invoice.api.Invoice;
import org.killbill.billing.invoice.api.InvoiceItemType;
import org.killbill.billing.payment.api.PluginProperty;
import org.testng.Assert;
import org.testng.annotations.Test;

import com.google.common.collect.ImmutableList;
Expand Down Expand Up @@ -246,7 +249,7 @@ public void testCreateSubscriptionWithAddOns() throws Exception {


@Test(groups = "slow")
public void testCancelFutureSubscription() throws Exception {
public void testCancelFutureSubscriptionWithPolicy() throws Exception {

final LocalDate initialDate = new LocalDate(2015, 9, 1);
clock.setDay(initialDate);
Expand All @@ -261,6 +264,7 @@ public void testCancelFutureSubscription() throws Exception {
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);
assertListenerStatus();


final Entitlement cancelledEntitlement = createdEntitlement.cancelEntitlementWithPolicyOverrideBillingPolicy(EntitlementActionPolicy.IMMEDIATE, BillingActionPolicy.IMMEDIATE, null, callContext);
Expand All @@ -271,7 +275,48 @@ public void testCancelFutureSubscription() throws Exception {
// 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();
}

@Test(groups = "slow")
public void testCancelFutureSubscriptionWithRequestedDate() 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);
assertListenerStatus();


final LocalDate invalidCancelDate = initialDate.plusDays(1);
try {
createdEntitlement.cancelEntitlementWithDate(invalidCancelDate, true, null, callContext);
Assert.fail("Should not succeed to cancel subscription prior startDate");
} catch (final EntitlementApiException e) {
assertEquals(e.getCode(), ErrorCode.SUB_INVALID_REQUESTED_DATE.getCode());
}

final Entitlement cancelledEntitlement = createdEntitlement.cancelEntitlementWithDate(futureDate, true, 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
Expand Down
Expand Up @@ -510,7 +510,7 @@ private void populateDryRunEvents(@Nullable final UUID bundleId,
dryRunArguments.getPlanPhaseSpecifier().getPriceListName(), utcNow, tenantContext);
policy = planChangeResult.getPolicy();
}
changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(subscriptionForChange.getStartDate(), policy);
changeEffectiveDate = subscriptionForChange.getPlanChangeEffectiveDate(policy);
}
dryRunEvents = apiService.getEventsOnChangePlan(subscriptionForChange, plan, realPriceList, changeEffectiveDate, utcNow, true, context);
break;
Expand All @@ -530,7 +530,7 @@ private void populateDryRunEvents(@Nullable final UUID bundleId,
subscriptionForCancellation.getCurrentPhase().getPhaseType());
policy = catalogService.getFullCatalog(context).planCancelPolicy(spec, utcNow);
}
cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(subscriptionForCancellation.getStartDate(), policy);
cancelEffectiveDate = subscriptionForCancellation.getPlanChangeEffectiveDate(policy);
}
dryRunEvents = apiService.getEventsOnCancelPlan(subscriptionForCancellation, cancelEffectiveDate, utcNow, true, context);
break;
Expand Down
Expand Up @@ -492,7 +492,7 @@ public boolean isSubscriptionFutureCancelled() {
return getFutureEndDate() != null;
}

public DateTime getPlanChangeEffectiveDate(final DateTime subscriptionStartDate, final BillingActionPolicy policy) {
public DateTime getPlanChangeEffectiveDate(final BillingActionPolicy policy) {

final DateTime candidateResult;
switch (policy) {
Expand All @@ -512,7 +512,7 @@ public DateTime getPlanChangeEffectiveDate(final DateTime subscriptionStartDate,
throw new SubscriptionBaseError(String.format(
"Unexpected policy type %s", policy.toString()));
}
return (candidateResult.compareTo(subscriptionStartDate) < 0) ? subscriptionStartDate : candidateResult;
return (candidateResult.compareTo(getStartDate()) < 0) ? getStartDate() : candidateResult;
}

public DateTime getCurrentPhaseStart() {
Expand Down
Expand Up @@ -222,7 +222,7 @@ public boolean cancel(final DefaultSubscriptionBase subscription, final CallCont
try {
final InternalTenantContext internalCallContext = createTenantContextFromBundleId(subscription.getBundleId(), context);
final BillingActionPolicy policy = catalogService.getFullCatalog(internalCallContext).planCancelPolicy(planPhase, now);
final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), policy);
final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy);

return doCancelPlan(subscription, now, effectiveDate, context);
} catch (final CatalogApiException e) {
Expand All @@ -248,7 +248,7 @@ public boolean cancelWithPolicy(final DefaultSubscriptionBase subscription, fina
throw new SubscriptionBaseApiException(ErrorCode.SUB_CANCEL_BAD_STATE, subscription.getId(), currentState);
}
final DateTime now = clock.getUTCNow();
final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), policy);
final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy);

return doCancelPlan(subscription, now, effectiveDate, context);
}
Expand Down Expand Up @@ -319,7 +319,7 @@ public DateTime changePlan(final DefaultSubscriptionBase subscription, final Str
validateEntitlementState(subscription);

final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, productName, term, priceList, now, context);
final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), planChangeResult.getPolicy());
final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(planChangeResult.getPolicy());
validateEffectiveDate(subscription, effectiveDate);

try {
Expand Down Expand Up @@ -354,7 +354,7 @@ public DateTime changePlanWithPolicy(final DefaultSubscriptionBase subscription,

validateEntitlementState(subscription);

final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(subscription.getStartDate(), policy);
final DateTime effectiveDate = subscription.getPlanChangeEffectiveDate(policy);
try {
return doChangePlan(subscription, productName, term, priceList, overrides, now, effectiveDate, context);
} catch (final CatalogApiException e) {
Expand Down Expand Up @@ -548,10 +548,14 @@ private List<DefaultSubscriptionBase> addCancellationAddOnForEventsIfRequired(fi
}

private void validateEffectiveDate(final DefaultSubscriptionBase subscription, final DateTime effectiveDate) throws SubscriptionBaseApiException {

final SubscriptionBaseTransition previousTransition = subscription.getPreviousTransition();
if (previousTransition != null && previousTransition.getEffectiveTransitionTime().isAfter(effectiveDate)) {

// Our effectiveDate must be after or equal the last transition that already occured (START, PHASE1, PHASE2,...) or the startDate for future started subscription
final DateTime earliestValidDate = previousTransition != null ? previousTransition.getEffectiveTransitionTime() : subscription.getStartDate();
if (effectiveDate.isBefore(earliestValidDate)) {
throw new SubscriptionBaseApiException(ErrorCode.SUB_INVALID_REQUESTED_DATE,
effectiveDate.toString(), previousTransition.getEffectiveTransitionTime());
effectiveDate.toString(), previousTransition != null ? previousTransition.getEffectiveTransitionTime() : "null");
}
}

Expand Down

0 comments on commit 13dc8bf

Please sign in to comment.