Search in sources :

Example 51 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class TestTransfer method testTransferBPInTrialWithCTD.

@Test(groups = "slow")
public void testTransferBPInTrialWithCTD() 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 ctd = baseSubscription.getStartDate().plusDays(30);
    setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
    final DateTime evergreenPhaseDate = ((DefaultSubscriptionBase) baseSubscription).getPendingTransition().getEffectiveTransitionTime();
    // MOVE A LITTLE, STILL IN TRIAL
    clock.addDays(20);
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    final DateTime transferRequestedDate = clock.getUTCNow();
    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) 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);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 52 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class TestTransfer method testTransferWithAO.

@Test(groups = "slow")
public void testTransferWithAO() 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 3 DAYS AND CREATE AO1
    clock.addDays(3);
    final String aoProduct1 = "Telescopic-Scope";
    final BillingPeriod aoTerm1 = BillingPeriod.MONTHLY;
    final DefaultSubscriptionBase aoSubscription1 = testUtil.createSubscription(bundle, aoProduct1, aoTerm1, basePriceList);
    assertEquals(aoSubscription1.getState(), EntitlementState.ACTIVE);
    // MOVE ANOTHER 25 DAYS AND CREATE AO2 [ BP STILL IN TRIAL]
    // LASER-SCOPE IS SUBSCRIPTION ALIGN SO EVERGREN WILL ONLY START IN A MONTH
    clock.addDays(25);
    final String aoProduct2 = "Laser-Scope";
    final BillingPeriod aoTerm2 = BillingPeriod.MONTHLY;
    final DefaultSubscriptionBase aoSubscription2 = testUtil.createSubscription(bundle, aoProduct2, aoTerm2, basePriceList);
    assertEquals(aoSubscription2.getState(), EntitlementState.ACTIVE);
    // MOVE AFTER TRIAL AND AO DISCOUNT PHASE [LASER SCOPE STILL IN DISCOUNT]
    testListener.pushExpectedEvent(NextEvent.PHASE);
    testListener.pushExpectedEvent(NextEvent.PHASE);
    clock.addDays(5);
    assertListenerStatus();
    // SET CTD TO TRIGGER CANCELLATION EOT
    final DateTime ctd = baseSubscription.getStartDate().plusDays(30).plusMonths(1);
    setChargedThroughDate(baseSubscription.getId(), ctd, internalCallContext);
    final DateTime transferRequestedDate = clock.getUTCNow();
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    transferApi.transferBundle(bundle.getAccountId(), newAccountId, bundle.getExternalKey(), transferRequestedDate, true, false, callContext);
    assertListenerStatus();
    // RETRIEVE NEW BUNDLE AND CHECK SUBSCRIPTIONS
    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(), 3);
    boolean foundBP = false;
    boolean foundAO1 = false;
    boolean foundAO2 = false;
    for (final SubscriptionBase cur : subscriptions) {
        final Plan curPlan = cur.getCurrentPlan();
        final Product curProduct = curPlan.getProduct();
        if (curProduct.getName().equals(baseProduct)) {
            foundBP = true;
            assertTrue(((DefaultSubscriptionBase) cur).getAlignStartDate().compareTo(((DefaultSubscriptionBase) baseSubscription).getAlignStartDate()) == 0);
            assertNull(cur.getPendingTransition());
        } else if (curProduct.getName().equals(aoProduct1)) {
            foundAO1 = true;
            assertTrue(((DefaultSubscriptionBase) cur).getAlignStartDate().compareTo((aoSubscription1).getAlignStartDate()) == 0);
            assertNull(cur.getPendingTransition());
        } else if (curProduct.getName().equals(aoProduct2)) {
            foundAO2 = true;
            assertTrue(((DefaultSubscriptionBase) cur).getAlignStartDate().compareTo((aoSubscription2).getAlignStartDate()) == 0);
            assertNotNull(cur.getPendingTransition());
        } else {
            Assert.fail("Unexpected product " + curProduct.getName());
        }
    }
    assertTrue(foundBP);
    assertTrue(foundAO1);
    assertTrue(foundAO2);
    // MOVE AFTER CANCEL DATE TO TRIGGER OLD SUBSCRIPTIONS CANCELLATION + LASER_SCOPE PHASE EVENT
    testListener.pushExpectedEvents(NextEvent.PHASE, NextEvent.PHASE);
    testListener.pushExpectedEvent(NextEvent.CANCEL);
    testListener.pushExpectedEvent(NextEvent.CANCEL);
    testListener.pushExpectedEvent(NextEvent.CANCEL);
    clock.addMonths(1);
    assertListenerStatus();
    // ISSUE ANOTHER TRANSFER TO CHECK THAT WE CAN TRANSFER AGAIN-- NOTE WILL NOT WORK ON PREVIOUS ACCOUNT (LIMITATION)
    final DateTime newTransferRequestedDate = clock.getUTCNow();
    testListener.pushExpectedEvent(NextEvent.CANCEL);
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    testListener.pushExpectedEvent(NextEvent.TRANSFER);
    transferApi.transferBundle(newBundle.getAccountId(), finalNewAccountId, newBundle.getExternalKey(), newTransferRequestedDate, true, false, callContext);
    assertListenerStatus();
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) Product(org.killbill.billing.catalog.api.Product) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 53 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class TestTransfer method testTransferBPNoTrialWithNoCTD.

@Test(groups = "slow")
public void testTransferBPNoTrialWithNoCTD() 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();
    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) baseSubscription).getAlignStartDate()) == 0);
    // CHECK ONLY ONE PHASE EXISTS
    assertEquals(subscriptionInternalApi.getAllTransitions(newBaseSubscription, internalCallContext).size(), 1);
    final Plan newPlan = newBaseSubscription.getCurrentPlan();
    assertEquals(newPlan.getProduct().getName(), baseProduct);
    assertEquals(newBaseSubscription.getCurrentPhase().getPhaseType(), PhaseType.EVERGREEN);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) BillingPeriod(org.killbill.billing.catalog.api.BillingPeriod) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) Plan(org.killbill.billing.catalog.api.Plan) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 54 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class DefaultSubscriptionInternalApi method createBundleForAccount.

@Override
public SubscriptionBaseBundle createBundleForAccount(final UUID accountId, final String bundleKey, final InternalCallContext context) throws SubscriptionBaseApiException {
    final List<SubscriptionBaseBundle> existingBundles = dao.getSubscriptionBundlesForKey(bundleKey, context);
    //
    // Because the creation of the SubscriptionBundle is not atomic (with creation of Subscription/SubscriptionEvent), we verify if we were left
    // with an empty SubscriptionBaseBundle form a past failing operation (See #684). We only allow reuse if such SubscriptionBaseBundle is fully
    // empty (and don't allow use case where all Subscription are cancelled, which is the condition for that key to be re-used)
    // Such condition should have been checked upstream (to decide whether that key is valid or not)
    //
    final SubscriptionBaseBundle existingBundleForAccount = Iterables.tryFind(existingBundles, new Predicate<SubscriptionBaseBundle>() {

        @Override
        public boolean apply(final SubscriptionBaseBundle input) {
            return input.getAccountId().equals(accountId);
        }
    }).orNull();
    // If Bundle already exists, and there is 0 Subscription, we reuse
    if (existingBundleForAccount != null) {
        try {
            final Map<UUID, List<SubscriptionBase>> accountSubscriptions = dao.getSubscriptionsForAccount(context);
            final List<SubscriptionBase> subscriptions = accountSubscriptions.get(existingBundleForAccount.getId());
            if (subscriptions == null || subscriptions.size() == 0) {
                return existingBundleForAccount;
            }
        } catch (final CatalogApiException e) {
            throw new SubscriptionBaseApiException(e);
        }
    }
    final DateTime now = clock.getUTCNow();
    final DateTime originalCreatedDate = !existingBundles.isEmpty() ? existingBundles.get(0).getCreatedDate() : now;
    final DefaultSubscriptionBaseBundle bundle = new DefaultSubscriptionBaseBundle(bundleKey, accountId, now, originalCreatedDate, now, now);
    if (null != bundleKey && bundleKey.length() > 255) {
        throw new SubscriptionBaseApiException(ErrorCode.EXTERNAL_KEY_LIMIT_EXCEEDED);
    }
    return dao.createSubscriptionBundle(bundle, context);
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) List(java.util.List) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) UUID(java.util.UUID) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException) DateTime(org.joda.time.DateTime) Predicate(com.google.common.base.Predicate) PlanPhasePriceOverride(org.killbill.billing.catalog.api.PlanPhasePriceOverride)

Example 55 with SubscriptionBase

use of org.killbill.billing.subscription.api.SubscriptionBase in project killbill by killbill.

the class BlockingCalculator method createBundleSubscriptionMap.

protected Hashtable<UUID, List<SubscriptionBase>> createBundleSubscriptionMap(final SortedSet<BillingEvent> billingEvents) {
    final Hashtable<UUID, List<SubscriptionBase>> result = new Hashtable<UUID, List<SubscriptionBase>>();
    for (final BillingEvent event : billingEvents) {
        final UUID bundleId = event.getSubscription().getBundleId();
        List<SubscriptionBase> subs = result.get(bundleId);
        if (subs == null) {
            subs = new ArrayList<SubscriptionBase>();
            result.put(bundleId, subs);
        }
        if (!result.get(bundleId).contains(event.getSubscription())) {
            subs.add(event.getSubscription());
        }
    }
    return result;
}
Also used : SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) Hashtable(java.util.Hashtable) ArrayList(java.util.ArrayList) ImmutableList(com.google.common.collect.ImmutableList) List(java.util.List) BillingEvent(org.killbill.billing.junction.BillingEvent) UUID(java.util.UUID)

Aggregations

SubscriptionBase (org.killbill.billing.subscription.api.SubscriptionBase)120 Test (org.testng.annotations.Test)47 UUID (java.util.UUID)46 DateTime (org.joda.time.DateTime)40 Plan (org.killbill.billing.catalog.api.Plan)37 ArrayList (java.util.ArrayList)35 LocalDate (org.joda.time.LocalDate)33 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)32 BillingEvent (org.killbill.billing.junction.BillingEvent)30 PlanPhase (org.killbill.billing.catalog.api.PlanPhase)26 MockPlan (org.killbill.billing.catalog.MockPlan)24 MockPlanPhase (org.killbill.billing.catalog.MockPlanPhase)24 MockBillingEventSet (org.killbill.billing.invoice.MockBillingEventSet)23 SubscriptionBaseApiException (org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)23 BigDecimal (java.math.BigDecimal)22 LinkedList (java.util.LinkedList)21 Invoice (org.killbill.billing.invoice.api.Invoice)21 AccountInvoices (org.killbill.billing.invoice.optimizer.InvoiceOptimizerBase.AccountInvoices)21 BillingEventSet (org.killbill.billing.junction.BillingEventSet)21 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)20