Search in sources :

Example 6 with DefaultSubscriptionBaseBundle

use of org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle in project killbill by killbill.

the class TestSubscriptionDao method testGetActiveSubscriptionsForAccounts.

@Test(groups = "slow")
public void testGetActiveSubscriptionsForAccounts() throws SubscriptionBaseApiException, CatalogApiException {
    final String bundleExternalKey = "54341455sttfs1";
    final DateTime startDate = clock.getUTCNow();
    final DateTime cancelDate = startDate.plusDays(17);
    final DefaultSubscriptionBaseBundle bundleDef = new DefaultSubscriptionBaseBundle(bundleExternalKey, accountId, startDate, startDate, startDate, startDate);
    final SubscriptionBaseBundle bundle = dao.createSubscriptionBundle(bundleDef, catalog, true, internalCallContext);
    createSubscription(bundle, null, startDate, null);
    createSubscription(bundle, null, startDate, cancelDate);
    final InternalCallContext callContextWithAccountID = internalCallContextFactory.createInternalCallContext(accountId, callContext);
    final Map<UUID, List<DefaultSubscriptionBase>> res1 = dao.getSubscriptionsFromAccountId(null, callContextWithAccountID);
    assertEquals(res1.size(), 1);
    assertEquals(res1.get(bundle.getId()).size(), 2);
    final List<SubscriptionBaseEvent> events1 = ((DefaultSubscriptionDao) dao).getEventsForAccountId(null, callContextWithAccountID);
    assertEquals(events1.size(), 3);
    final Map<UUID, List<DefaultSubscriptionBase>> res2 = dao.getSubscriptionsFromAccountId(cancelDate.toLocalDate(), callContextWithAccountID);
    assertEquals(res2.size(), 1);
    assertEquals(res2.get(bundle.getId()).size(), 2);
    final List<SubscriptionBaseEvent> events2 = ((DefaultSubscriptionDao) dao).getEventsForAccountId(cancelDate.toLocalDate(), callContextWithAccountID);
    assertEquals(events2.size(), 3);
    final Map<UUID, List<DefaultSubscriptionBase>> res3 = dao.getSubscriptionsFromAccountId(cancelDate.plusDays(1).toLocalDate(), callContextWithAccountID);
    assertEquals(res3.size(), 1);
    assertEquals(res3.get(bundle.getId()).size(), 1);
    final List<SubscriptionBaseEvent> events3 = ((DefaultSubscriptionDao) dao).getEventsForAccountId(cancelDate.plusDays(1).toLocalDate(), callContextWithAccountID);
    assertEquals(events3.size(), 1);
}
Also used : DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) UUID(java.util.UUID) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) DateTime(org.joda.time.DateTime) Test(org.testng.annotations.Test)

Example 7 with DefaultSubscriptionBaseBundle

use of org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle in project killbill by killbill.

the class DefaultSubscriptionDao method transferBundleDataFromTransaction.

private void transferBundleDataFromTransaction(final BundleTransferData bundleTransferData, final EntitySqlDao transactional, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory, final InternalCallContext context) throws EntityPersistenceException {
    final SubscriptionSqlDao transSubDao = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class);
    final BundleSqlDao transBundleDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
    final DefaultSubscriptionBaseBundle bundleData = bundleTransferData.getData();
    final SubscriptionBundleModelDao existingBundleForAccount = transBundleDao.getBundlesFromAccountAndKey(bundleData.getAccountId().toString(), bundleData.getExternalKey(), context);
    if (existingBundleForAccount != null) {
        log.warn("Bundle already exists for accountId='{}', bundleExternalKey='{}'", bundleData.getAccountId(), bundleData.getExternalKey());
        return;
    }
    for (final SubscriptionTransferData curSubscription : bundleTransferData.getSubscriptions()) {
        final DefaultSubscriptionBase subData = curSubscription.getData();
        for (final SubscriptionBaseEvent curEvent : curSubscription.getInitialEvents()) {
            createAndRefresh(transactional, new SubscriptionEventModelDao(curEvent), context);
            recordFutureNotificationFromTransaction(entitySqlDaoWrapperFactory, curEvent.getEffectiveDate(), new SubscriptionNotificationKey(curEvent.getId()), context);
        }
        createAndRefresh(transSubDao, new SubscriptionModelDao(subData), context);
        // Notify the Bus of the latest requested change
        final SubscriptionBaseEvent finalEvent = curSubscription.getInitialEvents().get(curSubscription.getInitialEvents().size() - 1);
        notifyBusOfRequestedChange(entitySqlDaoWrapperFactory, subData, finalEvent, SubscriptionBaseTransitionType.TRANSFER, 0, context);
    }
    createAndRefresh(transBundleDao, new SubscriptionBundleModelDao(bundleData), context);
}
Also used : SubscriptionNotificationKey(org.killbill.billing.subscription.engine.core.SubscriptionNotificationKey) SubscriptionModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionModelDao) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) SubscriptionBundleModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) SubscriptionTransferData(org.killbill.billing.subscription.api.transfer.SubscriptionTransferData) SubscriptionBaseEvent(org.killbill.billing.subscription.events.SubscriptionBaseEvent) SubscriptionEventModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionEventModelDao)

Example 8 with DefaultSubscriptionBaseBundle

use of org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle 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 9 with DefaultSubscriptionBaseBundle

use of org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle in project killbill by killbill.

the class DefaultSubscriptionDao method createSubscriptionBundle.

@Override
public SubscriptionBaseBundle createSubscriptionBundle(final DefaultSubscriptionBaseBundle bundle, final SubscriptionCatalog catalog, final boolean renameCancelledBundleIfExist, final InternalCallContext context) throws SubscriptionBaseApiException {
    return transactionalSqlDao.execute(false, SubscriptionBaseApiException.class, new EntitySqlDaoTransactionWrapper<SubscriptionBaseBundle>() {

        // 
        // 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)
        // 
        private SubscriptionBaseBundle findExistingUnusedBundleForExternalKeyAndAccount(final List<SubscriptionBundleModelDao> existingBundles, final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) {
            final SubscriptionBundleModelDao existingBundleForAccount = Iterables.tryFind(existingBundles, new Predicate<SubscriptionBundleModelDao>() {

                @Override
                public boolean apply(final SubscriptionBundleModelDao input) {
                    return input.getAccountId().equals(bundle.getAccountId()) && // We look for strict equality ignoring tsf items with keys 'kbtsf-343453:'
                    bundle.getExternalKey().equals(input.getExternalKey());
                }
            }).orNull();
            // If Bundle already exists, and there is 0 Subscription associated with this bundle, we reuse
            if (existingBundleForAccount != null) {
                final List<SubscriptionModelDao> accountSubscriptions = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getByAccountRecordId(context);
                if (accountSubscriptions == null || !Iterables.any(accountSubscriptions, new Predicate<SubscriptionModelDao>() {

                    @Override
                    public boolean apply(final SubscriptionModelDao input) {
                        return input.getBundleId().equals(existingBundleForAccount.getId());
                    }
                })) {
                    return SubscriptionBundleModelDao.toSubscriptionBundle(existingBundleForAccount);
                }
            }
            return null;
        }

        @Override
        public SubscriptionBaseBundle inTransaction(final EntitySqlDaoWrapperFactory entitySqlDaoWrapperFactory) throws Exception {
            final List<SubscriptionBundleModelDao> existingBundles = bundle.getExternalKey() == null ? ImmutableList.<SubscriptionBundleModelDao>of() : entitySqlDaoWrapperFactory.become(BundleSqlDao.class).getBundlesForLikeKey(bundle.getExternalKey(), context);
            final SubscriptionBaseBundle unusedBundle = findExistingUnusedBundleForExternalKeyAndAccount(existingBundles, entitySqlDaoWrapperFactory);
            if (unusedBundle != null) {
                log.info("Found unused bundle for externalKey='{}': bundleId='{}'", bundle.getExternalKey(), unusedBundle.getId());
                return unusedBundle;
            }
            final BundleSqlDao bundleSqlDao = entitySqlDaoWrapperFactory.become(BundleSqlDao.class);
            for (SubscriptionBundleModelDao cur : existingBundles) {
                final List<SubscriptionModelDao> subscriptions = entitySqlDaoWrapperFactory.become(SubscriptionSqlDao.class).getSubscriptionsFromBundleId(cur.getId().toString(), context);
                final Iterable<SubscriptionModelDao> filtered = subscriptions != null ? Iterables.filter(subscriptions, new Predicate<SubscriptionModelDao>() {

                    @Override
                    public boolean apply(final SubscriptionModelDao input) {
                        return input.getCategory() != ProductCategory.ADD_ON;
                    }
                }) : ImmutableList.<SubscriptionModelDao>of();
                for (SubscriptionModelDao f : filtered) {
                    try {
                        final SubscriptionBase s = buildSubscription(SubscriptionModelDao.toSubscription(f, cur.getExternalKey()), catalog, context);
                        if (s.getState() != EntitlementState.CANCELLED) {
                            throw new SubscriptionBaseApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, bundle.getExternalKey());
                        } else if (renameCancelledBundleIfExist) {
                            log.info("Renaming bundles with externalKey='{}', prefix='cncl'", bundle.getExternalKey());
                            renameBundleExternalKey(bundleSqlDao, bundle.getExternalKey(), "cncl", context);
                        }
                    /* else {
                                Code will throw SQLIntegrityConstraintViolationException because of unique constraint on externalKey; might be worth having an ErrorCode just for that
                            } */
                    } catch (CatalogApiException e) {
                        throw new SubscriptionBaseApiException(e);
                    }
                }
            }
            final SubscriptionBundleModelDao model = new SubscriptionBundleModelDao(bundle);
            // Preserve Original created date
            if (!existingBundles.isEmpty()) {
                model.setOriginalCreatedDate(existingBundles.get(0).getCreatedDate());
            }
            final SubscriptionBundleModelDao result = createAndRefresh(bundleSqlDao, model, context);
            return SubscriptionBundleModelDao.toSubscriptionBundle(result);
        }
    });
}
Also used : SubscriptionModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionModelDao) SubscriptionBundleModelDao(org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) SubscriptionApiException(org.killbill.billing.entitlement.api.SubscriptionApiException) IOException(java.io.IOException) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException) EventBusException(org.killbill.bus.api.PersistentBus.EventBusException) EntityPersistenceException(org.killbill.billing.entity.EntityPersistenceException) Predicate(com.google.common.base.Predicate) SubscriptionBase(org.killbill.billing.subscription.api.SubscriptionBase) DefaultSubscriptionBase(org.killbill.billing.subscription.api.user.DefaultSubscriptionBase) CatalogApiException(org.killbill.billing.catalog.api.CatalogApiException) SubscriptionBaseBundle(org.killbill.billing.subscription.api.user.SubscriptionBaseBundle) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle) EntitySqlDaoWrapperFactory(org.killbill.billing.util.entity.dao.EntitySqlDaoWrapperFactory) ArrayList(java.util.ArrayList) List(java.util.List) ImmutableList(com.google.common.collect.ImmutableList) LinkedList(java.util.LinkedList) SubscriptionBaseApiException(org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)

Example 10 with DefaultSubscriptionBaseBundle

use of org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle in project killbill by killbill.

the class SubscriptionBundleModelDao method toSubscriptionBundle.

public static SubscriptionBaseBundle toSubscriptionBundle(final SubscriptionBundleModelDao src) {
    if (src == null) {
        return null;
    }
    // Fix externalKey to remove internal prefix used for tsf
    final Matcher m = BUNDLE_KEY_PATTERN.matcher(src.getExternalKey());
    final String externalKey = m.matches() ? m.group(1) : src.getExternalKey();
    return new DefaultSubscriptionBaseBundle(src.getId(), externalKey, src.getAccountId(), src.getOriginalCreatedDate(), src.getCreatedDate(), src.getUpdatedDate());
}
Also used : Matcher(java.util.regex.Matcher) DefaultSubscriptionBaseBundle(org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle)

Aggregations

DefaultSubscriptionBaseBundle (org.killbill.billing.subscription.api.user.DefaultSubscriptionBaseBundle)13 DateTime (org.joda.time.DateTime)9 SubscriptionBaseBundle (org.killbill.billing.subscription.api.user.SubscriptionBaseBundle)9 DefaultSubscriptionBase (org.killbill.billing.subscription.api.user.DefaultSubscriptionBase)6 SubscriptionBaseApiException (org.killbill.billing.subscription.api.user.SubscriptionBaseApiException)6 CatalogApiException (org.killbill.billing.catalog.api.CatalogApiException)5 SubscriptionBaseEvent (org.killbill.billing.subscription.events.SubscriptionBaseEvent)5 Test (org.testng.annotations.Test)4 ImmutableList (com.google.common.collect.ImmutableList)3 LinkedList (java.util.LinkedList)3 List (java.util.List)3 SubscriptionBuilder (org.killbill.billing.subscription.api.user.SubscriptionBuilder)3 SubscriptionBundleModelDao (org.killbill.billing.subscription.engine.dao.model.SubscriptionBundleModelDao)3 SubscriptionModelDao (org.killbill.billing.subscription.engine.dao.model.SubscriptionModelDao)3 ApiEventBuilder (org.killbill.billing.subscription.events.user.ApiEventBuilder)3 Predicate (com.google.common.base.Predicate)2 ArrayList (java.util.ArrayList)2 UUID (java.util.UUID)2 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)2 SubscriptionBase (org.killbill.billing.subscription.api.SubscriptionBase)2