use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class DefaultSubscriptionBaseCreateApi method verifyAndBuildSubscriptionSpecifiers.
private List<SubscriptionSpecifier> verifyAndBuildSubscriptionSpecifiers(final SubscriptionBaseBundle bundle, final boolean hasBaseOrStandalonePlanSpecifier, final List<EntitlementSpecifier> entitlements, final List<Plan> entitlementsPlans, final boolean isMigrated, final DateTime effectiveDate, final SubscriptionCatalog catalog, final AddonUtils addonUtils, final TenantContext callContext, final InternalCallContext context) throws SubscriptionBaseApiException, CatalogApiException {
final List<SubscriptionSpecifier> subscriptions = new ArrayList<SubscriptionSpecifier>();
for (int i = 0; i < entitlements.size(); i++) {
final EntitlementSpecifier entitlement = entitlements.get(i);
final PlanPhaseSpecifier spec = entitlement.getPlanPhaseSpecifier();
if (spec == null) {
// BP already exists
continue;
}
final Plan plan = entitlementsPlans.get(i);
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", spec.getProductName(), spec.getBillingPeriod().toString(), plan.getPriceList()));
}
// verify the number of subscriptions (of the same kind) allowed per bundle and the existing ones
if (ProductCategory.ADD_ON.toString().equalsIgnoreCase(plan.getProduct().getCategory().toString())) {
if (plan.getPlansAllowedInBundle() != -1 && plan.getPlansAllowedInBundle() > 0) {
// TODO We should also look to the specifiers being created for validation
final List<DefaultSubscriptionBase> subscriptionsForBundle = getSubscriptionsForBundle(bundle.getId(), null, catalog, addonUtils, callContext, context);
final int existingAddOnsWithSamePlanName = addonUtils.countExistingAddOnsWithSamePlanName(subscriptionsForBundle, plan.getName());
final int currentAddOnsWithSamePlanName = countCurrentAddOnsWithSamePlanName(entitlementsPlans, plan);
if ((existingAddOnsWithSamePlanName + currentAddOnsWithSamePlanName) > plan.getPlansAllowedInBundle()) {
// a new ADD_ON subscription of the same plan can't be added because it has reached its limit by bundle
throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_AO_MAX_PLAN_ALLOWED_BY_BUNDLE, plan.getName());
}
}
}
final DateTime bundleStartDate;
if (hasBaseOrStandalonePlanSpecifier) {
bundleStartDate = effectiveDate;
} else {
final SubscriptionBase baseSubscription = dao.getBaseSubscription(bundle.getId(), catalog, context);
bundleStartDate = getBundleStartDateWithSanity(bundle.getId(), baseSubscription, plan, effectiveDate, addonUtils, context);
}
final SubscriptionSpecifier subscription = new SubscriptionSpecifier();
subscription.setRealPriceList(plan.getPriceList().getName());
subscription.setEffectiveDate(effectiveDate);
subscription.setProcessedDate(context.getCreatedDate());
subscription.setPlan(plan);
subscription.setInitialPhase(spec.getPhaseType());
subscription.setBuilder(new SubscriptionBuilder().setId(UUIDs.randomUUID()).setBundleId(bundle.getId()).setExternalKey(entitlement.getExternalKey()).setBundleExternalKey(bundle.getExternalKey()).setCategory(plan.getProduct().getCategory()).setBundleStartDate(bundleStartDate).setAlignStartDate(effectiveDate).setMigrated(isMigrated).setSubscriptionBCD(entitlement.getBillCycleDay()));
subscriptions.add(subscription);
}
return subscriptions;
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class TestBillCycleDayCalculator method verifyBCDCalculation.
private void verifyBCDCalculation(final DateTimeZone accountTimeZone, final DateTime startDateUTC, final int bcdLocal) throws AccountApiException, CatalogApiException {
final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
Mockito.when(subscription.getStartDate()).thenReturn(startDateUTC);
Mockito.when(subscription.getDateOfFirstRecurringNonZeroCharge()).thenReturn(startDateUTC);
final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
final Integer bcd = BillCycleDayCalculator.calculateBcdForAlignment(new HashMap<UUID, Integer>(), subscription, subscription, BillingAlignment.SUBSCRIPTION, internalCallContext, 0);
Assert.assertEquals(bcd, (Integer) bcdLocal);
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class TestBillCycleDayCalculator method testCalculateBCDForAOWithBPCancelledBundleAligned.
@Test(groups = "fast")
public void testCalculateBCDForAOWithBPCancelledBundleAligned() throws Exception {
final DateTimeZone accountTimeZone = DateTimeZone.UTC;
final DateTime bpStartDateUTC = new DateTime(2012, 7, 16, 21, 0, 0, DateTimeZone.UTC);
final int expectedBCDUTC = 16;
// Create a Bundle associated with a subscription
final SubscriptionBaseBundle bundle = Mockito.mock(SubscriptionBaseBundle.class);
final SubscriptionBase subscription = Mockito.mock(SubscriptionBase.class);
Mockito.when(subscription.getStartDate()).thenReturn(bpStartDateUTC);
// Create a the base plan associated with that subscription
final Plan plan = Mockito.mock(Plan.class);
Mockito.when(subscription.getLastActivePlan()).thenReturn(plan);
Mockito.when(subscription.getDateOfFirstRecurringNonZeroCharge()).thenReturn(bpStartDateUTC);
final ImmutableAccountData account = Mockito.mock(ImmutableAccountData.class);
Mockito.when(account.getTimeZone()).thenReturn(accountTimeZone);
final Integer billCycleDayLocal = BillCycleDayCalculator.calculateBcdForAlignment(new HashMap<UUID, Integer>(), subscription, subscription, BillingAlignment.BUNDLE, internalCallContext, 0);
Assert.assertEquals(billCycleDayLocal, (Integer) expectedBCDUTC);
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class TestOverdueWithSubscriptionCancellation method testCheckSubscriptionCancellation.
@Test(groups = "slow", retryAnalyzer = FlakyRetryAnalyzer.class)
public void testCheckSubscriptionCancellation() throws Exception {
clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
setupAccount();
// Set next invoice to fail and create subscription
paymentPlugin.makeAllInvoicesFailWithError(true);
final DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", productName, ProductCategory.BASE, term, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
bundle = subscriptionApi.getSubscriptionBundle(baseEntitlement.getBundleId(), callContext);
invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 5, 1), callContext);
final DefaultEntitlement addOn1 = addAOEntitlementAndCheckForCompletion(baseEntitlement.getBundleId(), "Holster", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
final DefaultEntitlement addOn2 = addAOEntitlementAndCheckForCompletion(baseEntitlement.getBundleId(), "Holster", ProductCategory.ADD_ON, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
// Cancel addOn1 one day after
clock.addDays(1);
cancelEntitlementAndCheckForCompletion(addOn1, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.NULL_INVOICE);
// DAY 30 have to get out of trial before first payment
addDaysAndCheckForCompletion(29, NextEvent.PHASE, NextEvent.PHASE, NextEvent.NULL_INVOICE, NextEvent.INVOICE, NextEvent.PAYMENT_ERROR, NextEvent.INVOICE_PAYMENT_ERROR);
invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 6, 30), callContext);
// Should still be in clear state
checkODState(OverdueWrapper.CLEAR_STATE_NAME);
// DAY 36 -- RIGHT AFTER OD1 (two block events, for the cancellation and the OD1 state)
// One BLOCK event is for the overdue state transition
// The 2 other BLOCK are for the entitlement blocking states for both base plan and addOn2
addDaysAndCheckForCompletion(6, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.BLOCK, NextEvent.CANCEL, NextEvent.CANCEL, NextEvent.INVOICE, NextEvent.INVOICE_ADJUSTMENT);
// Should be in OD1
checkODState("OD1");
final SubscriptionBase cancelledBaseSubscription = ((DefaultEntitlement) entitlementApi.getEntitlementForId(baseEntitlement.getId(), callContext)).getSubscriptionBase();
assertTrue(cancelledBaseSubscription.getState() == EntitlementState.CANCELLED);
final SubscriptionBase cancelledAddon1 = ((DefaultEntitlement) entitlementApi.getEntitlementForId(addOn1.getId(), callContext)).getSubscriptionBase();
assertTrue(cancelledAddon1.getState() == EntitlementState.CANCELLED);
}
use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.
the class InvoiceChecker method checkChargedThroughDate.
public void checkChargedThroughDate(final UUID entitlementId, final LocalDate expectedLocalCTD, final CallContext context) {
try {
final DefaultEntitlement entitlement = (DefaultEntitlement) entitlementApi.getEntitlementForId(entitlementId, context);
final SubscriptionBase subscription = entitlement.getSubscriptionBase();
if (expectedLocalCTD == null) {
assertNull(subscription.getChargedThroughDate());
} else {
final String msg = String.format("Checking CTD for entitlement %s : expectedLocalCTD = %s, got %s", entitlementId, expectedLocalCTD, subscription.getChargedThroughDate().toLocalDate());
assertTrue(expectedLocalCTD.compareTo(subscription.getChargedThroughDate().toLocalDate()) == 0, msg);
}
} catch (final EntitlementApiException e) {
fail("Failed to retrieve entitlement for " + entitlementId);
}
}
Aggregations