public DefaultBlockingState(final BlockingState input, final DateTime effectiveDate) { this(input.getBlockedId(), input.getType(), input.getStateName(), input.getService(), input.isBlockChange(), input.isBlockEntitlement(), input.isBlockBilling(), effectiveDate); }
@Override public boolean apply(final Entitlement entitlement) { // Note: this would miss add-ons created in the future. We should expose a new API to do something similar to EventsStreamBuilder#findBaseSubscription return !ProductCategory.ADD_ON.equals(entitlement.getLastActiveProductCategory()); } });
@Override protected SubscriptionApiException generateAlreadyExistsException(final SubscriptionBundleModelDao entity, final InternalCallContext context) { return new SubscriptionApiException(ErrorCode.SUB_CREATE_ACTIVE_BUNDLE_KEY_EXISTS, entity.getExternalKey()); }
public void checkStateApplied(final BlockingState result, final OverdueState state) { Assert.assertEquals(result.getStateName(), state.getName()); Assert.assertEquals(result.isBlockChange(), state.isBlockChanges()); Assert.assertEquals(result.isBlockEntitlement(), state.isDisableEntitlementAndChangesBlocked()); Assert.assertEquals(result.isBlockBilling(), state.isDisableEntitlementAndChangesBlocked()); }
private void clearWithLock(final DateTime effectiveDate, final InternalCallContext context) throws OverdueException, OverdueApiException { final BlockingState blockingStateForService = api.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, context); final String previousOverdueStateName = blockingStateForService != null ? blockingStateForService.getStateName() : OverdueWrapper.CLEAR_STATE_NAME; final OverdueState previousOverdueState = overdueStateSet.findState(previousOverdueStateName); overdueStateApplicator.clear(effectiveDate, overdueable, previousOverdueState, overdueStateSet.getClearState(), context); }
@Test(groups = "fast") public void testChangeSubscriptionWithPolicy() throws Exception { final SubscriptionBase subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME); try { final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME); subscription.changePlanWithPolicy(new DefaultEntitlementSpecifier(planPhaseSpecifier), BillingActionPolicy.ILLEGAL, callContext); Assert.fail("Call changePlanWithPolicy should have failed"); } catch (final SubscriptionBaseError error) { assertTrue(true); assertEquals(subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext).getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.ANNUAL); } // Assume the call takes less than a second final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME); assertEquals(DefaultClock.truncateMs(subscription.changePlanWithPolicy(new DefaultEntitlementSpecifier(planPhaseSpecifier), BillingActionPolicy.IMMEDIATE, callContext)), DefaultClock.truncateMs(clock.getUTCNow())); assertEquals(subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext).getCurrentPlan().getRecurringBillingPeriod(), BillingPeriod.MONTHLY); }
@Override public BlockingState getBlockingStateForService(final UUID blockableId, final BlockingStateType blockingStateType, final String serviceName, final InternalTenantContext context) { if (blockingState != null && blockingState.getBlockedId().equals(blockableId)) { return blockingState; } else { return new DefaultBlockingState(null, blockingStateType, OverdueWrapper.CLEAR_STATE_NAME, serviceName, false, false, false, null); } }
@Override public int compareTo(final BlockingState arg0) { // effective_date column NOT NULL final int comparison = effectiveDate.compareTo(arg0.getEffectiveDate()); if (comparison == 0) { // Keep a stable ordering for ties final int comparison2 = createdDate.compareTo(arg0.getCreatedDate()); if (comparison2 == 0 && arg0 instanceof DefaultBlockingState) { final DefaultBlockingState other = (DefaultBlockingState) arg0; // New element is last if (totalOrdering == null) { return 1; } else if (other.getTotalOrdering() == null) { return -1; } else { return totalOrdering.compareTo(other.getTotalOrdering()); } } else { return comparison2; } } else { return comparison; } }
@Override public int hashCode() { int result = totalOrdering != null ? totalOrdering.hashCode() : 0; result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0); result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0); result = 31 * result + (eventId != null ? eventId.hashCode() : 0); result = 31 * result + (requestedTransitionTime != null ? requestedTransitionTime.hashCode() : 0); result = 31 * result + (effectiveTransitionTime != null ? effectiveTransitionTime.hashCode() : 0); result = 31 * result + (previousState != null ? previousState.hashCode() : 0); result = 31 * result + (previousPriceList != null ? previousPriceList.hashCode() : 0); result = 31 * result + (previousBillCycleDayLocal != null ? previousBillCycleDayLocal.hashCode() : 0); result = 31 * result + (previousPlan != null ? previousPlan.hashCode() : 0); result = 31 * result + (previousPhase != null ? previousPhase.hashCode() : 0); result = 31 * result + (nextState != null ? nextState.hashCode() : 0); result = 31 * result + (nextPriceList != null ? nextPriceList.hashCode() : 0); result = 31 * result + (nextBillCycleDayLocal != null ? nextBillCycleDayLocal.hashCode() : 0); result = 31 * result + (nextPlan != null ? nextPlan.hashCode() : 0); result = 31 * result + (nextPhase != null ? nextPhase.hashCode() : 0); result = 31 * result + (remainingEventsForUserOperation != null ? remainingEventsForUserOperation.hashCode() : 0); result = 31 * result + (transitionType != null ? transitionType.hashCode() : 0); result = 31 * result + (startDate != null ? startDate.hashCode() : 0); return result; } }
private void computeEntitlementsToCancel(final ImmutableAccountData account, final List<Entitlement> result, final CallContext context) throws EntitlementApiException { final List<Entitlement> allEntitlementsForAccountId = entitlementApi.getAllEntitlementsForAccountId(account.getId(), context); // Entitlement is smart enough and will cancel the associated add-ons. See also discussion in https://github.com/killbill/killbill/issues/94 final Collection<Entitlement> allEntitlementsButAddonsForAccountId = Collections2.<Entitlement>filter(allEntitlementsForAccountId, new Predicate<Entitlement>() { @Override public boolean apply(final Entitlement entitlement) { // Note: this would miss add-ons created in the future. We should expose a new API to do something similar to EventsStreamBuilder#findBaseSubscription return !ProductCategory.ADD_ON.equals(entitlement.getLastActiveProductCategory()); } }); result.addAll(allEntitlementsButAddonsForAccountId); }
@Override public DateTime dryRunChangePlan(final DefaultSubscriptionBase subscription, final EntitlementSpecifier spec, @Nullable final DateTime requestedDateWithMs, @Nullable final BillingActionPolicy requestedPolicy, final TenantContext context) throws SubscriptionBaseApiException { final DateTime now = clock.getUTCNow(); BillingActionPolicy policyMaybeNull = requestedPolicy; if (requestedDateWithMs == null && requestedPolicy == null) { final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, spec.getPlanPhaseSpecifier(), now, context); policyMaybeNull = planChangeResult.getPolicy(); } if (policyMaybeNull != null) { return subscription.getPlanChangeEffectiveDate(policyMaybeNull, null, -1, null); } else if (requestedDateWithMs != null) { return DefaultClock.truncateMs(requestedDateWithMs); } else { return now; } }
@Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (blockedId != null ? blockedId.hashCode() : 0); result = 31 * result + (stateName != null ? stateName.hashCode() : 0); result = 31 * result + (service != null ? service.hashCode() : 0); result = 31 * result + (blockChange ? 1 : 0); result = 31 * result + (blockEntitlement ? 1 : 0); result = 31 * result + (blockBilling ? 1 : 0); result = 31 * result + (effectiveDate != null ? effectiveDate.hashCode() : 0); result = 31 * result + (type != null ? type.hashCode() : 0); result = 31 * result + (totalOrdering != null ? totalOrdering.hashCode() : 0); return result; }
@Override public OverdueState getOverdueStateFor(final UUID accountId, final TenantContext tenantContext) throws OverdueApiException { final InternalTenantContext internalTenantContext = internalCallContextFactory.createInternalTenantContext(accountId, tenantContext); final BlockingState blockingStateForService = blockingInternalApi.getBlockingStateForService(accountId, BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, internalTenantContext); final String stateName = blockingStateForService != null ? blockingStateForService.getStateName() : OverdueWrapper.CLEAR_STATE_NAME; final OverdueConfig overdueConfig = overdueConfigCache.getOverdueConfig(internalTenantContext); final OverdueStateSet states = ((DefaultOverdueConfig) overdueConfig).getOverdueStatesAccount(); return states.findState(stateName); }
@Test(groups = "slow") public void testChangePlanOnCreate() throws SubscriptionBaseApiException { final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME); // CHANGE PLAN IMMEDIATELY: the CHANGE event will be transformed into a CREATE testListener.pushExpectedEvent(NextEvent.CREATE); final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME); subscription.changePlanWithDate(new DefaultEntitlementSpecifier(planPhaseSpecifier), subscription.getStartDate(), callContext); assertListenerStatus(); checkChangePlan(subscription, "Pistol", ProductCategory.BASE, BillingPeriod.MONTHLY, PhaseType.TRIAL); final SubscriptionBase refreshedSubscription = subscriptionInternalApi.getSubscriptionFromId(subscription.getId(), internalCallContext); assertEquals(refreshedSubscription.getAllTransitions().size(), 2); assertEquals(refreshedSubscription.getAllTransitions().get(0).getTransitionType(), SubscriptionBaseTransitionType.CREATE); assertEquals(refreshedSubscription.getAllTransitions().get(1).getTransitionType(), SubscriptionBaseTransitionType.PHASE); }
@Override public int hashCode() { int result = totalOrdering != null ? totalOrdering.hashCode() : 0; result = 31 * result + (subscriptionId != null ? subscriptionId.hashCode() : 0); result = 31 * result + (bundleId != null ? bundleId.hashCode() : 0); result = 31 * result + (bundleExternalKey != null ? bundleExternalKey.hashCode() : 0); result = 31 * result + (eventId != null ? eventId.hashCode() : 0); result = 31 * result + (eventType != null ? eventType.hashCode() : 0); result = 31 * result + (apiEventType != null ? apiEventType.hashCode() : 0); result = 31 * result + (effectiveTransitionTime != null ? effectiveTransitionTime.hashCode() : 0); result = 31 * result + (previousState != null ? previousState.hashCode() : 0); result = 31 * result + (previousPriceList != null ? previousPriceList.hashCode() : 0); result = 31 * result + (previousBillingCycleDayLocal != null ? previousBillingCycleDayLocal.hashCode() : 0); result = 31 * result + (previousPlan != null ? previousPlan.hashCode() : 0); result = 31 * result + (previousPhase != null ? previousPhase.hashCode() : 0); result = 31 * result + (nextState != null ? nextState.hashCode() : 0); result = 31 * result + (nextPriceList != null ? nextPriceList.hashCode() : 0); result = 31 * result + (nextBillingCycleDayLocal != null ? nextBillingCycleDayLocal.hashCode() : 0); result = 31 * result + (nextPlan != null ? nextPlan.hashCode() : 0); result = 31 * result + (nextPhase != null ? nextPhase.hashCode() : 0); result = 31 * result + (isFromDisk != null ? isFromDisk.hashCode() : 0); result = 31 * result + (remainingEventsForUserOperation != null ? remainingEventsForUserOperation.hashCode() : 0); result = 31 * result + (userToken != null ? userToken.hashCode() : 0); return result; } }
@Override public DateTime changePlan(final DefaultSubscriptionBase subscription, final EntitlementSpecifier spec, final CallContext context) throws SubscriptionBaseApiException { validateSubscriptionStateForChangePlan(subscription, null); final PlanChangeResult planChangeResult = getPlanChangeResult(subscription, spec.getPlanPhaseSpecifier(), context.getCreatedDate(), context); final DateTime effectiveDate = dryRunChangePlan(subscription, spec, null, planChangeResult.getPolicy(), context); validateEffectiveDate(subscription, effectiveDate); try { doChangePlan(subscription, spec, effectiveDate, context); } catch (final CatalogApiException e) { throw new SubscriptionBaseApiException(e); } return effectiveDate; }
private OverdueState refreshWithLock(final DateTime effectiveDate, final InternalCallContext context) throws OverdueException, OverdueApiException { final BillingState billingState = billingState(context); final BlockingState blockingStateForService = api.getBlockingStateForService(overdueable.getId(), BlockingStateType.ACCOUNT, OverdueService.OVERDUE_SERVICE_NAME, context); final String previousOverdueStateName = blockingStateForService != null ? blockingStateForService.getStateName() : OverdueWrapper.CLEAR_STATE_NAME; final OverdueState currentOverdueState = overdueStateSet.findState(previousOverdueStateName); final OverdueState nextOverdueState = overdueStateSet.calculateOverdueState(billingState, context.toLocalDate(context.getCreatedDate())); overdueStateApplicator.apply(effectiveDate, overdueStateSet, billingState, overdueable, currentOverdueState, nextOverdueState, context); return nextOverdueState; }
@Test(groups = "fast") public void testChangeSubscriptionNonActive() throws SubscriptionBaseApiException { final SubscriptionBase subscription = testUtil.createSubscription(bundle, "Shotgun", BillingPeriod.ANNUAL, PriceListSet.DEFAULT_PRICELIST_NAME); testListener.pushExpectedEvent(NextEvent.CANCEL); subscription.cancelWithDate(clock.getUTCNow(), callContext); assertListenerStatus(); try { final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier("Pistol", BillingPeriod.MONTHLY, PriceListSet.DEFAULT_PRICELIST_NAME); subscription.changePlanWithDate(new DefaultEntitlementSpecifier(planPhaseSpecifier), clock.getUTCNow(), callContext); Assert.fail("Exception expected, error code: " + ErrorCode.SUB_CHANGE_NON_ACTIVE); } catch (final SubscriptionBaseApiException e) { assertEquals(e.getCode(), ErrorCode.SUB_CHANGE_NON_ACTIVE.getCode()); } }
+ ((nextPriceList == null) ? 0 : nextPriceList.hashCode()); result = prime * result + ((nextState == null) ? 0 : nextState.hashCode()); result = prime * result + ((previousPhase == null) ? 0 : previousPhase.hashCode()); .hashCode()); result = prime * result + ((previousState == null) ? 0 : previousState.hashCode()); result = prime
private void tChangePlanBundleAlignIMM(final String fromProd, final BillingPeriod fromTerm, final String fromPlanSet, final String toProd, final BillingPeriod toTerm, final String toPlanSet) throws SubscriptionBaseApiException { final DefaultSubscriptionBase subscription = testUtil.createSubscription(bundle, fromProd, fromTerm, fromPlanSet); testListener.pushExpectedEvent(NextEvent.CHANGE); Interval it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(3)); clock.addDeltaFromReality(it.toDurationMillis()); // CHANGE PLAN IMM final PlanPhaseSpecifier planPhaseSpecifier = new PlanPhaseSpecifier(toProd, toTerm, toPlanSet); subscription.changePlan(new DefaultEntitlementSpecifier(planPhaseSpecifier), callContext); checkChangePlan(subscription, toProd, ProductCategory.BASE, toTerm, PhaseType.TRIAL); assertListenerStatus(); final PlanPhase currentPhase = subscription.getCurrentPhase(); final DateTime nextExpectedPhaseChange = TestSubscriptionHelper.addDuration(subscription.getStartDate(), currentPhase.getDuration()); testUtil.checkNextPhaseChange(subscription, 1, nextExpectedPhaseChange); // NEXT PHASE testListener.pushExpectedEvent(NextEvent.PHASE); it = new Interval(clock.getUTCNow(), clock.getUTCNow().plusDays(30)); clock.addDeltaFromReality(it.toDurationMillis()); final DateTime futureNow = clock.getUTCNow(); assertTrue(futureNow.isAfter(nextExpectedPhaseChange)); assertListenerStatus(); }