use of org.killbill.billing.catalog.api.BillingPeriod in project killbill by killbill.
the class DefaultSubscriptionBase method getEffectiveDateForPolicy.
public DateTime getEffectiveDateForPolicy(final BillingActionPolicy policy, @Nullable final BillingAlignment alignment, @Nullable final Integer accountBillCycleDayLocal, final InternalTenantContext context) {
final DateTime candidateResult;
switch(policy) {
case IMMEDIATE:
candidateResult = clock.getUTCNow();
break;
case START_OF_TERM:
if (chargedThroughDate == null) {
candidateResult = getStartDate();
// Will take care of billing IN_ARREAR or subscriptions that are not invoiced up to date
} else if (!chargedThroughDate.isAfter(clock.getUTCNow())) {
candidateResult = chargedThroughDate;
} else {
// In certain path (dryRun, or default catalog START_OF_TERM policy), the info is not easily available and as a result, such policy is not implemented
Preconditions.checkState(alignment != null && context != null && accountBillCycleDayLocal != null, "START_OF_TERM not implemented in dryRun use case");
Preconditions.checkState(alignment != BillingAlignment.BUNDLE || category != ProductCategory.ADD_ON, "START_OF_TERM not implemented for AO configured with a BUNDLE billing alignment");
// If BCD was overriden at the subscription level, we take its latest value (it should also be reflected in the chargedThroughDate) but still required for
// alignment purpose
Integer bcd = getBillCycleDayLocal();
if (bcd == null) {
bcd = BillCycleDayCalculator.calculateBcdForAlignment(null, this, this, alignment, context, accountBillCycleDayLocal);
}
final BillingPeriod billingPeriod = getLastActivePlan().getRecurringBillingPeriod();
DateTime proposedDate = chargedThroughDate;
while (proposedDate.isAfter(clock.getUTCNow())) {
proposedDate = proposedDate.minus(billingPeriod.getPeriod());
}
final LocalDate resultingLocalDate = BillCycleDayCalculator.alignProposedBillCycleDate(proposedDate, bcd, billingPeriod, context);
candidateResult = context.toUTCDateTime(resultingLocalDate);
}
break;
case END_OF_TERM:
//
// If we have a chargedThroughDate that is 'up to date' we use it, if not default to now
// chargedThroughDate could exist and be less than now if:
// 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
//
candidateResult = (chargedThroughDate != null && chargedThroughDate.isAfter(clock.getUTCNow())) ? chargedThroughDate : clock.getUTCNow();
break;
default:
throw new SubscriptionBaseError(String.format("Unexpected policy type %s", policy.toString()));
}
// Finally we verify we won't cancel prior the beginning of our current PHASE -- mostly as a sanity or for test stability
final DateTime lastTransitionTime = getCurrentPhaseStart();
return (candidateResult.compareTo(lastTransitionTime) < 0) ? lastTransitionTime : candidateResult;
}
use of org.killbill.billing.catalog.api.BillingPeriod in project killbill by killbill.
the class TestTransfer method testTransferBPNoTrialWithCTD.
@Test(groups = "slow")
public void testTransferBPNoTrialWithCTD() throws Exception {
final String baseProduct = "Shotgun";
final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
// CREATE BP
final SubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
// MOVE AFTER TRIAL
testListener.pushExpectedEvent(NextEvent.PHASE);
clock.addDays(40);
assertListenerStatus();
// SET CTD
final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
final DateTime transferRequestedDate = clock.getUTCNow();
testListener.pushExpectedEvent(NextEvent.TRANSFER);
transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, false, false, callContext);
assertListenerStatus();
// CHECK OLD BASE IS CANCEL AT THE TRANSFER DATE
final SubscriptionBase oldBaseSubscription = subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
assertNotNull(oldBaseSubscription.getFutureEndDate());
assertTrue(oldBaseSubscription.getFutureEndDate().compareTo(ctd) == 0);
// CHECK NEW BUNDLE EXIST, WITH ONE SUBSCRIPTION STARTING ON TRANSFER_DATE
final List<SubscriptionBaseBundle> bundlesForAccountAndKey = subscriptionInternalApi.getBundlesForAccountAndKey(newAccountId, bundle.getExternalKey(), internalCallContext);
assertEquals(bundlesForAccountAndKey.size(), 1);
final SubscriptionBaseBundle newBundle = bundlesForAccountAndKey.get(0);
final List<SubscriptionBase> subscriptions = subscriptionInternalApi.getSubscriptionsForBundle(newBundle.getId(), null, internalCallContext);
assertEquals(subscriptions.size(), 1);
final SubscriptionBase newBaseSubscription = subscriptions.get(0);
assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) baseSubscription).getAlignStartDate()) == 0);
// CHECK ONLY ONE PHASE EXISTS
assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 1);
Plan newPlan = newBaseSubscription.getCurrentPlan();
assertEquals(newPlan.getProduct().getName(), baseProduct);
assertEquals(newBaseSubscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
// MAKE A PLAN CHANGE IMM
clock.addDays(5);
final String newBaseProduct1 = "Assault-Rifle";
final BillingPeriod newBaseTerm1 = BillingPeriod.ANNUAL;
testListener.pushExpectedEvent(NextEvent.CHANGE);
final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(newBaseProduct1, newBaseTerm1, basePriceList);
newBaseSubscription.changePlan(new DefaultEntitlementSpecifier(planPhaseSpecifier, null, null, null), callContext);
assertListenerStatus();
newPlan = newBaseSubscription.getCurrentPlan();
assertEquals(newPlan.getProduct().getName(), newBaseProduct1);
assertEquals(newBaseSubscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
// SET CTD AND MAKE CHANGE EOT
clock.addDays(2);
final DateTime newCtd = newBaseSubscription.getStartDate().plusYears(1);
setChargedThroughDate(newBaseSubscription.getId(), newCtd, internalCallContext);
final SubscriptionBase newBaseSubscriptionWithCtd = subscriptionInternalApi.getSubscriptionFromId(newBaseSubscription.getId(), internalCallContext);
final String newBaseProduct2 = "Pistol";
final BillingPeriod newBaseTerm2 = BillingPeriod.ANNUAL;
final PlanPhaseSpecifier planPhaseSpecifier1 = new PlanPhaseSpecifier(newBaseProduct2, newBaseTerm2, basePriceList);
newBaseSubscriptionWithCtd.changePlan(new DefaultEntitlementSpecifier(planPhaseSpecifier1, null, null, null), callContext);
newPlan = newBaseSubscriptionWithCtd.getCurrentPlan();
assertEquals(newPlan.getProduct().getName(), newBaseProduct1);
assertEquals(newBaseSubscriptionWithCtd.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
assertNotNull(newBaseSubscriptionWithCtd.getPendingTransition());
assertEquals(newBaseSubscriptionWithCtd.getPendingTransition().getEffectiveTransitionTime(), newCtd);
}
use of org.killbill.billing.catalog.api.BillingPeriod in project killbill by killbill.
the class TestTransfer method testTransferWithUncancel.
@Test(groups = "slow")
public void testTransferWithUncancel() throws Exception {
final String baseProduct = "Shotgun";
final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
// CREATE BP
SubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
testListener.pushExpectedEvent(NextEvent.PHASE);
clock.addDays(30);
assertListenerStatus();
// SET CTD TO TRIGGER CANCELLATION EOT
final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
// CANCEL BP
baseSubscription = subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
baseSubscription.cancel(callContext);
// MOVE CLOCK one day AHEAD AND UNCANCEL BP
clock.addDays(1);
testListener.pushExpectedEvent(NextEvent.UNCANCEL);
baseSubscription.uncancel(callContext);
assertListenerStatus();
// MOVE CLOCK one day AHEAD AND UNCANCEL BP
clock.addDays(1);
final DateTime transferRequestedDate = clock.getUTCNow();
testListener.pushExpectedEvent(NextEvent.TRANSFER);
transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, true, false, callContext);
assertListenerStatus();
final List<SubscriptionBaseBundle> bundlesForAccountAndKey = subscriptionInternalApi.getBundlesForAccountAndKey(newAccountId, bundle.getExternalKey(), internalCallContext);
assertEquals(bundlesForAccountAndKey.size(), 1);
final SubscriptionBaseBundle newBundle = bundlesForAccountAndKey.get(0);
final List<SubscriptionBase> subscriptions = subscriptionInternalApi.getSubscriptionsForBundle(newBundle.getId(), null, internalCallContext);
assertEquals(subscriptions.size(), 1);
}
use of org.killbill.billing.catalog.api.BillingPeriod in project killbill by killbill.
the class TestTransfer method testTransferBPInTrialWithNoCTD.
@Test(groups = "slow")
public void testTransferBPInTrialWithNoCTD() throws Exception {
final String baseProduct = "Shotgun";
final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
// CREATE BP
final SubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
final DateTime evergreenPhaseDate = ((DefaultSubscriptionBase) baseSubscription).getPendingTransition().getEffectiveTransitionTime();
// MOVE A LITTLE, STILL IN TRIAL
clock.addDays(20);
final DateTime beforeTransferDate = clock.getUTCNow();
final DateTime transferRequestedDate = clock.getUTCNow();
testListener.pushExpectedEvent(NextEvent.TRANSFER);
testListener.pushExpectedEvent(NextEvent.CANCEL);
transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, false, false, callContext);
assertListenerStatus();
final DateTime afterTransferDate = clock.getUTCNow();
// CHECK OLD BASE IS CANCEL AT THE TRANSFER DATE
final SubscriptionBase oldBaseSubscription = subscriptionInternalApi.getSubscriptionFromId(baseSubscription.getId(), internalCallContext);
assertNotNull(oldBaseSubscription.getEndDate());
testUtil.assertDateWithin(oldBaseSubscription.getEndDate(), beforeTransferDate, afterTransferDate);
assertTrue(oldBaseSubscription.getEndDate().compareTo(transferRequestedDate) == 0);
// CHECK NEW BUNDLE EXIST, WITH ONE SUBSCRIPTION STARTING ON TRANSFER_DATE
final List<SubscriptionBaseBundle> bundlesForAccountAndKey = subscriptionInternalApi.getBundlesForAccountAndKey(newAccountId, bundle.getExternalKey(), internalCallContext);
assertEquals(bundlesForAccountAndKey.size(), 1);
final SubscriptionBaseBundle newBundle = bundlesForAccountAndKey.get(0);
final List<SubscriptionBase> subscriptions = subscriptionInternalApi.getSubscriptionsForBundle(newBundle.getId(), null, internalCallContext);
assertEquals(subscriptions.size(), 1);
final SubscriptionBase newBaseSubscription = subscriptions.get(0);
assertTrue(((DefaultSubscriptionBase) newBaseSubscription).getAlignStartDate().compareTo(((DefaultSubscriptionBase) oldBaseSubscription).getAlignStartDate()) == 0);
// CHECK NEXT PENDING PHASE IS ALIGNED WITH OLD SUBSCRIPTION START DATE
assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 2);
assertTrue(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).get(1).getEffectiveTransitionTime().compareTo(evergreenPhaseDate) == 0);
final Plan newPlan = newBaseSubscription.getCurrentPlan();
assertEquals(newPlan.getProduct().getName(), baseProduct);
assertEquals(newBaseSubscription.getCurrentPhase().getPhaseType(), PhaseType.TRIAL);
}
use of org.killbill.billing.catalog.api.BillingPeriod in project killbill by killbill.
the class TestUserApiAddOn method testAddonCreateInternal.
private void testAddonCreateInternal(final String aoProduct, final BillingPeriod aoTerm, final String aoPriceList, final PlanAlignmentCreate expAlignement) throws SubscriptionBaseApiException {
final String baseProduct = "Shotgun";
final BillingPeriod baseTerm = BillingPeriod.MONTHLY;
final String basePriceList = PriceListSet.DEFAULT_PRICELIST_NAME;
// CREATE BP
final DefaultSubscriptionBase baseSubscription = testUtil.createSubscription(bundle, baseProduct, baseTerm, basePriceList);
// MOVE CLOCK 14 DAYS LATER
Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(14));
clock.addDeltaFromReality(it.toDurationMillis());
// CREATE ADDON
final DateTime beforeAOCreation = clock.getUTCNow();
DefaultSubscriptionBase aoSubscription = testUtil.createSubscription(bundle, aoProduct, aoTerm, aoPriceList);
final DateTime afterAOCreation = clock.getUTCNow();
// CHECK EVERYTHING
Plan aoCurrentPlan = aoSubscription.getCurrentPlan();
assertNotNull(aoCurrentPlan);
assertEquals(aoCurrentPlan.getProduct().getName(), aoProduct);
assertEquals(aoCurrentPlan.getProduct().getCategory(), ProductCategory.ADD_ON);
assertEquals(aoCurrentPlan.getRecurringBillingPeriod(), aoTerm);
PlanPhase aoCurrentPhase = aoSubscription.getCurrentPhase();
assertNotNull(aoCurrentPhase);
assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.DISCOUNT);
testUtil.assertDateWithin(aoSubscription.getStartDate(), beforeAOCreation, afterAOCreation);
assertEquals(aoSubscription.getBundleStartDate().compareTo(baseSubscription.getBundleStartDate()), 0);
// CHECK next AO PHASE EVENT IS INDEED A MONTH AFTER BP STARTED => BUNDLE ALIGNMENT
SubscriptionBaseTransition aoPendingTranstion = aoSubscription.getPendingTransition();
if (expAlignement == PlanAlignmentCreate.START_OF_BUNDLE) {
assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), baseSubscription.getStartDate().plusMonths(1));
} else {
assertEquals(aoPendingTranstion.getEffectiveTransitionTime(), aoSubscription.getStartDate().plusMonths(1));
}
// ADD TWO PHASE EVENTS (BP + AO)
testListener.pushExpectedEvent(NextEvent.PHASE);
testListener.pushExpectedEvent(NextEvent.PHASE);
// MOVE THROUGH TIME TO GO INTO EVERGREEN
it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(33));
clock.addDeltaFromReality(it.toDurationMillis());
assertListenerStatus();
// CHECK EVERYTHING AGAIN
aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
aoCurrentPlan = aoSubscription.getCurrentPlan();
assertNotNull(aoCurrentPlan);
assertEquals(aoCurrentPlan.getProduct().getName(), aoProduct);
assertEquals(aoCurrentPlan.getProduct().getCategory(), ProductCategory.ADD_ON);
assertEquals(aoCurrentPlan.getRecurringBillingPeriod(), aoTerm);
aoCurrentPhase = aoSubscription.getCurrentPhase();
assertNotNull(aoCurrentPhase);
assertEquals(aoCurrentPhase.getPhaseType(), PhaseType.EVERGREEN);
aoSubscription = (DefaultSubscriptionBase) subscriptionInternalApi.getSubscriptionFromId(aoSubscription.getId(), internalCallContext);
aoPendingTranstion = aoSubscription.getPendingTransition();
assertNull(aoPendingTranstion);
assertListenerStatus();
}
Aggregations